[Bio] / FigKernelPackages / FigFam.pm Repository:
ViewVC logotype

View of /FigKernelPackages/FigFam.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.50 - (download) (as text) (annotate)
Thu May 10 13:12:02 2007 UTC (12 years, 10 months ago) by overbeek
Branch: MAIN
Changes since 1.49: +109 -77 lines
update FigFam.pm

#
# Copyright (c) 2003-2006 University of Chicago and Fellowship
# for Interpretations of Genomes. All Rights Reserved.
#
# This file is part of the SEED Toolkit.
# 
# The SEED Toolkit is free software. You can redistribute
# it and/or modify it under the terms of the SEED Toolkit
# Public License. 
#
# You should have received a copy of the SEED Toolkit Public License
# along with this program; if not write to the University of Chicago
# at info@ci.uchicago.edu or the Fellowship for Interpretation of
# Genomes at veronika@thefig.info or download a copy from
# http://www.theseed.org/LICENSE.TXT.
#

package FigFam;

use strict;
use FIG;
use SameFunc;
use gjoseqlib;
use gjoalignment;
use PHOB;
use Tracer;

use Carp;
use Data::Dumper;

=head1 Module to access FIGfams

=head3 new

usage:
C<< my $figfam_obj = FigFam->new($fig, $fam_id, $fam_dir); >>

This is the constructor.  Presumably, C<$class> is 'FigFam'.  

C<$fig> is an object reference created by a C<< FIG->new() >> constructor.

C<$fam_id> is the ID of the family, of the form C<FIGnnnnnn> where C<n> is a digit;
it is required.

C<$fam_data> is optional.  If it is defined, it will be treated
as the directory that contains (or will contain) FigFam data.
If omitted, the FIGfam directory defaults to
C<$FIG_Config::data/FigfamsData>.

A families file C<families.2c> must exist within C<$fam_data.>
It contains a 3-column tab-separated "tuple representation" of the FIG families, 
of the form
C<<< FIGfam_IDE<lt>tabE<gt>FIG_Protein_IDE<lt>tabE<gt>Assigned_function. >>>

If the C<$fam_dir/yyy/FIGxxxyyy> directory (which is where the subdirectory
where the specific family will go) does not exist, the specification of the PEGs
in C<$fam_file> will be used to initialize the family.

=cut


#### To turn on tracing, at the command line type
###
###  export TRACING=Ross
###  trace 3 FigFam
###

