AlignSliceAdaptor.pm
Go to the documentation of this file.
00001 =head1 LICENSE 00002 00003 Copyright (c) 1999-2012 The European Bioinformatics Institute and 00004 Genome Research Limited. All rights reserved. 00005 00006 This software is distributed under a modified Apache license. 00007 For license details, please see 00008 00009 http://www.ensembl.org/info/about/code_licence.html 00010 00011 =head1 CONTACT 00012 00013 Please email comments or questions to the public Ensembl 00014 developers list at <dev@ensembl.org>. 00015 00016 Questions may also be sent to the Ensembl help desk at 00017 <helpdesk@ensembl.org>. 00018 00019 =head1 NAME 00020 00021 Bio::EnsEMBL::Compara::DBSQL::AlignSliceAdaptor - An AlignSlice can be used to map genes from one species onto another one. This adaptor is used to fetch all the data needed for an AlignSlice from the database. 00022 00023 =head1 INHERITANCE 00024 00025 This module inherits attributes and methods from Bio::EnsEMBL::DBSQL::BaseAdaptor 00026 00027 =head1 SYNOPSIS 00028 00029 use Bio::EnsEMBL::Registry; 00030 00031 ## Load adaptors using the Registry 00032 Bio::EnsEMBL::Registry->load_all(); 00033 00034 ## Fetch the query slice 00035 my $query_slice_adaptor = Bio::EnsEMBL::Registry->get_adaptor( 00036 "Homo sapiens", "core", "Slice"); 00037 my $query_slice = $query_slice_adaptor->fetch_by_region( 00038 "chromosome", "14", 50000001, 50010001); 00039 00040 ## Fetch the method_link_species_set 00041 my $mlss_adaptor = Bio::EnsEMBL::Registry->get_adaptor( 00042 "Compara26", "compara", "MethodLinkSpeciesSet"); 00043 my $method_link_species_set = $mlss_adaptor->fetch_by_method_link_type_registry_aliases( 00044 "BLASTZ_NET", ["Homo sapiens", "Rattus norvegicus"]); 00045 00046 ## Fetch the align_slice 00047 my $align_slice_adaptor = Bio::EnsEMBL::Registry->get_adaptor( 00048 "Compara26", 00049 "compara", 00050 "AlignSlice" 00051 ); 00052 my $align_slice = $align_slice_adaptor->fetch_by_Slice_MethodLinkSpeciesSet( 00053 $query_slice, 00054 $method_link_species_set, 00055 "expanded" 00056 ); 00057 00058 =head1 OBJECT ATTRIBUTES 00059 00060 =over 00061 00062 =item db (from SUPER class) 00063 00064 =back 00065 00066 =head1 APPENDIX 00067 00068 The rest of the documentation details each of the object methods. Internal methods are usually preceded with a _ 00069 00070 =cut 00071 00072 00073 # Let the code begin... 00074 00075 package Bio::EnsEMBL::Compara::DBSQL::AlignSliceAdaptor; 00076 00077 use strict; 00078 use Bio::EnsEMBL::DBSQL::BaseAdaptor; 00079 use Bio::EnsEMBL::Utils::Exception qw(throw warning info); 00080 use Bio::EnsEMBL::Compara::AlignSlice; 00081 00082 our @ISA = qw(Bio::EnsEMBL::DBSQL::BaseAdaptor); 00083 00084 =head2 new (CONSTRUCTOR) 00085 00086 Arg : 00087 Example : 00088 Description: Creates a new AlignSliceAdaptor object 00089 Returntype : Bio::EnsEMBL::Compara::DBSQL::AlignSliceAdaptor 00090 Exceptions : none 00091 Caller : Bio::EnsEMBL::Registry->get_adaptor 00092 00093 =cut 00094 00095 sub new { 00096 my $class = shift; 00097 00098 my $self = $class->SUPER::new(@_); 00099 00100 return $self; 00101 } 00102 00103 00104 =head2 fetch_by_Slice_MethodLinkSpeciesSet 00105 00106 Arg[1] : Bio::EnsEMBL::Slice $query_slice 00107 Arg[2] : Bio::EnsEMBL::Compara::MethodLinkSpeciesSet $method_link_species_set 00108 Arg[3] : [optional] boolean $expanded (def. FALSE) 00109 Arg[4] : [optional] boolean $solve_overlapping (def. FALSE) 00110 Arg[5] : [optional] Bio::EnsEMBL::Slice $target_slice 00111 Example : 00112 my $align_slice = $align_slice_adaptor->fetch_by_Slice_MethodLinkSpeciesSet( 00113 $query_slice, $method_link_species_set); 00114 Description: Fetches from the database all the data needed for the AlignSlice 00115 corresponding to the $query_slice and the given 00116 $method_link_species_set. Setting $expanded to anything different 00117 from 0 or "" will create an AlignSlice in "expanded" mode. This means 00118 that gaps are allowed in the reference species in order to allocate 00119 insertions from other species. 00120 By default overlapping alignments are ignored. You can choose to 00121 reconciliate the alignments by means of a fake alignment setting the 00122 solve_overlapping option to TRUE. 00123 In order to restrict the AlignSlice to alignments with a given 00124 genomic region, you can specify a target_slice. All alignments which 00125 do not match this slice will be ignored. 00126 Returntype : Bio::EnsEMBL::Compara::AlignSlice 00127 Exceptions : thrown if wrong arguments are given 00128 Caller : $object->methodname 00129 00130 =cut 00131 00132 sub fetch_by_Slice_MethodLinkSpeciesSet { 00133 my ($self, $reference_slice, $method_link_species_set, $expanded, $solve_overlapping, $target_slice) = @_; 00134 00135 throw("[$reference_slice] is not a Bio::EnsEMBL::Slice") 00136 unless ($reference_slice and ref($reference_slice) and 00137 $reference_slice->isa("Bio::EnsEMBL::Slice")); 00138 throw("[$method_link_species_set] is not a Bio::EnsEMBL::Compara::MethodLinkSpeciesSet") 00139 unless ($method_link_species_set and ref($method_link_species_set) and 00140 $method_link_species_set->isa("Bio::EnsEMBL::Compara::MethodLinkSpeciesSet")); 00141 00142 # Use cache whenever possible 00143 my $key = $reference_slice->name.":".$method_link_species_set->dbID.":".($expanded?"exp":"cond"). 00144 ":".($solve_overlapping?"fake-overlap":"non-overlap"); 00145 if (defined($target_slice)) { 00146 throw("[$target_slice] is not a Bio::EnsEMBL::Slice") 00147 unless ($target_slice and ref($target_slice) and 00148 $target_slice->isa("Bio::EnsEMBL::Slice")); 00149 $key .= ":".$target_slice->name(); 00150 } 00151 return $self->{'_cache'}->{$key} if (defined($self->{'_cache'}->{$key})); 00152 00153 my $genomic_align_block_adaptor = $self->db->get_GenomicAlignBlockAdaptor; 00154 my $genomic_align_blocks = $genomic_align_block_adaptor->fetch_all_by_MethodLinkSpeciesSet_Slice( 00155 $method_link_species_set, 00156 $reference_slice 00157 ); 00158 00159 ## Remove all alignments not matching the target slice if any 00160 if (defined($target_slice)) { 00161 ## Get the DnaFrag for the target Slice 00162 my $target_dnafrag = $self->db->get_DnaFragAdaptor->fetch_by_Slice($target_slice); 00163 if (!$target_dnafrag) { 00164 throw("Cannot get a DnaFrag for the target Slice"); 00165 } 00166 00167 ## Loop through all the alignment blocks and test whether they match the target slice or not 00168 for (my $i = 0; $i < @$genomic_align_blocks; $i++) { 00169 my $this_genomic_align_block = $genomic_align_blocks->[$i]; 00170 my $hits_the_target_slice = 0; 00171 foreach my $this_genomic_align (@{$this_genomic_align_block->get_all_non_reference_genomic_aligns}) { 00172 if ($this_genomic_align->dnafrag->dbID == $target_dnafrag->dbID and 00173 $this_genomic_align->dnafrag_start <= $target_slice->end and 00174 $this_genomic_align->dnafrag_end >= $target_slice->start) { 00175 $hits_the_target_slice = 1; 00176 last; 00177 } 00178 } 00179 if (!$hits_the_target_slice) { 00180 splice(@$genomic_align_blocks, $i, 1); 00181 $i--; 00182 } 00183 } 00184 } 00185 00186 my $genomic_align_trees = (); 00187 my $species_order; 00188 if ($method_link_species_set->method_link_class =~ /GenomicAlignTree/ and @$genomic_align_blocks) { 00189 my $genomic_align_tree_adaptor = $self->db->get_GenomicAlignTreeAdaptor; 00190 foreach my $this_genomic_align_block (@$genomic_align_blocks) { 00191 # print $this_genomic_align_block->reference_genomic_align, "\n"; 00192 my $this_genomic_align_tree = $genomic_align_tree_adaptor-> 00193 fetch_by_GenomicAlignBlock($this_genomic_align_block); 00194 push(@$genomic_align_trees, $this_genomic_align_tree); 00195 # $this_genomic_align_tree->print(); 00196 # foreach my $this_ga (@{$this_genomic_align_tree->get_all_sorted_genomic_align_nodes}) { 00197 # print $this_ga->genomic_align->genome_db->name(), "\n"; 00198 # } 00199 00200 } 00201 my $last_node_id = undef; 00202 my $tree_order; 00203 foreach my $this_genomic_align_tree (@$genomic_align_trees) { 00204 if ($last_node_id) { 00205 $tree_order->{$this_genomic_align_tree->node_id}->{prev} = $last_node_id; 00206 $tree_order->{$last_node_id}->{next} = $this_genomic_align_tree; 00207 } 00208 $last_node_id = $this_genomic_align_tree->node_id; 00209 } 00210 00211 ## First tree. Build the species order using the first tree only 00212 foreach my $this_genomic_align_node (@{$genomic_align_trees->[0]->get_all_sorted_genomic_align_nodes}) { 00213 next if (!@{$this_genomic_align_node->get_all_genomic_aligns_for_node}); 00214 my $this_genomic_align = $this_genomic_align_node->get_all_genomic_aligns_for_node->[0]; 00215 my $genome_db = $this_genomic_align->genome_db; 00216 my $this_node_id = $this_genomic_align_node->node_id; 00217 my $right_node_id = _get_right_node_id($this_genomic_align_node); 00218 my $genomic_align_ids = []; 00219 foreach my $each_genomic_align (@{$this_genomic_align_node->get_all_genomic_aligns_for_node}) { 00220 push (@$genomic_align_ids, $each_genomic_align->dbID); 00221 } 00222 push(@$species_order, 00223 { 00224 genome_db => $genome_db, 00225 right_node_id => $right_node_id, 00226 genomic_align_ids => $genomic_align_ids, 00227 # # last_node => $this_genomic_align_node, 00228 }); 00229 } 00230 $| = 1; 00231 ## Combine the first tree with the second, the resulting order with the third and so on 00232 foreach my $this_genomic_align_tree (@$genomic_align_trees) { 00233 my $next_genomic_align_tree = $tree_order->{$this_genomic_align_tree->node_id}->{next}; 00234 next if (!$next_genomic_align_tree); 00235 # # # print STDERR "\nBEFORE:\n - ", join("\n - ", map { 00236 # # # $_->{genome_db}->name." (".($_->{right_node_id} or "***").") [". 00237 # # # join(" : ", @{$_->{genomic_align_ids}})."]" 00238 # # # } @$species_order), "\n"; 00239 _combine_genomic_align_trees($species_order, $this_genomic_align_tree, $next_genomic_align_tree); 00240 # $next_genomic_align_tree->print(); 00241 # # # print STDERR "\nAFTER:\n - ", join("\n - ", map { 00242 # # # $_->{genome_db}->name." (".($_->{right_node_id} or "***").") [". 00243 # # # join(" : ", @{$_->{genomic_align_ids}})."]" 00244 # # # } @$species_order), "\n"; 00245 # # # <STDIN>; 00246 00247 } 00248 } 00249 my $align_slice = new Bio::EnsEMBL::Compara::AlignSlice( 00250 -adaptor => $self, 00251 -reference_Slice => $reference_slice, 00252 -Genomic_Align_Blocks => $genomic_align_blocks, 00253 -Genomic_Align_Trees => $genomic_align_trees, 00254 -species_order => $species_order, 00255 -method_link_species_set => $method_link_species_set, 00256 -expanded => $expanded, 00257 -solve_overlapping => $solve_overlapping, 00258 ); 00259 $self->{'_cache'}->{$key} = $align_slice; 00260 00261 return $align_slice; 00262 } 00263 00264 00265 =head2 fetch_by_GenomicAlignBlock 00266 00267 Arg[1] : Bio::EnsEMBL::Compara::GenomicAlignBlock $genomic_align_block 00268 Arg[2] : [optional] boolean $expanded (def. FALSE) 00269 Arg[3] : [optional] boolean $solve_overlapping (def. FALSE) 00270 Example : 00271 my $align_slice = $align_slice_adaptor->fetch_by_GenomicAlignBlock( 00272 $genomic_align_block); 00273 Description: Uses this genomic_aling_block to create an AlignSlice. 00274 Setting $expanded to anything different 00275 from 0 or "" will create an AlignSlice in "expanded" mode. This means 00276 that gaps are allowed in the reference species in order to allocate 00277 insertions from other species. 00278 By default overlapping alignments are ignored. You can choose to 00279 reconciliate the alignments by means of a fake alignment setting the 00280 solve_overlapping option to TRUE. 00281 Returntype : Bio::EnsEMBL::Compara::AlignSlice 00282 Exceptions : thrown if arg[1] is not a Bio::EnsEMBL::Compara::GenomicAlignBlock 00283 Exceptions : thrown if $genomic_align_block has no method_link_species_set 00284 Caller : $object->methodname 00285 00286 =cut 00287 00288 sub fetch_by_GenomicAlignBlock { 00289 my ($self, $genomic_align_block, $expanded, $solve_overlapping) = @_; 00290 00291 throw("[$genomic_align_block] is not a Bio::EnsEMBL::Compara::GenomicAlignBlock") 00292 unless (UNIVERSAL::isa($genomic_align_block, "Bio::EnsEMBL::Compara::GenomicAlignBlock")); 00293 my $method_link_species_set = $genomic_align_block->method_link_species_set(); 00294 throw("GenomicAlignBlock [$genomic_align_block] has no MethodLinkSpeciesSet") 00295 unless ($method_link_species_set); 00296 my $reference_genomic_align = $genomic_align_block->reference_genomic_align; 00297 if (!$reference_genomic_align) { 00298 $genomic_align_block->reference_genomic_align($genomic_align_block->get_all_GenomicAligns->[0]); 00299 $reference_genomic_align = $genomic_align_block->reference_genomic_align; 00300 } 00301 my $reference_slice = $reference_genomic_align->get_Slice(); 00302 00303 # Use cache whenever possible 00304 my $key; 00305 if ($genomic_align_block->dbID) { 00306 $key = "gab_".$genomic_align_block->dbID.":".($expanded?"exp":"cond"). 00307 ":".($solve_overlapping?"fake-overlap":"non-overlap"); 00308 } else { 00309 $key = "gab_".$genomic_align_block.":".($expanded?"exp":"cond"). 00310 ":".($solve_overlapping?"fake-overlap":"non-overlap"); 00311 } 00312 return $self->{'_cache'}->{$key} if (defined($self->{'_cache'}->{$key})); 00313 00314 my $align_slice = new Bio::EnsEMBL::Compara::AlignSlice( 00315 -adaptor => $self, 00316 -reference_Slice => $reference_slice, 00317 -Genomic_Align_Blocks => [$genomic_align_block], 00318 -method_link_species_set => $method_link_species_set, 00319 -expanded => $expanded, 00320 -solve_overlapping => $solve_overlapping, 00321 -preserve_blocks => 1, 00322 ); 00323 $self->{'_cache'}->{$key} = $align_slice; 00324 00325 return $align_slice; 00326 } 00327 00328 00329 =head2 flush_cache 00330 00331 Arg[1] : none 00332 Example : $align_slice_adaptor->flush_cache() 00333 Description: Destroy the cache 00334 Returntype : none 00335 Exceptions : none 00336 Caller : $object->methodname 00337 00338 =cut 00339 00340 sub flush_cache { 00341 my ($self) = @_; 00342 foreach my $align_slice (values (%{$self->{'_cache'}})) { 00343 $align_slice->DESTROY; 00344 } 00345 undef $self->{'_cache'}; 00346 } 00347 00348 00349 =head2 _combine_genomic_align_trees 00350 00351 Arg[1] : listref $species_order 00352 Arg[2] : Bio::EnsEMBL::Compara::GenomicAlignTree $this_tree 00353 Arg[3] : Bio::EnsEMBL::Compara::GenomicAlignTree $next_tree 00354 Example : 00355 Description: This method tries to accommodate the nodes in $next_tree 00356 into $species_order. It uses several approaches. If there 00357 is information available about left and right node IDs, it 00358 will use it to link the nodes. Alternatively, it will rely 00359 on the species names to do its best. When a new species name 00360 appears in the $next_tree, it will try to insert it in the right 00361 position. 00362 Returntype : none 00363 Exceptions : none 00364 Caller : $object->methodname 00365 00366 =cut 00367 00368 sub _combine_genomic_align_trees { 00369 my ($species_order, $this_tree, $next_tree) = @_; 00370 00371 # $this_tree is already taken into account in the species_order. $next_tree is the new info to combine 00372 my $species_counter = 0; 00373 my $existing_node_ids; # Lists all node_ids in the next tree 00374 my $existing_right_node_ids; 00375 my $next_species_names; # Lists all species names in the next tree 00376 my $existing_species_names; # Lists all species names in the $species_order tracks 00377 00378 ## Initialise values 00379 foreach my $this_genomic_align_node (@{$next_tree->get_all_sorted_genomic_align_nodes}) { 00380 my $this_node_id = $this_genomic_align_node->node_id; 00381 $existing_node_ids->{$this_node_id} = 1; 00382 push(@$next_species_names, $this_genomic_align_node->genomic_align_group->genome_db->name) 00383 if ($this_genomic_align_node->genomic_align_group and 00384 $this_genomic_align_node->genomic_align_group->genome_db->name ne "ancestral_sequences"); 00385 } 00386 foreach my $species_def (@$species_order) { 00387 my $right_node_id = $species_def->{right_node_id}; 00388 $existing_right_node_ids->{$right_node_id} = 1 if ($right_node_id); 00389 push(@$existing_species_names, $species_def->{genome_db}->name); 00390 } 00391 00392 ## MAIN LOOP. For each of the nodes in $next_tree, try to find the best position in $species_order. 00393 ## First, rely on the right_node_id, then on the species_name. If $next_tree has a new species_name, 00394 ## include it. If no good position has been found, append the node to the end of the $species_order. 00395 foreach my $this_genomic_align_node (@{$next_tree->get_all_sorted_genomic_align_nodes}) { 00396 next if (!@{$this_genomic_align_node->get_all_genomic_aligns_for_node}); 00397 my $this_genomic_align = $this_genomic_align_node->get_all_genomic_aligns_for_node->[0]; 00398 my $this_genome_db = $this_genomic_align->genome_db; 00399 my $this_node_id = $this_genomic_align_node->node_id; 00400 my $this_right_node_id = _get_right_node_id($this_genomic_align_node); 00401 my $these_genomic_align_ids = []; 00402 foreach my $each_genomic_align (@{$this_genomic_align_node->get_all_genomic_aligns_for_node}) { 00403 push (@$these_genomic_align_ids, $each_genomic_align->dbID); 00404 } 00405 ## DEBUG info 00406 # print "Inserting ", $this_genome_db->name, " into the species_order\n"; 00407 00408 my $match = 0; 00409 ## SECONDARY LOOP. Note that the $species_counter is not reset at the end of the loop. 00410 ## This ensures that we do not add two nodes to the same species_order track and that we 00411 ## preserve the order in all existing and in the new tree. 00412 while (!$match and $species_counter < @$species_order) { 00413 my $species_genome_db = $species_order->[$species_counter]->{genome_db}; 00414 my $species_right_node_id = $species_order->[$species_counter]->{right_node_id}; 00415 $match = 1; 00416 00417 ## 1. Use info from species_right_node_id if available 00418 if (defined($species_right_node_id) and $species_right_node_id == $this_node_id) { 00419 $species_order->[$species_counter]->{right_node_id} = $this_right_node_id; 00420 # # $species_order->[$species_counter]->{last_node} = $this_genomic_align_node; 00421 push (@{$species_order->[$species_counter]->{genomic_align_ids}}, @$these_genomic_align_ids); 00422 ## DEBUG info 00423 # print "NODE LINK!\n"; 00424 # for (my $i = 0; $i<@$species_order; $i++) { 00425 # if ($i == $species_counter) { 00426 # print $species_order->[$i]->{genome_db}->name, "***\n"; 00427 # } else { 00428 # print $species_order->[$i]->{genome_db}->name, "\n"; 00429 # } 00430 # } 00431 00432 ## 2. Force insertions in a math to the next right_node is expected 00433 } elsif (defined($species_right_node_id) and exists($existing_node_ids->{$species_right_node_id})) { 00434 splice(@$species_order, $species_counter, 0, { 00435 genome_db => $this_genome_db, 00436 right_node_id => $this_right_node_id, 00437 genomic_align_ids => [@$these_genomic_align_ids], 00438 }); 00439 ## DEBUG info 00440 # print "FORCE INSERT!\n"; 00441 # for (my $i = 0; $i<@$species_order; $i++) { 00442 # if ($i == $species_counter) { 00443 # print $species_order->[$i]->{genome_db}->name, "***\n"; 00444 # } else { 00445 # print $species_order->[$i]->{genome_db}->name, "\n"; 00446 # } 00447 # } 00448 00449 ## 3. If there is no info about right node or this points to a node not found in next tree, 00450 ## rely on the species name 00451 } elsif ($this_genome_db->name eq $species_genome_db->name 00452 and (!defined($species_right_node_id) or 00453 !defined($existing_node_ids->{$species_right_node_id})) 00454 ) { 00455 $species_order->[$species_counter]->{right_node_id} = $this_right_node_id; 00456 push (@{$species_order->[$species_counter]->{genomic_align_ids}}, @$these_genomic_align_ids); 00457 ## DEBUG info 00458 # print "MATCH!\n"; 00459 # for (my $i = 0; $i<@$species_order; $i++) { 00460 # if ($i == $species_counter) { 00461 # print $species_order->[$i]->{genome_db}->name, "***\n"; 00462 # } else { 00463 # print $species_order->[$i]->{genome_db}->name, "\n"; 00464 # } 00465 # } 00466 00467 ## 4. Insert this species if not found in the remaining set of existing species (in species_order) 00468 } elsif (!defined($existing_right_node_ids->{$this_node_id}) 00469 and !grep {$_ eq $this_genome_db->name} @$existing_species_names) { 00470 splice(@$species_order, $species_counter, 0, { 00471 genome_db => $this_genome_db, 00472 right_node_id => $this_right_node_id, 00473 genomic_align_ids => [@$these_genomic_align_ids], 00474 }); 00475 ## DEBUG info 00476 # print "INSERT!\n"; 00477 # for (my $i = 0; $i<@$species_order; $i++) { 00478 # if ($i == $species_counter) { 00479 # print $species_order->[$i]->{genome_db}->name, "***\n"; 00480 # } else { 00481 # print $species_order->[$i]->{genome_db}->name, "\n"; 00482 # } 00483 # } 00484 00485 ## Unset $match, try with the next $species_order track. 00486 } else { 00487 $match = 0; 00488 } 00489 $species_counter++; 00490 shift(@$existing_species_names); 00491 } 00492 00493 ## 5. We have not found any good position for this node: add a new track to the $species_order 00494 if (!$match) { 00495 push(@$species_order, { 00496 genome_db => $this_genome_db, 00497 right_node_id => $this_right_node_id, 00498 genomic_align_ids => [@$these_genomic_align_ids], 00499 }); 00500 $species_counter++; 00501 ## DEBUG info 00502 # print "APPEND!\n"; 00503 # for (my $i = 0; $i<@$species_order; $i++) { 00504 # if ($i == $species_counter) { 00505 # print $species_order->[$i]->{genome_db}->name, "***\n"; 00506 # } else { 00507 # print $species_order->[$i]->{genome_db}->name, "\n"; 00508 # } 00509 # } 00510 } 00511 ## DEBUG info 00512 # print "[ENTER]"; 00513 # <STDIN>; 00514 shift(@$next_species_names); 00515 } 00516 00517 return; 00518 } 00519 00520 sub _get_right_node_id { 00521 my ($this_genomic_align_node) = @_; 00522 00523 my $use_right = 1; 00524 $use_right = 1 - $use_right if (!$this_genomic_align_node->root->get_original_strand); 00525 00526 my $neighbour_node; 00527 if ($use_right) { 00528 $neighbour_node = $this_genomic_align_node->right_node; 00529 } else { 00530 $neighbour_node = $this_genomic_align_node->left_node; 00531 } 00532 if ($neighbour_node) { 00533 return $neighbour_node->node_id; 00534 } 00535 00536 return undef; 00537 } 00538 00539 00540 1;