File Coverage

Bio/PopGen/Simulation/GeneticDrift.pm
Criterion Covered Total %
statement 53 69 76.8
branch 9 14 64.2
condition 7 21 33.3
subroutine 9 11 81.8
pod 8 8 100.0
total 86 123 69.9


line stmt bran cond sub pod time code
1             #
2             # BioPerl module for Bio::PopGen::Simulation::GeneticDrift
3             #
4             # Please direct questions and support issues to
5             #
6             # Cared for by Jason Stajich
7             #
8             # Copyright Jason Stajich
9             #
10             # You may distribute this module under the same terms as perl itself
11              
12             # POD documentation - main docs before the code
13              
14             =head1 NAME
15              
16             Bio::PopGen::Simulation::GeneticDrift - A simple genetic drift simulation
17              
18             =head1 SYNOPSIS
19              
20             use Bio::PopGen::Simulation::GeneticDrift;
21             my $sim = Bio::PopGen::Simulation::GeneticDrift->new(-popsize => 40,
22             -alleles => {A => 0.2,
23             B => 0.8});
24             for(my $i =0 ;$i < 10; $i++ ) {
25             my %f = $sim->next_generation; # get the freqs for each generation
26             }
27              
28             for(my $i =0 ;$i < 10; $i++ ) {
29             # get the allele freqs as part of a Bio::PopGen::Population object
30             my $pop = $sim->next_generation('population');
31             }
32              
33             =head1 DESCRIPTION
34              
35             A very simple 1 locus multi-allele random drift module, start with an
36             initial set of allele frequency and simulate what happens over time.
37              
38             This isn't really useful for anything in particular yet but will be
39             built upon.
40              
41             See Gillespie JH. (1998) "Population Genetics: a Concise guide." The Johns
42             Hopkins University Press, Baltimore, USA. pp.19-47.
43              
44             =head1 FEEDBACK
45              
46             =head2 Mailing Lists
47              
48             User feedback is an integral part of the evolution of this and other
49             Bioperl modules. Send your comments and suggestions preferably to
50             the Bioperl mailing list. Your participation is much appreciated.
51              
52             bioperl-l@bioperl.org - General discussion
53             http://bioperl.org/wiki/Mailing_lists - About the mailing lists
54              
55             =head2 Support
56              
57             Please direct usage questions or support issues to the mailing list:
58              
59             I
60              
61             rather than to the module maintainer directly. Many experienced and
62             reponsive experts will be able look at the problem and quickly
63             address it. Please include a thorough description of the problem
64             with code and data examples if at all possible.
65              
66             =head2 Reporting Bugs
67              
68             Report bugs to the Bioperl bug tracking system to help us keep track
69             of the bugs and their resolution. Bug reports can be submitted via
70             email or the web:
71              
72             https://github.com/bioperl/bioperl-live/issues
73              
74             =head1 AUTHOR - Jason Stajich
75              
76             Email jason-at-bioperl-dot-org
77              
78             =head1 APPENDIX
79              
80             The rest of the documentation details each of the object methods.
81             Internal methods are usually preceded with a _
82              
83             =cut
84              
85              
86             # Let the code begin...
87              
88              
89             package Bio::PopGen::Simulation::GeneticDrift;
90 1     1   387 use strict;
  1         1  
  1         22  
91              
92 1     1   266 use Bio::PopGen::Population;
  1         2  
  1         24  
93              
94 1     1   5 use base qw(Bio::Root::Root);
  1         0  
  1         638  