sub new {
    my($class,$fig,$fam_id,$fam_data) = @_;

    ($fam_id =~ /^FIG\d{6}$/) || confess "invalid family id: $fam_id";

    my $fam = {};
    $fam->{id}  = $fam_id;
    $fam->{fig} = $fig;

    if (! defined($fam_data))
    {
	$fam_data = "$FIG_Config::data/FigfamsData";
    }
    $fam->{data} = $fam_data;

    my $fam_dir = "$fam_data/FIGFAMS";
    my $fam_file = "$fam_data/families.2c";
    my $dir = &fam_dir($fam_data,$fam_id);
    $fam->{dir} = $dir;

    &FIG::verify_dir($dir);

    if ((! -s "$dir/built") && (! -s "$dir/PEGs") && defined($fam_file))
    {
	if (-s $fam_file)
	{
	    system("grep $fam_id \"$fam_file\" > \"$dir/PEGs\"");
	    if (! -s "$dir/PEGs")
	    {
		system "rm -rf $dir";
		confess "PEG file $dir/PEGs does not exist --- $dir deleted";
		return undef;
	    }
	    &Tracer::Trace('created PEGs file') if (T(3));
	}
	else
	{
	    confess "Family file $fam_file does not exist";
	    return undef;
	}
    }

    if ((! -s "$dir/function") && (! -s "$dir/built"))
    {
	&reset_function($fam);
	&Tracer::Trace("reset function for $fam_id") if (T(3));
    }

    open(FUNC,"<$dir/function") || die "could not open $dir/function";
    my $func = <FUNC>;
    chomp $func;
    close(FUNC);
    $fam->{function} = $func;
    
    my($peg,$pegs);
    my $pegsL = [
		 sort { &FIG::by_fig_id($a,$b) } 
		 grep { scalar $fig->function_of($_) eq $func }
		 grep { $fig->is_real_feature($_) } 
		 map { $_ =~ /^\S+\t(\S+)/; $1 } 
		 `cat \"$dir/PEGs\"`
		];

    if (@$pegsL < 2)
    {
	system "echo 1 > $dir/built";
	return undef;
    }

    $fam->{pegsL} = $pegsL;
    my $pegsH = {};
    foreach $peg (@$pegsL)
    {
	$pegsH->{$peg} = 1;
    }
    $fam->{pegsH} = $pegsH;
    
    
    if (-s "$dir/PEGs.fasta")
    {
	open(FASTA,"<$dir/PEGs.fasta") || die "could not read-open $dir/PEGs.fasta";
	while (my ($peg, $seqP) = &FIG::read_fasta_record(\*FASTA))
	{
	    $fam->{peg_lengths}->{$peg} = length($$seqP);
	}
	close(FASTA);
    }
    elsif (! -s "$dir/built")
    {
	open(FASTA,">$dir/PEGs.fasta") || die "could not write-open $dir/PEGs.fasta";
	foreach $peg (@$pegsL)
	{
	    my $seq = $fig->get_translation($peg);
	    if ($seq)
	    {
		print FASTA ">$peg\n$seq\n";
		$fam->{peg_lengths}->{$peg} = length($seq);
	    }
	    else
	    {
		confess "Could not get seq for $peg";
	    }
	}
	close(FASTA);
    }

    if ((! -s "$dir/built") && ((! -s "$dir/PEGs.fasta.pin") || ((-M "$dir/PEGs.fasta.pin") > (-M "$dir/PEGs.fasta"))))
    {
	&FIG::run("$FIG_Config::ext_bin/formatdb -i \"$dir/PEGs.fasta\" -p");
    }
    
    if ((! -s "$dir/bounds.sims") && (! -s "$dir/built"))
    {
	open(SIMS,">$dir/bounds.sims")
	    || die "could not open $dir/bounds.sims";
	
	foreach $peg (@$pegsL)
	{
	    my @sims = $fig->sims($peg,1000,1.0e-20,"fig");
	    foreach my $sim (@sims)
	    {
		print SIMS join("\t",$sim->id1,
			             $sim->id2,
			             $sim->bit_score,
			             scalar $fig->function_of($sim->id2)),"\n";
	    }
	    print SIMS "//\n";
	}
	close(SIMS);
    }

    if ((! -s "$dir/built") && (! -s "$dir/bounds"))
    {
	print STDERR " building bounds for $fam_id\n";
	open(BOUNDS,">$dir/bounds")    || die "could not open $dir/bounds";
	open(SIMS,"<$dir/bounds.sims") || die "could not open $dir/bounds.sims";

	my($sims);
	$/ = "\n//\n";
	while (defined($sims = <SIMS>))
	{
	    chomp $sims;
	    my @sims = sort { $b->[2] <=> $a->[2] } map { [split(/\t/,$_)] } split(/\n/,$sims);
	    if ($peg = $sims[0]->[0])
	    {
		my($i,$hits,$bad,$bad_sc,$last_good,$func2);
		for ($i=0, $hits=0, $bad="", $bad_sc=0, $last_good=1; ($i < @sims) && (! $bad); $i++)
		{
		    my $sim = $sims[$i];
		    my $id2 = $sim->[1];
		    if ($pegsH->{$id2})
		    {
			$last_good = $sim->[2];
			$hits++;
		    }
		    else
		    {
			$func2 = $sim->[3];
			if (! &ok_func($fig,$func,$func2,$id2,$fam))
			{
			    $bad = $id2;
			    $bad_sc = $sim->[2];
			}
		    }
		}

		if ($hits > 0)
		{
		    print BOUNDS join("\t",($peg,$hits,$last_good,$bad,$bad_sc)),"\n";
		}
	    }
	}
	close(BOUNDS);
	close(SIMS);
	$/ = "\n";
    }

    my $bounds = {};
    if (open(BOUNDS,"<$dir/bounds"))
    {
	my $x;
	while (defined($x = <BOUNDS>))
	{
	    chomp $x;
	    my @flds = split(/\t/,$x);
	    my $peg =shift @flds;
	    $bounds->{$peg} = [@flds];
	}
	close(BOUNDS);
	$fam->{bounds} = $bounds;
    }

    if ((! -d "$dir/SplitNew") && (! -s "$dir/built"))
    {
	mkdir("$dir/SplitNew",0777) || die "could not make $dir/SplitNew";
	my $seqs    = &gjoseqlib::read_fasta("$dir/PEGs.fasta");
	my %seqs = map { $_->[0] => $_ } @$seqs;
	my(undef,$sets) = &representative_sequences::rep_seq_2($seqs,{ max_sim => 0.3 });
	my $n = 1;
	foreach my $id (sort { @{$sets->{$b}}  <=> @{$sets->{$a}} } keys(%$sets))
	{
	    my @ext_seqs = map { $seqs{$_} } ($id,@{$sets->{$id}});
	    if (@ext_seqs > 1)
	    {
		my $trimmed = &PHOB::kernel_of_trimmed_seqs(seqs => \@ext_seqs);
		if (@$trimmed > 1)
		{
		    my $ali     = &PHOB::align_seqs(seqs => $trimmed);
		    &gjoseqlib::print_alignment_as_fasta("$dir/SplitNew/$n.ali",$ali);
		    $n++;
		}
	    }
	}
    }

    
    my $blast_file = "$dir/blastout";
    my $rep_file   = "$dir/reps";
    if ((! -f $blast_file) && (! -s "$dir/built"))
    {
        &FIG::run("split_and_trim_sequences $dir/Split blastout=$blast_file < $dir/PEGs.fasta");
        if (-s $blast_file)
        {
            my @out = map { chop; [split(/\t/,$_) ] } `cat $blast_file`;
            my @keep = ();
            my $write = 0;
            my $i;
            for ($i=0; ($i < @out); $i++)
            {
                if ((($i == 0) ||
                     (($out[$i-1]->[0] ne $out[$i]->[0]) || ($out[$i-1]->[1] ne $out[$i]->[1]))) &&
                    ($out[$i-1]->[6] <= 1.0e-10))
                {
                    push(@keep,$out[$i]);
                }
                else
                {
                    $write = 1;
                }
            }
            if ($write)
            {
                open(OUT,">$blast_file") || die $blast_file;
                foreach my $x (@keep)
                {
                    print OUT join("\t",@$x),"\n";
                }
                close(OUT);
            }
        }
    }

    if ((-s "$dir/Split/set.sizes") && (! -s "$dir/built"))
    {
        my @to_align = map { (($_ =~ /^(\d+)\t(\d+)/) && ($2 > 1)) ? $1 : () } `cat $dir/Split/set.sizes`;
        foreach my $n (@to_align)
        {
            if (! -s "$dir/Split/$n.aln")
            {
                system "runclustalw $dir/Split/$n";
            }
        }
    }

    if ((-s $blast_file) && (! -s $rep_file) && (! -s "$dir/built"))
    {
        my $n = 1;
        open(REP,">$rep_file")          || die "could not open $rep_file";
        open(FASTA,"<$dir/PEGs.fasta")  || die "could not open $dir/PEGs.fasta";
        my %seen;
        my($seq,$peg,$sim);
        $/ = "\n>";
        while (defined($_ = <FASTA>))
        {   
            chomp;
            if ($_ =~ /^>?(\S+)[^\n]*\n(.*)/s)
            {
                $peg  =  $1;
                if (! $seen{$peg})
                {
                    $seq =  $2;
                    $seq =~ s/\s//gs;
                    print REP ">$fam_id-$n\n$seq\n";
                    $n++;

                    $/ = "\n";
                    $seen{$peg} = 1;

                    open(BLAST,"<$blast_file") || die "could not open $blast_file";
                    while (defined($sim = <BLAST>))
                    {
                        if (($sim =~ /^(\S+)\t(\S+)(\t\d+){4}\t(\S+)/) && ($1 eq $peg) &&
                            ($4 < 1.0e-10))
                        {
                            $seen{$2} = 1;
                        }
                    }
                    close(BLAST);
                    $/ = "\n>";
                }
            }
        }
        $/ = "\n";
        close(FASTA);
        close(REP);
    }

    $fam->{reps} = (-s $rep_file) ? [map { $_ =~ /^(\S+)/; $1 } `grep -v "^>" $rep_file`] : [];

#   if (@$pegsL < 4)
#   {
#	if (! -s "$dir/built") { system "echo 1 > $dir/built" }
#	return undef;
#   }

    if ((! -s "$dir/built") && $fam->{bounds}) { system "echo 1 > $dir/built" }
    bless $fam,$class;
    return $fam;
}

