1 /*
2  * scrm is an implementation of the Sequential-Coalescent-with-Recombination Model.
3  *
4  * Copyright (C) 2013, 2014 Paul R. Staab, Sha (Joe) Zhu, Dirk Metzler and Gerton Lunter
5  *
6  * This file is part of scrm.
7  *
8  * scrm is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "model.h"
23 
24 
Model()25 Model::Model() :
26   has_migration_(false),
27   has_recombination_(false) {
28 
29   this->set_loci_number(1);
30   this->setLocusLength(1);
31   this->addChangeTime(0.0);
32   this->addChangePosition(0.0);
33 
34   this->set_population_number(1);
35 
36   this->setMutationRate(0.0);
37   this->setRecombinationRate(0.0);
38 
39   this->window_length_seq_ = 0;
40   this->set_window_length_rec(500);
41 
42   this->setSequenceScaling(ms);
43 
44   this->resetTime();
45   this->resetSequencePosition();
46 }
47 
48 
Model(size_t sample_size)49 Model::Model(size_t sample_size) :
50   has_migration_(false),
51   has_recombination_(false) {
52 
53   this->set_loci_number(1);
54   this->setLocusLength(1);
55   this->addChangeTime(0.0);
56   this->addChangePosition(0.0);
57 
58   this->set_population_number(1);
59 
60   this->setMutationRate(0.0);
61   this->setRecombinationRate(0.0);
62 
63   this->window_length_seq_ = 0;
64   this->set_window_length_rec(500);
65 
66   this->setSequenceScaling(ms);
67 
68   this->addSampleSizes(0.0, std::vector<size_t>(1, sample_size));
69   this->setLocusLength(1000);
70   this->resetTime();
71   this->resetSequencePosition();
72 }
73 
74 
75 /**
76  * Function to add a new change time to the model.
77  *
78  * It preserves the relation between the times and the *param*_list_ containers.
79  * If the same time is added multiple times, it is just added once to the model,
80  * but this should not make a difference when using this function.
81  *
82  * @param time The time that is added
83  * @param scaled set to TRUE if the time is in units of 4N0 generations, and
84  * FALSE if it is in units of generations.
85  *
86  * @returns The position the time has now in the vector
87  */
addChangeTime(double time,const bool & scaled)88 size_t Model::addChangeTime(double time, const bool &scaled) {
89   if (scaled) time *= 4 * default_pop_size();
90 
91   size_t position = 0;
92   if ( change_times_.size() == 0 ) {
93     change_times_ = std::vector<double>(1, time);
94     pop_sizes_list_.push_back(std::vector<double>());
95     growth_rates_list_.push_back(std::vector<double>());
96     mig_rates_list_.push_back(std::vector<double>());
97     total_mig_rates_list_.push_back(std::vector<double>());
98     single_mig_list_.push_back(std::vector<MigEvent>());
99     return position;
100   }
101 
102   std::vector<double>::iterator ti;
103   for (ti = change_times_.begin(); ti != change_times_.end(); ++ti) {
104     if ( *ti == time ) return position;
105     if ( *ti > time ) break;
106     ++position;
107   }
108 
109   change_times_.insert(ti, time);
110 
111   // Add Null at the right position in all parameter vectors
112   pop_sizes_list_.insert(pop_sizes_list_.begin() + position, std::vector<double>());
113   growth_rates_list_.insert(growth_rates_list_.begin() + position, std::vector<double>());
114   mig_rates_list_.insert(mig_rates_list_.begin() + position, std::vector<double>());
115   total_mig_rates_list_.insert(total_mig_rates_list_.begin() + position, std::vector<double>());
116   single_mig_list_.insert(single_mig_list_.begin() + position, std::vector<MigEvent>());
117   return position;
118 }
119 
120 
121 /**
122  * Adds a new change position to the model.
123  *
124  * Change position are sequence positions where mutation or recombination rates
125  * change. This creates a new position, but does not add the new rates.
126  *
127  * @param position The sequence position add which a change is added
128  *
129  * @returns The index of the new rates in the recombination_rates_ and
130  * mutation_rates vectors.
131  */
addChangePosition(const double position)132 size_t Model::addChangePosition(const double position) {
133   if (position < 0 || position > loci_length()) {
134     std::stringstream ss;
135     ss << "Rate change position " << position << " is outside of the simulated sequence.";
136     throw std::invalid_argument(ss.str());
137   }
138 
139   if ( change_position_.size() == 0 ) {
140     change_position_ = std::vector<double>(1, position);
141     recombination_rates_.push_back(-1);
142     mutation_rates_.push_back(-1);
143     return 0;
144   }
145 
146   size_t idx = 0;
147   std::vector<double>::iterator ti;
148   for (ti = change_position_.begin(); ti != change_position_.end(); ++ti) {
149     if ( *ti == position ) return idx;
150     if ( *ti > position ) break;
151     ++idx;
152   }
153 
154   change_position_.insert(ti, position);
155 
156   // Add Null at the right position in all parameter vectors
157   recombination_rates_.insert(recombination_rates_.begin() + idx, -1);
158   mutation_rates_.insert(mutation_rates_.begin() + idx, -1);
159 
160   return idx;
161 }
162 
163 
addSampleSizes(double time,const std::vector<size_t> & samples_sizes,const bool & scaled)164 void Model::addSampleSizes(double time, const std::vector<size_t> &samples_sizes, const bool &scaled) {
165   if (scaled) time *= 4 * default_pop_size();
166 
167   for (size_t pop = 0; pop < samples_sizes.size(); ++pop) {
168     for (size_t i = 0; i < samples_sizes.at(pop); ++i) {
169       sample_populations_.push_back(pop);
170       sample_times_.push_back(time);
171     }
172   }
173 }
174 
175 
176 /**
177  * @brief This changes the size of all populations to the given values at a
178  * specific point in time.
179  *
180  * The sizes apply for with point on backwards in time.
181  *
182  * @param time The time at which the population changes their sizes.
183  * @param pop_sizes A vector of new population sizes. Can either be given as
184  *    fraction of N0 or as an absolute value. See relative.
185  * @param time_scaled Set to true if the time is given in units of 4*N0
186  *    generations, or to false if the time is given in units of generations.
187  * @param relative set to TRUE, if the population sizes are given relative to
188  *    N0, or to FALSE if they are absolute values.
189  */
addPopulationSizes(double time,const std::vector<double> & pop_sizes,const bool & time_scaled,const bool & relative)190 void Model::addPopulationSizes(double time, const std::vector<double> &pop_sizes,
191                                const bool &time_scaled, const bool &relative) {
192 
193   if ( pop_sizes.size() != population_number() )
194     throw std::logic_error("Population size values do not meet the number of populations");
195 
196   size_t position = addChangeTime(time, time_scaled);
197 
198   pop_sizes_list_[position].clear();
199   for (double pop_size : pop_sizes) {
200     if (!std::isnan(pop_size)) {
201       // Scale to absolute values if necessary
202       if (relative) { pop_size *= this->default_pop_size(); }
203 
204       // Save inverse double value
205       if (pop_size <= 0.0) throw std::invalid_argument("population size <= 0");
206       pop_size = 1.0 / (2 * pop_size);
207     }
208     pop_sizes_list_[position].push_back(pop_size);
209   }
210 }
211 
212 
213 /**
214  * @brief This changes the size of all populations to a given value at a
215  * specific point in time.
216  *
217  * The sizes apply for with point on backwards in time.
218  *
219  * @param time The time at which the population changes their sizes.
220  * @param pop_sizes The size to which we set all populations. Can either be given as
221  *    fraction of N0 or as an absolute value. See relative.
222  * @param time_scaled Set to true if the time is given in units of 4*N0
223  *    generations, or to false if the time is given in units of generations.
224  * @param relative set to TRUE, if the population sizes are given relative to
225  *    N0, or to FALSE if they are absolute values.
226  */
addPopulationSizes(const double time,const double pop_size,const bool & time_scaled,const bool & relative)227 void Model::addPopulationSizes(const double time, const double pop_size,
228                                const bool &time_scaled, const bool &relative) {
229   addPopulationSizes(time, std::vector<double>(population_number(), pop_size), time_scaled, relative);
230 }
231 
232 
233 /**
234  * @brief This changes the size of a single populations to a given value at a
235  * specific point in time.
236  *
237  * The sizes apply for with point on backwards in time.
238  * Requires Model.finalization() to be called after the model is set up.
239  *
240  * @param time The time at which the population change its size.
241  * @param pop The population which will change its size.
242  * @param population_size The size to which we set the population. Can either be given as
243  *    fraction of N0 or as an absolute value. See relative.
244  * @param time_scaled Set to true if the time is given in units of 4*N0
245  *    generations, or to false if the time is given in units of generations.
246  * @param relative set to TRUE, if the population sizes are given relative to
247  *    N0, or to FALSE if they are absolute values.
248  */
addPopulationSize(const double time,const size_t pop,double population_size,const bool & time_scaled,const bool & relative)249 void Model::addPopulationSize(const double time, const size_t pop, double population_size,
250                               const bool &time_scaled, const bool &relative) {
251   checkPopulation(pop);
252   size_t position = addChangeTime(time, time_scaled);
253   if (relative) population_size *= default_pop_size();
254 
255   if (population_size <= 0.0) throw std::invalid_argument("population size <= 0");
256   if (pop_sizes_list_.at(position).empty()) addPopulationSizes(time, nan("value to replace"), time_scaled);
257   pop_sizes_list_.at(position).at(pop) = 1.0/(2*population_size);
258 }
259 
260 
261 /**
262  * @brief Set the population size growth rates at a certain time point.
263  *
264  * The population growth or shrinks exponentially from that time point on
265  * backwards in time.
266  * Requires Model.finalization() to be called after the model is set up.
267  *
268  * @param time The time at which to set the growth rates
269  * @param growth_rates A vector of growth rates for all populations
270  * @param time_scaled Set to true if the time is given in units of 4*N0
271  *    generations, or to false if the time is given in units of generations.
272  */
addGrowthRates(const double time,const std::vector<double> & growth_rates,const bool & time_scaled,const bool & rate_scaled)273 void Model::addGrowthRates(const double time, const std::vector<double> &growth_rates,
274                            const bool &time_scaled, const bool &rate_scaled) {
275   if ( growth_rates.size() != population_number() )
276     throw std::logic_error("Growth rates values do not meet the number of populations");
277   size_t position = addChangeTime(time, time_scaled);
278 
279   growth_rates_list_[position].clear();
280   for (double rate : growth_rates) {
281     if (rate_scaled) rate *= scaling_factor();
282     growth_rates_list_[position].push_back(rate);
283   }
284 }
285 
286 
287 /**
288  * @brief Set the population size growth rates at a certain time point.
289  *
290  * The population growth or shrinks exponentially from that time point on
291  * backwards in time.
292  * Requires Model.finalization() to be called after the model is set up.
293  *
294  * @param time The time at which to set the growth rates
295  * @param growth_rates The growth rate for all populations
296  * @param time_scaled Set to true if the time is given in units of 4*N0
297  *    generations, or to false if the time is given in units of generations.
298  */
addGrowthRates(const double time,const double growth_rate,const bool & time_scaled,const bool & rate_scaled)299 void Model::addGrowthRates(const double time, const double growth_rate,
300                            const bool &time_scaled, const bool &rate_scaled) {
301   addGrowthRates(time, std::vector<double>(population_number(), growth_rate), time_scaled, rate_scaled);
302 }
303 
304 
305 /**
306  * @brief Set the population size growth rates of a population at a certain time point.
307  *
308  * The population growth or shrinks exponentially from that time point on
309  * backwards in time.
310  * Requires Model.finalization() to be called after the model is set up.
311  *
312  * @param time The time at which to set the growth rates
313  * @param population The population to which the growth rate applies.
314  * @param growth_rates The growth rate for the populations
315  * @param time_scaled Set to true if the time is given in units of 4*N0
316  *    generations, or to false if the time is given in units of generations.
317  */
addGrowthRate(const double time,const size_t population,double growth_rate,const bool & time_scaled,const bool & rate_scaled)318 void Model::addGrowthRate(const double time, const size_t population,
319                           double growth_rate, const bool &time_scaled, const bool &rate_scaled) {
320   checkPopulation(population);
321   size_t position = addChangeTime(time, time_scaled);
322   if (rate_scaled) growth_rate *= scaling_factor();
323   if (growth_rates_list_.at(position).empty()) addGrowthRates(time, nan("number to replace"), time_scaled);
324   growth_rates_list_.at(position).at(population) = growth_rate;
325 }
326 
327 
328 /**
329  * @brief Sets a migration rate form a specific population to another starting from a
330  * certain time point (going backwards in time);
331  *
332  * This requires model finalization, e.g. call model.finalize() after you set up
333  * the model completely.
334  *
335  * @param time The time at which the migration is set to the given value.
336  *        It applies backwards in time until it is changed again.
337  * @param source The population from which the individuals migrate from when
338  *        looking backwards in time. Is the sink population when looking forward.
339  * @param sink The population to which the individuals migrate to (also
340  *        when looking backwards in time)
341  * @param mig_rate The backwards scaled migration rate M_ij = 4N0 * m_ij,
342  *        where m_ij is the fraction for population i = source that migrates
343  *        to population j = sink (again, when looking backwards in time).
344  * @param scaled_time Set to true if the time is given in units of 4*N0
345  *    generations, or to false if the time is given in units of generations.
346  * @param scaled_rate Set to true if the rate is given as M = 4*N0*m and to
347  *  false if it is given as m.
348  *
349  */
addMigrationRate(double time,size_t source,size_t sink,double mig_rate,const bool & scaled_time,const bool & scaled_rates)350 void Model::addMigrationRate(double time, size_t source, size_t sink, double mig_rate,
351                              const bool &scaled_time, const bool &scaled_rates) {
352   checkPopulation(source);
353   checkPopulation(sink);
354   size_t position = addChangeTime(time, scaled_time);
355   if (scaled_rates) mig_rate *= scaling_factor();
356   if (mig_rates_list_.at(position).empty()) {
357     addSymmetricMigration(time, nan("value to replace"), scaled_time);
358   }
359   mig_rates_list_.at(position).at(getMigMatrixIndex(source, sink)) = mig_rate;
360 }
361 
362 
363 /**
364  * @brief Sets the migration matrix to the given values for the time following at
365  * certain time point (backwards in time).
366  *
367  * This requires model finalization, e.g. call model.finalize() after you set up
368  * the model completely.
369  *
370  * @param time The time at which the migration is set to the given values.
371  *        The values apply backwards in time until they are changed again.
372  * @param mig_rates The (backwards) scaled migration matrix, given as concatenation of
373  *        row vectors (M_00, M_01, ..., M_0n, M_10, ..., M_n1, ..., M_nn), where
374  *        M_ij = 4N0 * m_ij and m_ij is the faction of population i that
375  *        migrates to population j (viewed backwards in time; forwards the
376  *        migration is from population j to i). The diagonal elements of the
377  *        matrix are ignored and can be set to "x" for better readability.
378  * @param scaled_time Set to true if the time is given in units of 4*N0
379  *    generations, or to false if the time is given in units of generations.
380  * @param scaled_rate Set to true if the rate is given as M = 4*N0*m and to
381  *  false if it is given as m.
382  */
addMigrationRates(double time,const std::vector<double> & mig_rates,const bool & scaled_time,const bool & scaled_rates)383 void Model::addMigrationRates(double time, const std::vector<double> &mig_rates,
384                               const bool &scaled_time, const bool &scaled_rates) {
385   double popnr = population_number();
386   double scaling = 1;
387   if (scaled_rates) scaling = scaling_factor();
388   if ( mig_rates.size() != population_number()*population_number() )
389     throw std::logic_error("Migration rates values do not meet the number of populations");
390 
391   size_t position = addChangeTime(time, scaled_time);
392   mig_rates_list_[position].clear();
393   mig_rates_list_[position].reserve(popnr*popnr-popnr);
394   for (size_t i = 0; i < popnr; ++i) {
395     for (size_t j = 0; j < popnr; ++j) {
396       if (i == j) continue;
397       mig_rates_list_[position].push_back(mig_rates.at(i*popnr+j) * scaling);
398     }
399   }
400 }
401 
402 
403 
404 /**
405  * @brief Adds symmetric migration to a model.
406  *
407  * Sets migration between all population to the given value starting at a
408  * certain time point going backwards in time. Unlike 'ms', this uses the actual
409  * value provided and does not divide it by #population-1.
410  *
411  * This requires model finalization, e.g. call model.finalize() after you set up
412  * the model completely.
413  *
414  * @param time The time at which the migration is set to the given value.
415  *        It applies backwards in time until it is changed again.
416  * @param mig_rate The scaled migration rate M_ij = 4N0 * m_ij that is used
417  *        between all populations i and j. m_ij is the fraction of population i
418  *        that migrates to population j.
419  * @param time_scaled Set to true if the time is given in units of 4*N0
420  *    generations, or to false if the time is given in units of generations.
421  * @param rate_scaled Set to true if the rate is given as M = 4*N0*m and to
422  *  false if it is given as m.
423  */
addSymmetricMigration(const double time,const double mig_rate,const bool & time_scaled,const bool & rate_scaled)424 void Model::addSymmetricMigration(const double time, const double mig_rate,
425                                   const bool &time_scaled, const bool &rate_scaled) {
426     std::vector<double> mig_rates = std::vector<double>(population_number()*population_number(), mig_rate);
427     this->addMigrationRates(time, mig_rates, time_scaled, rate_scaled);
428   }
429 
430 
addSingleMigrationEvent(const double time,const size_t source_pop,const size_t sink_pop,const double fraction,const bool & time_scaled)431 void Model::addSingleMigrationEvent(const double time, const size_t source_pop,
432                                     const size_t sink_pop, const double fraction,
433                                     const bool &time_scaled) {
434 
435   size_t position = addChangeTime(time, time_scaled);
436 
437   if ( time < 0.0 ) throw std::invalid_argument("Single migration event: Negative time");
438   if ( source_pop >= population_number() ) throw std::invalid_argument("Single migration event: Unknown population");
439   if ( sink_pop >= population_number() ) throw std::invalid_argument("Single migration event: Unknown population");
440   if ( fraction < 0.0 || fraction > 1.0 ) throw std::invalid_argument("Single migration event: Fraction out of range");
441 
442   if ( single_mig_list_.at(position).empty() ) {
443     single_mig_list_.at(position) = std::vector<MigEvent>(0);
444   }
445 
446   MigEvent migEvent = {source_pop, sink_pop, fraction};
447   single_mig_list_.at(position).push_back(migEvent);
448 
449   this->has_migration_ = true;
450 }
451 
452 
operator <<(std::ostream & os,Model & model)453 std::ostream& operator<<(std::ostream& os, Model& model) {
454   size_t n_pops = model.population_number();
455   os << "---- Model: ------------------------" << std::endl;
456   os << "Total Sample Size: " << model.sample_size() << std::endl;
457   os << "N0 is assumed to be " << model.default_pop_size() << std::endl;
458 
459   model.resetSequencePosition();
460   for (size_t idx = 0; idx < model.countChangePositions(); ++idx) {
461     os << std::endl << "At Position " << model.getCurrentSequencePosition() << ":" << std::endl;
462     os << " Mutation Rate: " << model.mutation_rate() << std::endl;
463     os << " Recombination Rate: " << model.recombination_rate() << std::endl;
464     model.increaseSequencePosition();
465   }
466   model.resetSequencePosition();
467 
468   model.resetTime();
469   for (size_t idx = 0; idx < model.countChangeTimes(); ++idx) {
470     os << std::endl << "At Time " << model.getCurrentTime() << ":" << std::endl;
471 
472     os << " Population Sizes: ";
473     for (size_t pop = 0; pop < n_pops; ++pop)
474       os << std::setw(10) << std::right << model.population_size(pop, model.getCurrentTime());
475     os << std::endl;
476 
477     os << " Growth Rates:     ";
478     for (size_t pop = 0; pop < n_pops; ++pop)
479       os << std::setw(10) << std::right << model.growth_rate(pop);
480     os << std::endl;
481 
482     os << " Migration Matrix: " << std::endl;
483     for (size_t i = 0; i < n_pops; ++i) {
484       for (size_t j = 0; j < n_pops; ++j) {
485         os << std::setw(10) << std::right << model.migration_rate(i, j);
486       }
487       os << std::endl;
488     }
489 
490     for (MigEvent me : model.single_mig_events()) {
491       os << " "
492          << me.prob * 100 << "% of pop "
493          << me.source_pop + 1 << " move to pop "
494          << me.sink_pop + 1 << std::endl;
495     }
496 
497     if (idx < model.countChangeTimes() - 1) model.increaseTime();
498   }
499   model.resetTime();
500   os << "------------------------------------" << std::endl;
501   return(os);
502 }
503 
504 
updateTotalMigRates(const size_t position)505 void Model::updateTotalMigRates(const size_t position) {
506   if ( total_mig_rates_list_.at(position).empty() ) {
507     total_mig_rates_list_.at(position) = std::vector<double>(population_number(), 0.0);
508   }
509 
510   std::vector<double>* mig_rates = &(total_mig_rates_list_.at(position));
511 
512   for (size_t i = 0; i < population_number(); ++i) {
513     for (size_t j = 0; j < population_number(); ++j) {
514       if (i == j) continue;
515       mig_rates->at(i) += mig_rates_list_.at(position).at( getMigMatrixIndex(i,j) );
516     }
517     if (mig_rates->at(i) > 0) has_migration_ = true;
518   }
519 }
520 
521 
finalize()522 void Model::finalize() {
523   fillVectorList(mig_rates_list_, default_mig_rate);
524   fillVectorList(growth_rates_list_, default_growth_rate);
525   calcPopSizes();
526 
527   for (size_t j = 0; j < mig_rates_list_.size(); ++j) {
528     if (mig_rates_list_.at(j).empty()) continue;
529     updateTotalMigRates(j);
530   }
531 
532   // Fill in missing recombination rates
533   assert( mutation_rates_.at(0) != -1 );
534   assert( recombination_rates_.at(0) != -1 );
535   for (size_t j = 1; j < change_position_.size(); ++j) {
536     if (mutation_rates_.at(j) == -1) {
537       mutation_rates_.at(j) = mutation_rates_.at(j-1);
538     }
539 
540     if (recombination_rates_.at(j) == -1) {
541       recombination_rates_.at(j) = recombination_rates_.at(j-1);
542     }
543   }
544 
545   resetTime();
546   resetSequencePosition();
547   check();
548 }
549 
550 
calcPopSizes()551 void Model::calcPopSizes() {
552   // Set initial population sizes
553   if (pop_sizes_list_.at(0).empty()) addPopulationSizes(0, default_pop_size());
554   else {
555     // Replace values not set by the user with the default size
556     for (size_t pop = 0; pop < population_number(); ++pop) {
557       if (std::isnan(pop_sizes_list_.at(0).at(pop)))
558         addPopulationSize(0, pop, default_pop_size());
559     }
560   }
561 
562   size_t last_growth = -1;
563   double duration = -1;
564   for (size_t i = 1; i < change_times_.size(); ++i) {
565     if (! growth_rates_list_.at(i - 1).empty()) last_growth = i - 1;
566 
567     // Make sure we always have a pop sizes vector
568     if (pop_sizes_list_.at(i).empty()) {
569       addPopulationSizes(change_times_.at(i), nan("value to replace"));
570       assert( ! pop_sizes_list_.at(i).empty() );
571     }
572 
573     // Calculate the effective duration of a growth period if it ends here
574     duration = change_times_.at(i) - change_times_.at(i - 1);
575 
576     // Calculate the population sizes:
577     for (size_t pop = 0; pop < population_number(); ++pop) {
578       // If the user explicitly gave a value => always use this value
579       if ( !std::isnan(pop_sizes_list_.at(i).at(pop)) ) continue;
580 
581       assert(!std::isnan(pop_sizes_list_.at(i - 1).at(pop)));
582       // Otherwise use last value
583       pop_sizes_list_.at(i).at(pop) = pop_sizes_list_.at(i - 1).at(pop);
584 
585       // ... and scale it if there was growth
586       if (last_growth != -1) {
587         pop_sizes_list_.at(i).at(pop) *=
588           std::exp((growth_rates_list_.at(last_growth).at(pop)) * duration);
589       }
590     }
591   }
592 }
593 
594 
check()595 void Model::check() {
596   // Sufficient sample size?
597   if (sample_size() < 2) throw std::invalid_argument("Sample size needs be to at least 2");
598 
599   // Structure without migration?
600   if (population_number() > 1 && !has_migration())
601     throw std::invalid_argument("Model has multiple populations but no migration. Coalescence impossible");
602 }
603 
604 
fillVectorList(std::vector<std::vector<double>> & vector_list,const double default_value)605 void Model::fillVectorList(std::vector<std::vector<double> > &vector_list, const double default_value) {
606   std::vector<double>* last = NULL;
607   std::vector<double>* current = NULL;
608   for (size_t j = 0; j < vector_list.size(); ++j) {
609     current = &(vector_list.at(j));
610     if (current->empty()) continue;
611 
612     for (size_t i = 0; i < current->size(); ++i) {
613       if ( !std::isnan(current->at(i)) ) continue;
614 
615       if (last == NULL) current->at(i) = default_value;
616       else current->at(i) = last->at(i);
617     }
618     last = current;
619   }
620 }
621 
622 
addPopulation()623 void Model::addPopulation() {
624   // Create the new population
625   size_t new_pop = population_number();
626   this->set_population_number(new_pop+1);
627 
628   // Change Vectors
629   addPopToVectorList(growth_rates_list_);
630   addPopToVectorList(pop_sizes_list_);
631 
632   // Change Matrices
633   addPopToMatrixList(mig_rates_list_, new_pop);
634 }
635 
636 
addPopToMatrixList(std::vector<std::vector<double>> & vector_list,size_t new_pop,double default_value)637 void Model::addPopToMatrixList(std::vector<std::vector<double> > &vector_list, size_t new_pop, double default_value) {
638   for (auto it = vector_list.begin(); it!= vector_list.end(); ++it) {
639     if (it->empty()) continue;
640     for (size_t i = 0; i < new_pop; ++i) {
641       it->insert(it->begin() + getMigMatrixIndex(i, new_pop), default_value);
642     }
643     for (size_t i = 0; i < new_pop; ++i) {
644       it->insert(it->begin() + getMigMatrixIndex(new_pop, i), default_value);
645     }
646   }
647 }
648 
649 
addPopToVectorList(std::vector<std::vector<double>> & vector_list)650 void Model::addPopToVectorList(std::vector<std::vector<double> > &vector_list) {
651   for (auto it = vector_list.begin(); it!= vector_list.end(); ++it) {
652     if (it->empty()) continue;
653     it->push_back(nan("value to replace"));
654   }
655 }
656 
657 
658 /**
659  * @brief Sets the recombination rate
660  *
661  * @param rate The recombination rate per sequence length per time unit.
662  * The sequence length can be either per locus or per base pair and the time
663  * can be given in units of 4N0 generations ("scaled") or per generation.
664  *
665  * @param loci_length The length of every loci.
666  * @param per_locus Set to TRUE, if the rate is given per_locus, and to FALSE
667  * if the rate is per base pair.
668  * @param scaled Set to TRUE is the rate is scaled with 4N0, or to FALSE if
669  * it isn't
670  */
setRecombinationRate(double rate,const bool & per_locus,const bool & scaled,const double seq_position)671 void Model::setRecombinationRate(double rate,
672                                  const bool &per_locus,
673                                  const bool &scaled,
674                                  const double seq_position) {
675 
676   if (rate < 0.0) {
677     throw std::invalid_argument("Recombination rate must be non-negative");
678   }
679 
680   if (scaled) rate /= 4.0 * default_pop_size();
681   if (per_locus) {
682     if (loci_length() <= 1) {
683       throw std::invalid_argument("Locus length must be at least two");
684     }
685     rate /= loci_length()-1;
686   }
687 
688   if (rate > 0.0) has_recombination_ = true;
689   recombination_rates_[addChangePosition(seq_position)] = rate;
690 }
691 
692 
693 /**
694  * @brief Sets the mutation rate
695  *
696  * @param rate The mutation rate per locus, either scaled as theta=4N0*u or
697  * unscaled as u.
698  * @param per_locus TRUE if the rate is per locus, FALSE if per base.
699  * @param scaled Set this to TRUE if you give the mutation rate in scaled
700  * units (e.g. as theta rather than as u).
701  */
setMutationRate(double rate,const bool & per_locus,const bool & scaled,const double seq_position)702 void Model::setMutationRate(double rate, const bool &per_locus, const bool &scaled,
703                             const double seq_position) {
704   if (scaled) rate /= 4.0 * default_pop_size();
705 
706   size_t idx = addChangePosition(seq_position);
707   if (per_locus) {
708     mutation_rates_.at(idx) = rate / loci_length();
709   } else {
710     mutation_rates_.at(idx) = rate;
711   }
712 }
713 
714