95              
96             =head2 new
97              
98             Title : new
99             Usage : my $obj = Bio::PopGen::Simulation::GeneticDrift->new();
100             Function: Builds a new Bio::PopGen::Simulation::GeneticDrift object
101             Returns : an instance of Bio::PopGen::Simulation::GeneticDrift
102             Args : -popsize => starting N
103             -haploid => boolean if we should simulate haploids
104             -alleles => arrayref of the allele names
105             OR
106             -population => L object to initialize
107             from some previously defined Population object
108             (or result from a previous simulation)
109              
110             =cut
111              
112             sub new {
113 2     2 1 1319 my($class,@args) = @_;
114              
115 2         10 my $self = $class->SUPER::new(@args);
116 2         9 my ($population,
117             $popsize, $haploid, $alleles) = $self->_rearrange([qw(POPULATION
118             POPSIZE
119             HAPLOID
120             ALLELES)],@args);
121 2 50 33     8 if( defined $population && ref($population) &&
      33        
122             $population->isa('Bio::PopGen::PopulationI') ) {
123 0   0     0 $self->population_size($population->get_number_individuals || $popsize);
124 0         0 my %f = $population->get_Allele_Frequencies;
125 0         0 while( my ($allele,$freq) = each %f ) {
126 0         0 $self->add_Allele_Frequency($allele,$freq);
127             }
128             } else {
129 2         5 $self->population_size($popsize);
130            
131 2 50 33     10 if( ! defined $alleles || ref($alleles) !~ /HASH/i ) {
132 0         0 $self->throw("Must provide a valid set of initial allele frequencies to $class as an hashref");
133             }
134 2         8 while( my ($allele,$freq) = each %$alleles ) {
135 5         6 $self->add_Allele_Frequency($allele,$freq);
136             }
137             }
138 2 50       4 unless( $self->validate_Frequencies ) {
139 0         0 $self->throw("You specified allele frequencies which summed to more than 1");
140             }
141 2         4 return $self;
142             }
143              
144              
145             =head2 next_generation
146              
147             Title : next_generation
148             Usage : my %generation = $sim->next_generation
149             Function: Get the next generation of allele frequencies based on the current
150             generation
151             Returns : Hash of allele frequencies
152             Args : 'allelefreqs' or 'population' to get back a hash of allele
153             frequencies (default) OR a L object
154              
155              
156             =cut
157              
158             sub next_generation{
159 20     20 1 8273 my ($self,$rettype) = @_;
160 20         30 my %initial = $self->get_Allele_Frequencies;
161 20   33     29 my $popsize = $self->population_size ||
162             $self->throw("Need to have set a valid population size when running the simulation");
163             # we're going to construct a mapping of the rational space from 0->1
164             # which will map to a particular allele and be proportional to it
165             # frequency
166 20         21 my ($last,@mapping) = (0);
167              
168             # we'll make ranges that cover from >= left and < right in terms of the
169             # order doesn't matter - 'distance' does
170             # range that we're going to try and match
171             # since rand() goes from 0 up to 1 (not including 1)
172 20         32 foreach my $a ( keys %initial ) {
173 41         64 push @mapping, [$last,$initial{$a}+$last,$a];
174 41         44 $last += $initial{$a};
175             }
176              
177 20         19 my %f;
178 20         35 for( my $i =0; $i < $popsize; $i++ ) {
179 900         579 my $rand = rand(1);
180 900         630 foreach my $val ( @mapping ) {
181 1423 100 66     3461 if( $rand >= $val->[0] && $rand < $val->[1] ) {
182 900         641 $f{$val->[2]}++;
183 900         1132 last;
184             }
185             }
186             }
187 20         23 foreach my $f ( values %f ) {
188 39         45 $f /= $popsize;
189             }
190 20         21 %{$self->{'_allele_freqs'}} = %f;
  20         50  
191            
192 20 50 33     50 if( defined $rettype &&
193             $rettype =~ /population/i) {
194 0         0 return Bio::PopGen::Poulation->new(-frequencies => \%f);
195             } else {
196 20         77 return %f;
197             }
198              
199             }
200              
201             =head2 population_size
202              
203             Title : population_size
204             Usage : $obj->population_size($newval)
205             Function:
206             Example :
207             Returns : value of population_size (a scalar)
208             Args : on set, new value (a scalar or undef, optional)
209              
210              
211             =cut
212              
213             sub population_size{
214 22     22 1 17 my $self = shift;
215              
216 22 100       41 return $self->{'_population_size'} = shift if @_;
217 20         38 return $self->{'_population_size'};
218             }
219              
220             =head2 set_Frequencies_Equivalent
221              
222             Title : set_Frequencies_Equivalent
223             Usage : $sim->set_Frequencies_Equivalent
224             Function: Reset the allele frequencies so they are all even
225             Returns : none
226             Args : none
227              
228              
229             =cut
230              
231             sub set_Frequencies_Equivalent{
232 0     0 1 0 my ($self) = @_;
233 0         0 my @alleles = keys %{$self->{'_allele_freqs'}};
  0         0  
234 0         0 my $eqfreq = 1 / scalar @alleles;
235 0         0 for ( @alleles ) { $self->{'_allele_freqs'}->{$_} = $eqfreq }
  0         0  
236 0         0 return;
237             }
238              
239              
240             =head2 get_Allele_Frequencies
241              
242             Title : get_Allele_Frequencies
243             Usage : my %allele_freqs = $marker->get_Allele_Frequencies;
244             Function: Get the alleles and their frequency (set relative to
245             a given population - you may want to create different
246             markers with the same name for different populations
247             with this current implementation
248             Returns : Associative array where keys are the names of the alleles
249             Args : none
250              
251              
252             =cut
253              
254             sub get_Allele_Frequencies{
255 22     22 1 17 return %{$_[0]->{'_allele_freqs'}};
  22         72  
256             }
257              
258             =head2 add_Allele_Frequency
259              
260             Title : add_Allele_Frequency
261             Usage : $marker->add_Allele_Frequency($allele,$freq)
262             Function: Adds an allele frequency
263             Returns : None
264             Args : $allele - allele name
265             $freq - frequency value
266              
267              
268             =cut
269              
270             sub add_Allele_Frequency{
271 5     5 1 5 my ($self,$allele,$freq) = @_;
272 5         13 $self->{'_allele_freqs'}->{$allele} = $freq;
273             }
274              
275             =head2 reset_alleles
276              
277             Title : reset_alleles
278             Usage : $marker->reset_alleles();
279             Function: Reset the alleles for a marker
280             Returns : None
281             Args : None
282              
283              
284             =cut
285              
286             sub reset_alleles{
287 0     0 1 0 my ($self) = @_;
288 0         0 $self->{'_allele_freqs'} = {};
289             }
290              
291             =head2 validate_Frequencies
292              
293             Title : validate_Frequencies
294             Usage : if( $sim->validate_Frequencies) {}
295             Function: Sanity checker that allele frequencies sum to 1 or less
296             Returns : boolean
297             Args : -strict => 1 boolean if you want to insure that sum of freqs is 1
298              
299              
300             =cut
301              
302             sub validate_Frequencies{
303 2     2 1 3 my ($self,@args) = @_;
304 2         4 my ($strict) = $self->_rearrange([qw(STRICT)], @args);
305 2         3 my $sum = 0;
306 2         3 my %freq = $self->get_Allele_Frequencies;
307 2         3 foreach my $f ( values %freq ) {
308 5         6 $sum += $f;
309             }
310 2 50       8 return ($strict) ? $sum == 1 : $sum <= 1;
311             }
312              
313              
314             1;