sub alignment {
    my($self) = @_;

    my $dir  = $self->{dir};
    my $fig  = $self->{fig};

    my $kernel_file = "$dir/kernel_alignment.fasta";
    my $ali_file = "$dir/alignment.fasta";

    if ((! -s $kernel_file) && (! -s "$dir/built.ali") && (-s "$dir/PEGs.fasta"))
    {
        my $seqs    = &gjoseqlib::read_fasta("$dir/PEGs.fasta");
        my $ali     = &PHOB::trimmed_aligned_kernel(seqs => $seqs, retrim => 1, tmp => $FIG_Config::temp );
        &gjoseqlib::print_alignment_as_fasta("$kernel_file",$ali);
    }

    if ((! -s $ali_file) && (-s $kernel_file) && (! -s "$dir/built.ali") && (-s "$dir/PEGs.fasta"))
    {
        my $seqs    = &gjoseqlib::read_fasta("$dir/PEGs.fasta");
	my $ali;
	if (-s "$ali_file.last")
	{
	    $ali = &gjoseqlib::read_fasta("$ali_file.last");
	}
	else
	{
	    $ali = &gjoseqlib::read_fasta($kernel_file);
	}

        my($seq);
	my %in_ali = map { $_->[0] => 1 } @$ali;
        foreach $seq (grep { ! $in_ali{$_->[0]} } @$seqs)
        {
            print STDERR "adding $seq->[0] to alignment\n";
            $ali     = &gjoalignment::add_to_alignment($seq,$ali,1);
	    my @tmp = @$ali;
            &gjoseqlib::print_alignment_as_fasta("$ali_file.last",$ali);
	    system "cat $ali_file.last >> $dir/log; echo '====' >> $dir/log";
        }

	if (! -s "$ali_file.last")
	{
            &gjoseqlib::print_alignment_as_fasta($ali_file,$ali);
	}
	else
	{
	    rename("$ali_file.last",$ali_file);
	}
	system "echo 1 > $dir/built.ali";
    }
    if (-s $ali_file)
    {
	return &gjoseqlib::read_fasta($ali_file);
    }
    else
    {
	return undef;
    }
}


