Mercurial > repos > mahtabm > ensemb_rep_gvl
diff variant_effect_predictor/Bio/Structure/Entry.pm @ 0:2bc9b66ada89 draft default tip
Uploaded
author | mahtabm |
---|---|
date | Thu, 11 Apr 2013 06:29:17 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/variant_effect_predictor/Bio/Structure/Entry.pm Thu Apr 11 06:29:17 2013 -0400 @@ -0,0 +1,992 @@ +# $Id: Entry.pm,v 1.17 2002/10/22 07:38:44 lapp Exp $ +# +# bioperl module for Bio::Structure::Entry +# +# Cared for by Kris Boulez <kris.boulez@algonomics.com> +# +# Copyright Kris Boulez +# +# You may distribute this module under the same terms as perl itself + +# POD documentation - main docs before the code + +=head1 NAME + +Bio::Structure::Entry - Bioperl structure Object, describes the whole entry + +=head1 SYNOPSIS + + #add synopsis here + +=head1 DESCRIPTION + +This object stores a whole Bio::Structure entry. It can consist of one or +more models (Bio::Structure::Model), which in turn consist of one or more +chains (Bio::Structure::Chain). A chain is composed of residues +(Bio::Structure::Residue) and a residue consists of atoms (Bio::Structure::Atom) +If no specific model or chain is chosen, the first one is choosen. + +=head1 FEEDBACK + +=head2 Mailing Lists + +User feedback is an integral part of the evolution of this and other +Bioperl modules. Send your comments and suggestions preferably to one +of the Bioperl mailing lists. Your participation is much appreciated. + + bioperl-l@bioperl.org - General discussion + http://bio.perl.org/MailList.html - About the mailing lists + +=head2 Reporting Bugs + +Report bugs to the Bioperl bug tracking system to help us keep track +the bugs and their resolution. Bug reports can be submitted via email +or the web: + + bioperl-bugs@bio.perl.org + http://bugzilla.bioperl.org/ + +=head1 AUTHOR - Kris Boulez + +Email kris.boulez@algonomics.com + +=head1 APPENDIX + +The rest of the documentation details each of the object methods. Internal methods are usually preceded with a _ + +=cut + + +# Let the code begin... + +package Bio::Structure::Entry; +use vars qw(@ISA); +use strict; + +use Bio::Root::Root; +use Bio::Structure::StructureI; +use Bio::Structure::Model; +use Bio::Structure::Chain; +use Bio::Annotation::Collection; +use Tie::RefHash; + +@ISA = qw(Bio::Root::Root Bio::Structure::StructureI); + + +=head2 new() + + Title : new() + Usage : $struc = Bio::Structure::Entry->new( + -id => 'structure_id', + ); + + Function: Returns a new Bio::Structure::Entry object from basic + constructors. Probably most called from Bio::Structure::IO. + Returns : a new Bio::Structure::Model object + +=cut + +sub new { + my ($class, @args) = @_; + my $self = $class->SUPER::new(@args); + + my($id, $model, $chain, $residue ) = + $self->_rearrange([qw( + ID + MODEL + CHAIN + RESIDUE + )], + @args); + + # where to store parent->child relations (1 -> 1..n) + # value to this hash will be an array ref + # by using Tie::RefHash we can store references in this hash + $self->{'p_c'} = (); + tie %{ $self->{'p_c'} } , "Tie::RefHash"; + + # where to store child->parent relations (1 -> 1) + $self->{'c_p'} = (); + tie %{ $self->{'c_p'} } , "Tie::RefHash"; + + $id && $self->id($id); + + $self->{'model'} = []; + $model && $self->model($model); + + + if($chain) { + if ( ! defined($self->model) ) { # no model yet, create default one + $self->_create_default_model; + } + for my $m ($self->model) { # add this chain on all models + $m->chain($chain); + } + } + + $residue && $self->residue($residue); + + # taken from Bio::Seq (or should we just inherit Bio::Seq and override some methods) + my $ann = Bio::Annotation::Collection->new; + $self->annotation($ann); + + return $self; +} + + +=head2 model() + + Title : model + Function: Connects a (or a list of) Model objects to a Bio::Structure::Entry. + To add a Model (and keep the existing ones) use add_model() + It returns a list of Model objects. + Returns : list of Bio::Structure::Model objects + Args : One Model or a reference to an array of Model objects + +=cut + +sub model { + my ($self, $model) = @_; + + if( defined $model) { + if( (ref($model) eq "ARRAY") || + ($model->isa('Bio::Structure::Model')) ) { + # remove existing ones, tell they've become orphan + my @obj = $self->model; + if (@obj) { + for my $m (@obj) { + $self->_remove_from_graph($m); + $self->{'model'} = []; + } + } + # add the new ones + $self->add_model($self,$model); + } + else { + $self->throw("Supplied a $model to model, we want a Bio::Structure::Model or a list of these\n"); + } + } + # give back list of models via general get method + $self->get_models($self); +} + + + +=head2 add_model() + + Title : add_model + Usage : $structure->add_model($model); + Function: Adds a (or a list of) Model objects to a Bio::Structure::Entry. + Returns : + Args : One Model or a reference to an array of Model objects + +=cut + +sub add_model { + my($self,$entry,$model) = @_; + + # if only one argument and it's a model, change evrything one place + # this is for people calling $entry->add_model($model); + if ( !defined $model && ref($entry) =~ /^Bio::Structure::Model/) { + $model = $entry; + $entry = $self; + } + # $self and $entry are the same here, but it's used for uniformicity + if ( !defined($entry) || ref($entry) !~ /^Bio::Structure::Entry/) { + $self->throw("first argument to add_model needs to be a Bio::Structure::Entry object\n"); + } + if (defined $model) { + if (ref($model) eq "ARRAY") { + # if the user passed in a reference to an array + for my $m ( @{$model} ) { + if( ! $m->isa('Bio::Structure::Model') ) { + $self->throw("$m is not a Model\n"); + } + if ( $self->_parent($m) ) { + $self->throw("$m already assigned to a parent\n"); + } + push @{$self->{'model'}}, $m; + # create a stringified version of our ref + # not used untill we get symbolic ref working + #my $str_ref = "$self"; + #$m->_grandparent($str_ref); + } + } + elsif ( $model->isa('Bio::Structure::Model') ) { + if ( $self->_parent($model) ) { # already assigned to a parent + $self->throw("$model already assigned\n"); + } + push @{$self->{'model'}}, $model; + # create a stringified version of our ref + #my $str_ref = "$self"; + #$model->_grandparent($str_ref); + } + else { + $self->throw("Supplied a $model to add_model, we want a Model or list of Models\n"); + } + } + + my $array_ref = $self->{'model'}; + return $array_ref ? @{$array_ref} : (); +} + + +=head2 get_models() + + Title : get_models + Usage : $structure->get_models($structure); + Function: general get method for models attached to an Entry + Returns : a list of models attached to this entry + Args : an Entry + +=cut + +sub get_models { + my ($self, $entry) = @_; + + # self and entry can be the same + if ( !defined $entry) { + $entry = $self; + } + # pass through to add_model + $self->add_model($entry); +} + + + +=head2 id() + + Title : id + Usage : $entry->id("identity"); + Function: Gets/sets the ID + Returns : + Args : + +=cut + +sub id { + my ($self, $value) = @_; + if (defined $value) { + $self->{'id'} = $value; + } + return $self->{'id'}; +} + + +=head2 chain() + + Title : chain + Usage : @chains = $structure->chain($chain); + Function: Connects a (or a list of) Chain objects to a Bio::Structure::Entry. + Returns : list of Bio::Structure::Residue objects + Args : One Residue or a reference to an array of Residue objects + +=cut + +sub chain { + my ($self, $chain) = @_; + + if ( ! $self->model ) { + $self->_create_default_model; + } + my @models = $self->model; + my $first_model = $models[0]; + + if ( defined $chain) { + + if( (ref($chain) eq "ARRAY") || + ($chain->isa('Bio::Structure::Chain')) ) { + # remove existing ones, tell they've become orphan + my @obj = $self->get_chains($first_model); + if (@obj) { + for my $c (@obj) { + $self->_remove_from_graph($c); + } + } + # add the new ones + $self->add_chain($first_model,$chain); + } + else { + $self->throw("Supplied a $chain to chain, we want a Bio::Structure::Chain or a list of these\n"); + } + } + $self->get_chains($first_model); +} + + +=head2 add_chain() + + Title : add_chain + Usage : @chains = $structure->add_chain($add_chain); + Function: Adds a (or a list of) Chain objects to a Bio::Structure::Entry. + Returns : + Args : + +=cut + +sub add_chain { + my($self, $model, $chain) = @_; + + if (ref($model) !~ /^Bio::Structure::Model/) { + $self->throw("add_chain: first argument needs to be a Model object ($model)\n"); + } + if (defined $chain) { + if (ref($chain) eq "ARRAY") { + # if the user passed in a reference to an array + for my $c ( @{$chain} ) { + if( ! $c->isa('Bio::Structure::Chain') ) { + $self->throw("$c is not a Chain\n"); + } + if ( $self->_parent($c) ) { + $self->throw("$c already assigned to a parent\n"); + } + $self->_parent($c, $model); + $self->_child($model, $c); + # stringify $self ref + #my $str_ref = "$self"; + #$c->_grandparent($str_ref); + } + } + elsif ( $chain->isa('Bio::Structure::Chain') ) { + if ( $self->_parent($chain) ) { # already assigned to parent + $self->throw("$chain already assigned to a parent\n"); + } + $self->_parent($chain,$model); + $self->_child($model, $chain); + # stringify $self ref + #my $str_ref = "$self"; + #$chain->_grandparent($str_ref); + } + else { + $self->throw("Supplied a $chain to add_chain, we want a Chain or list of Chains\n"); + } + } + my $array_ref = $self->_child($model); + return $array_ref ? @{$array_ref} : (); +} + + +=head2 get_chains() + + Title : get_chains + Usage : $entry->get_chains($model); + Function: general get method for chains attached to a Model + Returns : a list of chains attached to this model + Args : a Model + +=cut + +sub get_chains { + my ($self, $model) = @_; + + if (! defined $model) { + $model = ($self->get_models)[0]; + } + # pass through to add_chain + $self->add_chain($model); +} + + +=head2 residue() + + Title : residue + Usage : @residues = $structure->residue($residue); + Function: Connects a (or a list of) Residue objects to a Bio::Structure::Entry. + Returns : list of Bio::Structure::Residue objects + Args : One Residue or a reference to an array of Residue objects + +=cut + +sub residue { + my ($self, $residue) = @_; + + if ( ! $self->model ) { + my $m = $self->_create_default_model; + $self->add_model($self,$m); + } + my @models = $self->model; + my $first_model = $models[0]; + + if ( ! $self->get_chains($first_model) ) { + my $c = $self->_create_default_chain; + $self->add_chain($first_model, $c); + } + my @chains = $self->get_chains($first_model); + my $first_chain = $chains[0]; + + if( defined $residue) { + if( (ref($residue) eq "ARRAY") || + ($residue->isa('Bio::Structure::Residue')) ) { + # remove existing ones, tell they've become orphan + my @obj = $self->get_residues($first_chain); + if (@obj) { + for my $r (@obj) { + $self->_remove_from_graph($r); + } + } + # add the new ones + $self->add_residue($first_chain,$residue); + } + else { + $self->throw("Supplied a $residue to residue, we want a Bio::Structure::Residue or a list of these\n"); + } + } + $self->get_residues($first_chain); +} + + +=head2 add_residue() + + Title : add_residue + Usage : @residues = $structure->add_residue($residue); + Function: Adds a (or a list of) Residue objects to a Bio::Structure::Entry. + Returns : list of Bio::Structure::Residue objects + Args : One Residue or a reference to an array of Residue objects + +=cut + +sub add_residue { + my($self,$chain,$residue) = @_; + + if (ref($chain) !~ /^Bio::Structure::Chain/) { + $self->throw("add_residue: first argument needs to be a Chain object\n"); + } + if (defined $residue) { + if (ref($residue) eq "ARRAY") { + # if the user passed in a reference to an array + for my $r ( @{$residue} ) { + if( ! $r->isa('Bio::Structure::Residue') ) { + $self->throw("$r is not a Residue\n"); + } + if ( $self->_parent($r) ) { + $self->throw("$r already belongs to a parent\n"); + } + $self->_parent($r, $chain); + $self->_child($chain, $r); + # stringify + my $str_ref = "$self"; + $r->_grandparent($str_ref); + } + } + elsif ( $residue->isa('Bio::Structure::Residue') ) { + if ( $self->_parent($residue) ) { + $self->throw("$residue already belongs to a parent\n"); + } + $self->_parent($residue, $chain); + $self->_child($chain, $residue); + # stringify + my $str_ref = "$self"; + $residue->_grandparent($str_ref); + } + else { + $self->throw("Supplied a $residue to add_residue, we want a Residue or list of Residues\n"); + } + } + my $array_ref = $self->_child($chain); + return $array_ref ? @{$array_ref} : (); +} + + +=head2 get_residues() + + Title : get_residues + Usage : $structure->get_residues($chain); + Function: general get method for residues attached to a Chain + Returns : a list of residues attached to this chain + Args : a chain + +=cut + +sub get_residues { + my ($self, $chain) = @_; + + if ( !defined $chain) { + $self->throw("get_residues needs a Chain as argument"); + } + # pass through to add_residue + $self->add_residue($chain); +} + + +=head2 add_atom() + + Title : add_atom + Usage : @atoms = $structure->add_atom($residue,$atom); + Function: Adds a (or a list of) Atom objects to a Bio::Structure::Residue. + Returns : list of Bio::Structure::Atom objects + Args : a residue and an atom + +=cut + +sub add_atom { + my($self,$residue,$atom) = @_; + + if (ref($residue) !~ /^Bio::Structure::Residue/) { + $self->throw("add_atom: first argument needs to be a Residue object\n"); + } + if (defined $atom) { + if (ref($atom) eq "ARRAY") { + # if the user passed in a reference to an array + for my $a ( @{$atom} ) { + if( ! $a->isa('Bio::Structure::Atom') ) { + $self->throw("$a is not an Atom\n"); + } + if ( $self->_parent($a) ) { + $self->throw("$a already belongs to a parent\n"); + } + $self->_parent($a, $residue); + $self->_child($residue, $a); + # stringify + #my $str_ref = "$self"; + #$r->_grandparent($str_ref); + } + } + #elsif ( $atom->isa('Bio::Structure::Atom') ) { + elsif ( ref($atom) =~ /^Bio::Structure::Atom/ ) { + if ( $self->_parent($atom) ) { + $self->throw("$atom already belongs to a parent\n"); + } + $self->_parent($atom, $residue); + $self->_child($residue, $atom); + # stringify + #my $str_ref = "$self"; + #$atom->_grandparent($str_ref); + } + } + my $array_ref = $self->_child($residue); + return $array_ref ? @{$array_ref} : (); +} + + +=head2 get_atoms() + + Title : get_atoms + Usage : $structure->get_atoms($residue); + Function: general get method for atoms attached to a Residue + Returns : a list of atoms attached to this residue + Args : a residue + +=cut + +sub get_atoms { + my ($self, $residue) = @_; + + if ( !defined $residue) { + $self->throw("get_atoms needs a Residue as argument"); + } + # pass through to add_atom + $self->add_atom($residue); +} + + +=head2 parent() + + Title : parent + Usage : $structure->parent($residue); + Function: returns the parent of the argument + Returns : the parent of the argument + Args : a Bio::Structure object + +=cut + +=head2 conect() + + Title : conect + Usage : $structure->conect($source); + Function: get/set method for conect + Returns : a list of serial numbers for atoms connected to source + (together with $entry->get_atom_by_serial($model, $serial) this should be OK for now) + Args : the serial number for the source atom + +=cut + +sub conect { + my ($self, $source, $serial, $type) = @_; + + if ( !defined $source ) { + $self->throw("You need to supply at least a source to conect"); + } + if ( defined $serial && defined $type ) { + if ( !exists(${$self->{'conect'}}{$source}) || ref(${$self->{'conect'}}{$source} !~ /^ARRAY/ ) ) { + ${$self->{'conect'}}{$source} = []; + } + # we also need to store type, a conect object might be better + my $c = $serial . "_" . $type; + push @{ ${$self->{'conect'}}{$source} }, $c; + } + return @{ ${$self->{'conect'}}{$source} }; +} + +=head2 get_all_conect_source() + + Title : get_all_conect_source + Usage : @sources = $structure->get_all_conect_source; + Function: get all the sources for the conect records + Returns : a list of serial numbers for atoms connected to source + (together with $entry->get_atom_by_serial($model, $serial) this should be OK for now) + Args : + Description : This is a bit of a kludge, but it's the best for now. Conect info might need + to go in a sepearte object + +=cut + +sub get_all_conect_source { + my ($self) = shift; + my (@sources); + + for my $source (sort {$a<=>$b} keys %{$self->{'conect'}}) { + push @sources, $source; + } + return @sources; +} + + +=head2 master() + + Title : master + Usage : $structure->master($source); + Function: get/set method for master + Returns : the master line + Args : the master line for this entry + +=cut + +sub master { + my ($self, $value) = @_; + if (defined $value) { + $self->{'master'} = $value; + } + return $self->{'master'}; +} + + +=head2 seqres() + + Title : seqres + Usage : $seqobj = $structure->seqres("A"); + Function: gets a sequence object containing the sequence from the SEQRES record. + if a chain-ID is given , the sequence for this chain is given, if none + is provided the first chain is choosen + Returns : a Bio::PrimarySeq + Args : the chain-ID of the chain you want the sequence from + +=cut + +sub seqres { + my ($self, $chainid) = @_; + my $s_u = "x3 A1 x7 A3 x1 A3 x1 A3 x1 A3 x1 A3 x1 A3 x1 A3 x1 A3 x1 A3 x1 A3 x1 A3 x1 A3 x1 A3"; + my (%seq_ch); + if ( !defined $chainid) { + my $m = ($self->get_models($self))[0]; + my $c = ($self->get_chains($m))[0]; + $chainid = $c->id; + } + my $seqres = ($self->annotation->get_Annotations("seqres"))[0]; + my $seqres_string = $seqres->as_text; +$self->debug("seqres : $seqres_string\n"); + $seqres_string =~ s/^Value: //; + # split into lines of 62 long + my @l = unpack("A62" x (length($seqres_string)/62), $seqres_string); + for my $line (@l) { + # get out chain_id and sequence + # we use a1, as A1 strips all spaces :( + my ($chid, $seq) = unpack("x3 a1 x7 A51", $line); + if ($chid eq " ") { + $chid = "default"; + } + $seq =~ s/(\w+)/\u\L$1/g; # ALA -> Ala (for SeqUtils) + $seq =~ s/\s//g; # strip all spaces + $seq_ch{$chid} .= $seq; +$self->debug("seqres : $chid $seq_ch{$chid}\n"); + } + # do we have a seqres for this chainid + if(! exists $seq_ch{$chainid} ) { + $self->warn("There is no SEQRES known for chainid \"$chainid\""); + return undef; + } + + # this will break for non-protein structures (about 10% for now) XXX KB + my $pseq = Bio::PrimarySeq->new(-alphabet => 'protein'); + $pseq = Bio::SeqUtils->seq3in($pseq,$seq_ch{$chainid}); + my $id = $self->id . "_" . $chainid; + $pseq->id($id); + return $pseq; +} + +=head2 get_atom_by_serial() + + Title : get_atom_by_serial + Usage : $structure->get_atom_by_serial($module, $serial); + Function: get the Atom for a for get_atom_by_serial + Returns : the Atom object with this serial number in the model + Args : Model on which to work, serial number for atom + (if only a number is supplied, the first model is chosen) + +=cut + +sub get_atom_by_serial { + my ($self, $model, $serial) = @_; + + if ($model =~ /^\d+$/ && !defined $serial) { # only serial given + $serial = $model; + my @m = $self->get_models($self); + $model = $m[0]; + } + if ( !defined $model || ref($model) !~ /^Bio::Structure::Model/ ) { + $self->throw("Could not find (first) model\n"); + } + if ( !defined $serial || ($serial !~ /^\d+$/) ) { + $self->throw("The serial number you provided looks fishy ($serial)\n"); + } + for my $chain ($self->get_chains($model) ) { + for my $residue ($self->get_residues($chain) ) { + for my $atom ($self->get_atoms($residue) ) { + # this could get expensive, do we cache ??? + next unless ($atom->serial == $serial); + return $atom; + } + } + } +} + +sub parent { + my ($self, $obj) = @_; + + if ( !defined $obj) { + $self->throw("parent: you need to supply an argument to get the parent from\n"); + } + + # for now we pass on to _parent, untill we get the symbolic ref thing working. + $self->_parent($obj); +} + +sub DESTROY { + my $self = shift; + + #print STDERR "DESTROY on $self being called\n"; + +## for my $pc (keys %{ $self->{'p_c'} } ) { +## next unless ( defined ${ $self->{'p_c'} }{$pc} ); +## delete ${$self->{'p_c'}}{$pc}; +## } +## for my $cp (keys %{ $self->{'c_p'} } ) { +## next unless ( defined ${ $self->{'c_p'} }{$cp} ); +## delete ${$self->{'c_p'}}{$cp}; +## } + %{ $self->{'p_c'} } = (); + %{ $self->{'c_p'} } = (); +} + +# copied from Bio::Seq.pm +# +=head2 annotation + + Title : annotation + Usage : $obj->annotation($seq_obj) + Function: + Example : + Returns : value of annotation + Args : newvalue (optional) + + +=cut + +sub annotation { + my ($obj,$value) = @_; + if( defined $value) { + $obj->{'annotation'} = $value; + } + return $obj->{'annotation'}; + +} + + +# +# from here on only private methods +# + +=head2 _remove_models() + + Title : _remove_models + Usage : + Function: Removes the models attached to an Entry. Tells the models they + don't belong to this Entry any more + Returns : + Args : + +=cut + +#' + +sub _remove_models { + my ($self) = shift; + + ; +} + + +=head2 _create_default_model() + + Title : _create_default_model + Usage : + Function: Creates a default Model for this Entry. Typical situation + in an X-ray structure where there is only one model + Returns : + Args : + +=cut + +sub _create_default_model { + my ($self) = shift; + + my $model = Bio::Structure::Model->new(-id => "default"); + return $model; +} + + +=head2 _create_default_chain() + + Title : _create_default_chain + Usage : + Function: Creates a default Chain for this Model. Typical situation + in an X-ray structure where there is only one chain + Returns : + Args : + +=cut + +sub _create_default_chain { + my ($self) = shift; + + my $chain = Bio::Structure::Chain->new(-id => "default"); + return $chain; +} + + + +=head2 _parent() + + Title : _parent + Usage : This is an internal function only. It is used to have one + place that keeps track of which object has which other object + as parent. Thus allowing the underlying modules (Atom, Residue,...) + to have no knowledge about all this (and thus removing the possibility + of reference cycles). + This method hides the details of manipulating references to an anonymous + hash. + Function: To get/set an objects parent + Returns : a reference to the parent if it exist, undef otherwise. In the + current implementation each node should have a parent (except Entry). + Args : + +=cut + +# manipulating the c_p hash + +sub _parent { + no strict "refs"; + my ($self, $key, $value) = @_; + + if ( (!defined $key) || (ref($key) !~ /^Bio::/) ) { + $self->throw("First argument to _parent needs to be a reference to a Bio:: object ($key)\n"); + } + if ( (defined $value) && (ref($value) !~ /^Bio::/) ) { + $self->throw("Second argument to _parent needs to be a reference to a Bio:: object\n"); + } + # no checking here for consistency of key and value, needs to happen in caller + + if (defined $value) { + # is this value already in, shout + if (defined ( $self->{'c_p'}->{$key}) && + exists ( $self->{'c_p'}->{$key}) + ) { + $self->throw("_parent: $key already has a parent ${$self->{'c_p'}}{$key}\n"); + } + ${$self->{'c_p'}}{$key} = $value; + } + return ${$self->{'c_p'}}{$key}; +} + + +=head2 _child() + + Title : _child + Usage : This is an internal function only. It is used to have one + place that keeps track of which object has which other object + as child. Thus allowing the underlying modules (Atom, Residue,...) + to have no knowledge about all this (and thus removing the possibility + to have no knowledge about all this (and thus removing the possibility + of reference cycles). + This method hides the details of manipulating references to an anonymous + hash. + Function: To get/set an object's child(ren) + Returns : a reference to an array of child(ren) if it exist, undef otherwise. + Args : + +=cut + +# manipulating the p_c hash +sub _child { + my ($self, $key, $value) = @_; + + if ( (!defined $key) || (ref($key) !~ /^Bio::/) ) { + $self->throw("First argument to _child needs to be a reference to a Bio:: object\n"); + } + if ( (defined $value) && (ref($value) !~ /^Bio::/) ) { + $self->throw("Second argument to _child needs to be a reference to a Bio:: object\n"); + } + # no checking here for consistency of key and value, needs to happen in caller + + if (defined $value) { + if ( !exists(${$self->{'p_c'}}{$key}) || ref(${$self->{'p_c'}}{$key}) !~ /^ARRAY/ ) { + ${$self->{'p_c'}}{$key} = []; + } + push @{ ${$self->{'p_c'}}{$key} }, $value; + } + return ${$self->{'p_c'}}{$key}; +} + + + +=head2 _remove_from_graph() + + Title : _remove_from_graph + Usage : This is an internal function only. It is used to remove from + the parent/child graph. We only remove the links from object to + his parent. Not the ones from object to its children. + Function: To remove an object from the parent/child graph + Returns : + Args : the object to be orphaned + +=cut + +sub _remove_from_graph { + my ($self, $object) = @_; + + if ( !defined($object) && ref($object) !~ /^Bio::/) { + $self->throw("_remove_from_graph needs a Bio object as argument"); + } + if ( $self->_parent($object) ) { + my $dad = $self->_parent($object); + # if we have a parent, remove me as being a child + for my $k (0 .. $#{$self->_child($dad)}) { + if ($object eq ${$self->{'p_c'}{$dad}}[$k]) { + splice(@{$self->{'p_c'}{$dad}}, $k,1); + } + } + delete( $self->{'c_p'}{$object}); + } +} + + +sub _print_stats_pc { + # print stats about the parent/child hashes + my ($self) =@_; + my $pc = scalar keys %{$self->{'p_c'}}; + my $cp = scalar keys %{$self->{'c_p'}}; + my $now_time = Time::HiRes::time(); + $self->debug("pc stats: P_C $pc C_P $cp $now_time\n"); +} + + +1;