=head3 reset_function

usage:
C<< $figfam_obj->reset_function(); >>

Resets the function of a FIGfam to its "consensus function,"
where the weight of a vote toward the "consensus" is doubled
for PEGs connected to a subsytem.

=cut

sub reset_function {
    my($self) = @_;

    my $fam_dir  = $self->{dir};
    my $fig      = $self->{fig};

    my @pegs = grep { $fig->is_real_feature($_) } map { $_ =~ /^\S+\t(\S+)/; $1 } `cat "$fam_dir/PEGs"`;
    my($peg,%funcs,$func,@subs);
    foreach $peg (@pegs)
    {
	$func = $fig->function_of($peg);
	@subs = grep { $fig->usable_subsystem($_) } $fig->peg_to_subsystems($peg);
	my $incr = (@subs > 0) ? 2 : 1;
	$funcs{$func} += $incr;
    }
    my @funcs = sort { $funcs{$b} <=> $funcs{$a} } keys(%funcs);
    $func = (@funcs > 0) ? $funcs[0] : "hypothetical protein";
    open(FUNC,">$fam_dir/function") || die "could not open $fam_dir/function";
    print FUNC "$func\n";
    close(FUNC);
}


=head3 display

usage:
C<< print $figfam_obj->display(); >>

Returns a list-formatted table describing a family and its members.

=cut

sub display {
    my($self) = @_;

    my $fam_id   = $self->family_id;
    my $fig      = $self->{fig};
    my $fam_func = $self->family_function;
    my $fam_dir  = $self->{dir};
    my @pegs     = map { chomp; $_ } `cut -f2 $fam_dir/PEGs`;

    my $peg;
    my @disp  = ( "ID:        $fam_id",
		  "Function:  $fam_func",
		  "Directory: $fam_dir",
                  "PEGs:",
		  map { $peg = $_; "    " . join("\t",($peg,
						       $fig->genus_species(&FIG::genome_of($peg)),
						       scalar $fig->function_of($_))) 
		      } @pegs
	       );

    return join("\n", @disp) . "\n";
}

=head3 pegs_of

usage:
C<< print $figfam_obj->pegs_of(); >>

Returns a list of just pegs.

=cut

sub pegs_of {
    my($self) = @_;
    my $fam_dir  = $self->{dir};
    my @pegs     = map { chomp; $_ } `cut -f2 $fam_dir/PEGs`;
    return [@pegs];
}


=head3 fasta_of

usage:

C<< $seqs_of_members = $figfam_obj->fasta_of(); >>

or

C<< $figfam_obj->fasta_of($filehandle_glob); >>

Returns a ptr to a hash containing the sequences for all members of a FIGfam,
keyed by FIG feature ID (FID).
The filehandle glob is optional;
if included, the sequences will also print to the handle's file,
in fasta format.

=cut

sub fasta_of {
    my($self, $fh) = @_;
    
    my $fam_id   = $self->family_id;
    my $fam_dir  = $self->{dir};
    
    if (-s "$fam_dir/PEGs.fasta") {
	open(FASTA, "<$fam_dir/PEGs.fasta")
	    || die "Could not read-open $fam_dir/PEGs.fasta";
	
	my $seq_of = {};
	my ($id, $seqP);
	while (($id, $seqP) = &FIG::read_fasta_record(\*FASTA)) {
	    $seq_of->{$id} = $$seqP;
	    if (defined($fh)) {
		print $fh ">$id\n$$seqP\n";
	    }
	}
	close(FASTA) || die "Could not close $fam_dir/PEGs.fasta";
	return $seq_of;
    }
    else {
	return undef;
    }
}



=head3 ok_func

usage:
C<< if ( &FigFam::ok_func( $fig, $func, $func2, $id2, $fam) ) { #...do something... } >>

C<$fig> is an object constriucted by C<FIG->new()>.

C<$func> and C<$func2> are two possible assigned functions.

C<$id2> is the FIG ID (FID) of the PEG having function C<$func2>.

C<$fam> is the family that C<$id2> is presumed to be a member of.

Returns C<TRUE> is C<$func> and C$func2> are loosely "the same,"
or if C<$func> is judged to be "ignorable."

=cut

sub ok_func {
    my($fig,$func,$func2,$id2,$fam) = @_;

    my $i;
    if (&loose_same_func($func,$func2) || ($func eq $fig->function_of($id2))) { return 1 }
#
    my $funcI;
    if (defined($funcI = $fam->{ignorable_func}->{"$id2\t$func"}))
    {
	return $funcI;
    }

    my @sims = $fig->sims($id2,5,1.0e-30,"fig");
    if ($ENV{VERBOSE} && ($ENV{VERBOSE} > 1)) { print STDERR &FIG::flatten_dumper(\@sims), "\n"; }
    my($func3);
    for ($i=0; ($i < @sims) && (defined($func3 = $fig->function_of($sims[$i]->id2))) && 
	       (&FIG::hypo($func3) || &SameFunc::same_func($func,$func3)); $i++) {}
    if (($i == @sims) && ($ENV{'VERBOSE'})) { print STDERR "make assignment: $id2\t$func\n" }
    
    $fam->{ignorable_func}->{"$id2\t$func"} = ($i == @sims);

    return $fam->{ignorable_func}->{"$id2\t$func"}
}


=head3 member

usage:
C<< if ( &FigFam::member($x, \@y)) { #...do something... } >>

C<$x> is a scalar.

C<\@y> is a ptr to a list.

Returns C<TRUE> if C<$x> is in list C<@y>.

=cut

sub member {
    my($x,$yL) = @_;
    my $i;

    for ($i=0; ($i < @$yL) && ($yL->[$i] ne $x); $i++) {}
    return ($i < @$yL);
}



=head3 list_members

usage:
C<< @ids = $figfam_obj->list_members(); >>

Returns a list of the PEG FIDs in a family.

=cut

sub list_members {
    my ($self)  = @_;
    
    my $fam_dir = $self->{dir};
    my @pegs    = map { chomp; $_ } `cut -f2 $fam_dir/PEGs`;
    
    return @pegs;
}



=head3 loose_same_func

usage:

C<< if ( &FigFam::loose_same_func($f1, $f2) ) {	#...do something... } >>

C<$f1> and C<$f2> are function strings.

Returns C<TRUE> if C<$f1> and C<$f2> are "more or less the same."

=cut

sub loose_same_func {
    my($f1,$f2) = @_;

    if (&SameFunc::same_func($f1,$f2,'strong')) { return 1 }
    my @s1 = split(/\s*[;\/@]\s*/,$f1);
    my @s2 = split(/\s*[;\/@]\s*/,$f2);
    if ((@s1 == 1) && (@s2 > 1) && &member($s1[0],\@s2))
    {
	return 1;
    }
    elsif ((@s2 == 1) && (@s1 > 1) && &member($s2[0],\@s1))
    {
	return 1;
    }
    else
    {
	return 0;
    }
}



=head3 representatives

usage:
    C<< @rep_seqs = $figfam_obj->representatives(); >>

Returns a list of the "representative sequences" characterizing a FIGfam.

=cut

sub representatives {
    my($self) = @_;

    my $reps = $self->{reps};
    return @$reps;
}



=head3 should_be_member

usage:
C<< if ( $figfam_obj->should_be_member( $seq ) ) { #...do something... } >>

Returns C<TRUE> if the protein sequence in C<$seq> is judged to be
"similar enough" to the members of a family to potentially be included.

=cut

sub should_be_member {
    my($self,$seq,$debug) = @_;
    
    if ($debug) { $ENV{'VERBOSE'} = $ENV{'DEBUG'} = 1 }
    
    my $fig = $self->{fig};    
    my $dir = $self->{dir};
    open(TMP,">$FIG_Config::temp/tmp$$.fasta") 
	|| die "could not open $FIG_Config::temp/tmp$$.fasta";
    print TMP ">query\n$seq\n";
    close(TMP);
    
    if ($ENV{'DEBUG'}) { print STDERR &Dumper([$self->family_id,$seq]) }
    
    my $query_ln = length($seq);
    
    my @tmp = `blastall -i $FIG_Config::temp/tmp$$.fasta -d $dir/PEGs.fasta -m 8 -FF -p blastp`;
    
    my %seen;
    my $should_be = 0;
    my $yes = 0;
    my $no  = 0;
    
    my $ln1 = length($seq);
    my $good = 0;
    my $bad = 0;

    my $sims = [];
    foreach $_ (@tmp)
    {
	if ($ENV{'DEBUG'}) { print STDERR $_ }
	chop;
	
	my $sim = [split(/\t/,$_)];
	my $peg = $sim->[1];
	next if (($_ = $ENV{'IGNORE'}) && (&FIG::genome_of($peg) eq $_)); # for debugging

	my $sc = $sim->[10];
	my $bit_score = $sim->[11];

	my $matched1 = abs($sim->[7] - $sim->[6]) + 1;
	my $matched2 = abs($sim->[9] - $sim->[8]) + 1;
	my $ln2 = $self->{peg_lengths}->{$peg};

	if ((! $seen{$peg}) && ($sc <= 1.0e-10) && 
	    ($matched1 >= (0.8 * $ln1)) && 
	    ($matched2 >= (0.8 * $ln2)))
	{
	    $seen{$peg} = 1;
	    push @$sim, $query_ln, $self->{peg_lengths}->{$peg};
	    bless $sim, 'Sim';
	    push @$sims, $sim;
	    
	    my $bounds = $self->{bounds}->{$peg};
	    if ($bounds && (@$sims <= 10))
	    {
		if (($bit_score >= $bounds->[1]) && ((! $bounds->[2]) || $bounds->[3] < $bit_score))
		{
		    if ($ENV{'DEBUG'}) { print STDERR "    yes - $peg matched1=$matched1 ln1=$ln1 matched2=$matched2 ln2=$ln2\n" }
		    ++$yes;
		    if ($yes > ($no+1)) { $good = 1 }
		}
		else
		{
		    my $bad_func = $bounds->[2] ? $fig->function_of($bounds->[2]) : "";
		    if ($ENV{'DEBUG'}) { print STDERR "    no - $peg ",join(",",@$bounds)," $bad_func\n" }
		    ++$no;
		    if ($no > $yes) { $bad = 1 }
		}
	    }
	}
    }
    $good = ($good && (! $bad)) ? 1 : 0;
    if ($ENV{'DEBUG'}) { print STDERR "        yes=$yes no=$no good=$good\n" }
    return ($good,$sims);
}



=head3 family_function

usage:
C<< $func = $figfam_obj->family_function(); >>

Returns the "consensus function" assigned to a FIGfam object.

=cut

sub family_function {
    my($self) = @_;

    return $self->{function}
}



=head3 family_id

usage:
C<< $fam_id = $figfam_obj->family_id(); >>

Returns the FIGfam ID of a FIGfam object.

=cut

sub family_id {
    my($self) = @_;

    return $self->{id};
}



=head3 family_dir

usage:
    
C<< $dir = &FigFam::family_dir( $fam_data, $fam_id ); >>

Returns the path to the subdirectory of C<$fam_data>
that the FIGfam data for a FIGfam with ID C<$fam_id>
would be stored in.

=cut

sub fam_dir {
    my($fam_data,$fam_id) = @_;

    $fam_id =~ /(\d{3})$/;
    return "$fam_data/FIGFAMS/$1/$fam_id";
}

1;

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3