1 /*
2  *  cPopulation.cc
3  *  Avida
4  *
5  *  Called "population.cc" prior to 12/5/05.
6  *  Copyright 1999-2011 Michigan State University. All rights reserved.
7  *  Copyright 1993-2003 California Institute of Technology.
8  *
9  *
10  *  This file is part of Avida.
11  *
12  *  Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
13  *  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
14  *
15  *  Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public License along with Avida.
19  *  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include "cPopulation.h"
24 
25 #include "avida/core/Sequence.h"
26 
27 #include "AvidaTools.h"
28 
29 #include "cAvidaContext.h"
30 #include "cBioGroup.h"
31 #include "cBioGroupManager.h"
32 #include "cClassificationManager.h"
33 #include "cCPUTestInfo.h"
34 #include "cCodeLabel.h"
35 #include "cConstBurstSchedule.h"
36 #include "cConstSchedule.h"
37 #include "cDataFile.h"
38 #include "cDemePlaceholderUnit.h"
39 #include "cDemeProbSchedule.h"
40 #include "cEnvironment.h"
41 #include "cGenomeTestMetrics.h"
42 #include "cBGGenotype.h"
43 #include "cHardwareBase.h"
44 #include "cHardwareManager.h"
45 #include "cInitFile.h"
46 #include "cInstSet.h"
47 #include "cIntegratedSchedule.h"
48 #include "cMigrationMatrix.h"   // MIGRATION_MATRIX
49 #include "cOrganism.h"
50 #include "cParasite.h"
51 #include "cPhenotype.h"
52 #include "cPopulationCell.h"
53 #include "cProbSchedule.h"
54 #include "cProbDemeProbSchedule.h"
55 #include "cRandom.h"
56 #include "cResource.h"
57 #include "cResourceCount.h"
58 #include "cSaleItem.h"
59 #include "cStats.h"
60 #include "cTestCPU.h"
61 #include "cTopology.h"
62 #include "cWorld.h"
63 #include "tArrayUtils.h"
64 #include "tAutoRelease.h"
65 #include "tIterator.h"
66 #include "tKVPair.h"
67 #include "tHashMap.h"
68 #include "tManagedPointerArray.h"
69 
70 #include "cHardwareCPU.h"
71 
72 #include <fstream>
73 #include <vector>
74 #include <algorithm>
75 #include <numeric>
76 #include <set>
77 #include <cfloat>
78 #include <cmath>
79 #include <climits>
80 #include <limits>
81 
82 using namespace std;
83 using namespace AvidaTools;
84 
85 
cPopulation(cWorld * world)86 cPopulation::cPopulation(cWorld* world)
87 : m_world(world)
88 , schedule(NULL)
89 //, resource_count(world->GetEnvironment().GetResourceLib().GetSize())
90 , birth_chamber(world)
91 , print_mini_trace_genomes(false)
92 , use_micro_traces(false)
93 , m_next_prey_q(0)
94 , m_next_pred_q(0)
95 , environment(world->GetEnvironment())
96 , num_organisms(0)
97 , num_prey_organisms(0)
98 , num_pred_organisms(0)
99 , pop_enforce(0)
100 , m_has_predatory_res(false)
101 , sync_events(false)
102 , m_hgt_resid(-1)
103 {
104   // Avida specific information.
105   world_x = world->GetConfig().WORLD_X.Get();
106   world_y = world->GetConfig().WORLD_Y.Get();
107   world_z = world->GetConfig().WORLD_Z.Get();
108 
109   int num_demes = m_world->GetConfig().NUM_DEMES.Get();
110   const int num_cells = world_x * world_y * world_z;
111   const int geometry = world->GetConfig().WORLD_GEOMETRY.Get();
112 
113   if (m_world->GetConfig().ENERGY_CAP.Get() == -1) {
114     m_world->GetConfig().ENERGY_CAP.Set(std::numeric_limits<double>::max());
115   }
116 
117   if (m_world->GetConfig().LOG_SLEEP_TIMES.Get() == 1)  {
118     sleep_log = new tVector<pair<int,int> >[world_x*world_y];
119   }
120   // Print out world details
121   if (world->GetVerbosity() > VERBOSE_NORMAL) {
122     cout << "Building world " << world_x << "x" << world_y << "x" << world_z << " = " << num_cells << " organisms." << endl;
123     switch(geometry) {
124       case nGeometry::GRID: { cout << "Geometry: Bounded grid" << endl; break; }
125       case nGeometry::TORUS: { cout << "Geometry: Torus" << endl; break; }
126       case nGeometry::CLIQUE: { cout << "Geometry: Clique" << endl; break; }
127       case nGeometry::HEX: { cout << "Geometry: Hex" << endl; break; }
128       case nGeometry::LATTICE: { cout << "Geometry: Lattice" << endl; break; }
129       case nGeometry::PARTIAL: { cout << "Geometry: Partial" << endl; break; }
130 			case nGeometry::RANDOM_CONNECTED: { cout << "Geometry: Random connected" << endl; break; }
131       case nGeometry::SCALE_FREE: { cout << "Geometry: Scale-free" << endl; break; }
132 
133       default:
134         cout << "Unknown geometry!" << endl;
135         assert(false);
136     }
137   }
138 
139   // Invalid settings should be changed to one deme
140   if (num_demes <= 0) {
141     num_demes = 1; // One population == one deme.
142   }
143 
144   // Not ready for prime time yet; need to look at how resources work in this now
145   // more complex world.
146   assert(world_z == 1);
147 
148   // The following combination of options creates an infinite rotate-loop:
149   assert(!((m_world->GetConfig().DEMES_ORGANISM_PLACEMENT.Get()==0)
150            && (m_world->GetConfig().DEMES_ORGANISM_FACING.Get()==1)
151            && (m_world->GetConfig().WORLD_GEOMETRY.Get()==1)));
152 
153   // Incompatible deme replication strategies:
154   assert(!(m_world->GetConfig().DEMES_REPLICATE_SIZE.Get()
155            && (m_world->GetConfig().DEMES_PROB_ORG_TRANSFER.Get()>0.0)));
156   assert(!(m_world->GetConfig().DEMES_USE_GERMLINE.Get()
157            && (m_world->GetConfig().DEMES_PROB_ORG_TRANSFER.Get()>0.0)));
158   assert(!(m_world->GetConfig().DEMES_USE_GERMLINE.Get()
159            && (m_world->GetConfig().MIGRATION_RATE.Get()>0.0)));
160 
161 #ifdef DEBUG
162   const int birth_method = m_world->GetConfig().BIRTH_METHOD.Get();
163 
164   if (num_demes > 1) {
165     assert(birth_method != POSITION_OFFSPRING_FULL_SOUP_ELDEST);
166   }
167 #endif
168 
169   // Allocate the cells, resources, and market.
170   cell_array.ResizeClear(num_cells);
171   empty_cell_id_array.ResizeClear(cell_array.GetSize());
172   for (int i = 0; i < empty_cell_id_array.GetSize(); i++) {
173     empty_cell_id_array[i] = i;
174   }
175   market.Resize(MARKET_SIZE);
176 
177   // Setup the cells.  Do things that are not dependent upon topology here.
178   for(int i=0; i<num_cells; ++i) {
179     cell_array[i].Setup(world, i, environment.GetMutRates(), i%world_x, i/world_x);
180     // Setup the reaper queue.
181     if (world->GetConfig().BIRTH_METHOD.Get() == POSITION_OFFSPRING_FULL_SOUP_ELDEST) {
182       reaper_queue.Push(&(cell_array[i]));
183     }
184   }
185 
186   // What are the sizes of the demes that we're creating?
187   const int deme_size_x = world_x;
188   const int deme_size_y = world_y / num_demes;
189   const int deme_size = deme_size_x * deme_size_y;
190   deme_array.Resize(num_demes);
191 
192   // Broken setting:
193   assert(m_world->GetConfig().DEMES_REPLICATE_SIZE.Get() <= deme_size);
194 
195   // Setup the deme structures.
196   tArray<int> deme_cells(deme_size);
197   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
198     for (int offset = 0; offset < deme_size; offset++) {
199       int cell_id = deme_id * deme_size + offset;
200       deme_cells[offset] = cell_id;
201       cell_array[cell_id].SetDemeID(deme_id);
202     }
203     deme_array[deme_id].Setup(deme_id, deme_cells, deme_size_x, m_world);
204   }
205 
206   // Setup the topology.
207   // What we're doing here is chopping the cell_array up into num_demes pieces.
208   // Note that having 0 demes (one population) is the same as having 1 deme.  Then
209   // we send the cells that comprise each deme into the topology builder.
210   for(int i=0; i<num_cells; i+=deme_size) {
211     // We're cheating here; we're using the random access nature of an iterator
212     // to index beyond the end of the cell_array.
213     switch(geometry) {
214       case nGeometry::GRID:
215         build_grid(&cell_array.begin()[i],
216                    &cell_array.begin()[i+deme_size],
217                    deme_size_x, deme_size_y);
218         break;
219       case nGeometry::TORUS:
220         build_torus(&cell_array.begin()[i],
221                     &cell_array.begin()[i+deme_size],
222                     deme_size_x, deme_size_y);
223         break;
224       case nGeometry::CLIQUE:
225         build_clique(&cell_array.begin()[i],
226                      &cell_array.begin()[i+deme_size],
227                      deme_size_x, deme_size_y);
228         break;
229       case nGeometry::HEX:
230         build_hex(&cell_array.begin()[i],
231                   &cell_array.begin()[i+deme_size],
232                   deme_size_x, deme_size_y);
233         break;
234       case nGeometry::LATTICE:
235         build_lattice(&cell_array.begin()[i],
236                       &cell_array.begin()[i+deme_size],
237                       deme_size_x, deme_size_y, world_z);
238         break;
239       case nGeometry::RANDOM_CONNECTED:
240         build_random_connected_network(&cell_array.begin()[i],
241                                        &cell_array.begin()[i+deme_size],
242                                        deme_size_x, deme_size_y, m_world->GetRandom());
243         break;
244       case nGeometry::SCALE_FREE:
245         build_scale_free(&cell_array.begin()[i], &cell_array.begin()[i+deme_size],
246                          world->GetConfig().SCALE_FREE_M.Get(),
247                          world->GetConfig().SCALE_FREE_ALPHA.Get(),
248                          world->GetConfig().SCALE_FREE_ZERO_APPEAL.Get(),
249                          m_world->GetRandom());
250         break;
251       default:
252         assert(false);
253     }
254   }
255 
256   BuildTimeSlicer();
257 
258   // Setup the resources...
259   const cResourceLib & resource_lib = environment.GetResourceLib();
260   int global_res_index = -1;
261   int deme_res_index = -1;
262   int num_deme_res = 0;
263 
264   //setting size of global and deme-level resources
265   for(int i = 0; i < resource_lib.GetSize(); i++) {
266     cResource * res = resource_lib.GetResource(i);
267     if (res->GetDemeResource())
268       num_deme_res++;
269   }
270 
271   cResourceCount tmp_res_count(resource_lib.GetSize() - num_deme_res);
272   resource_count = tmp_res_count;
273   resource_count.ResizeSpatialGrids(world_x, world_y);
274 
275   for(int i = 0; i < GetNumDemes(); i++) {
276     cResourceCount tmp_deme_res_count(num_deme_res);
277     GetDeme(i).SetDemeResourceCount(tmp_deme_res_count);
278     GetDeme(i).ResizeSpatialGrids(deme_size_x, deme_size_y);
279   }
280 
281   for (int i = 0; i < resource_lib.GetSize(); i++) {
282     cResource * res = resource_lib.GetResource(i);
283 
284     // check to see if this is the hgt resource:
285     if (res->GetHGTMetabolize()) {
286       if (m_hgt_resid != -1) {
287         m_world->GetDriver().RaiseFatalException(-1, "Only one HGT resource is currently supported.");
288       }
289       m_hgt_resid = i;
290     }
291 
292     if (!res->GetDemeResource()) {
293       global_res_index++;
294       const double decay = 1.0 - res->GetOutflow();
295       resource_count.Setup(world, global_res_index, res->GetName(), res->GetInitial(),
296                            res->GetInflow(), decay,
297                            res->GetGeometry(), res->GetXDiffuse(),
298                            res->GetXGravity(), res->GetYDiffuse(),
299                            res->GetYGravity(), res->GetInflowX1(),
300                            res->GetInflowX2(), res->GetInflowY1(),
301                            res->GetInflowY2(), res->GetOutflowX1(),
302                            res->GetOutflowX2(), res->GetOutflowY1(),
303                            res->GetOutflowY2(), res->GetCellListPtr(),
304                            res->GetCellIdListPtr(), world->GetVerbosity(),
305                            res->GetDynamicResource(), res->GetPeaks(),
306                            res->GetMinHeight(), res->GetMinRadius(), res->GetRadiusRange(),
307                            res->GetAh(), res->GetAr(),
308                            res->GetAcx(), res->GetAcy(),
309                            res->GetHStepscale(), res->GetRStepscale(),
310                            res->GetCStepscaleX(), res->GetCStepscaleY(),
311                            res->GetHStep(), res->GetRStep(),
312                            res->GetCStepX(), res->GetCStepY(),
313                            res->GetUpdateDynamic(), res->GetPeakX(), res->GetPeakY(),
314                            res->GetHeight(), res->GetSpread(), res->GetPlateau(), res->GetDecay(),
315                            res->GetMaxX(), res->GetMinX(), res->GetMaxY(), res->GetMinY(), res->GetAscaler(),res->GetUpdateStep(),
316                            res->GetHalo(), res->GetHaloInnerRadius(), res->GetHaloWidth(),
317                            res->GetHaloAnchorX(), res->GetHaloAnchorY(), res->GetMoveSpeed(),
318                            res->GetPlateauInflow(), res->GetPlateauOutflow(), res->GetConeInflow(), res->GetConeOutflow(),
319                            res->GetGradientInflow(), res->GetIsPlateauCommon(), res->GetFloor(), res->GetHabitat(),
320                            res->GetMinSize(), res->GetMaxSize(), res->GetConfig(), res->GetCount(), res->GetResistance(),
321                            res->GetInitialPlatVal(), res->GetThreshold(), res->GetRefuge(), res->GetGradient()
322                            );
323       m_world->GetStats().SetResourceName(global_res_index, res->GetName());
324     } else if (res->GetDemeResource()) {
325       deme_res_index++;
326       for(int j = 0; j < GetNumDemes(); j++) {
327         GetDeme(j).SetupDemeRes(deme_res_index, res, world->GetVerbosity(), world);
328         // could add deme resources to global resource stats here
329       }
330     } else {
331       cerr<< "ERROR: Resource \"" << res->GetName() <<"\"is not a global or deme resource.  Exit";
332       exit(1);
333     }
334   }
335 
336   // if HGT is on, make sure there's a resource for it:
337   if (m_world->GetConfig().ENABLE_HGT.Get() && (m_hgt_resid == -1)) {
338     m_world->GetDriver().NotifyWarning("HGT is enabled, but no HGT resource is defined; add hgt=1 to a single resource in the environment file.");
339   }
340   min_prey_failures.Resize(0);
341 }
342 
InitiatePop(cUserFeedback * feedback)343 bool cPopulation::InitiatePop(cUserFeedback* feedback)
344 {
345   Genome start_org;
346   const cString& filename = m_world->GetConfig().START_ORGANISM.Get();
347 
348   if (filename != "-" && filename != "") {
349     if (!start_org.LoadFromDetailFile(filename, m_world->GetWorkingDir(), m_world->GetHardwareManager(), *feedback)) return false;
350     if (start_org.GetSize() != 0) {
351       Inject(start_org, SRC_ORGANISM_FILE_LOAD, m_world->GetDefaultContext());
352     } else {
353       if (feedback) feedback->Warning("zero length start organism, not injecting into initial population");
354     }
355   } else {
356     if (feedback) feedback->Warning("no start organism specified");
357   }
358 
359   return true;
360 }
361 
362 
~cPopulation()363 cPopulation::~cPopulation()
364 {
365   for (int i = 0; i < cell_array.GetSize(); i++) KillOrganism(cell_array[i], m_world->GetDefaultContext());
366   delete schedule;
367 }
368 
369 
AdjustSchedule(const cPopulationCell & cell,const cMerit & merit)370 inline void cPopulation::AdjustSchedule(const cPopulationCell& cell, const cMerit& merit)
371 {
372   const int deme_id = cell.GetDemeID();
373   const cDeme& deme = deme_array[deme_id];
374   schedule->Adjust(cell.GetID(), deme.HasDemeMerit() ? (merit * deme.GetDemeMerit()) : merit, cell.GetDemeID());
375 }
376 
377 
378 
379 // Activate the child, given information from the parent.
380 // Return true if parent lives through this process.
ActivateOffspring(cAvidaContext & ctx,const Genome & offspring_genome,cOrganism * parent_organism)381 bool cPopulation::ActivateOffspring(cAvidaContext& ctx, const Genome& offspring_genome, cOrganism* parent_organism)
382 {
383   if (m_world->GetConfig().FASTFORWARD_NUM_ORGS.Get() > 0 && GetNumOrganisms() >= m_world->GetConfig().FASTFORWARD_NUM_ORGS.Get())
384   {
385     return true;
386   }
387   assert(parent_organism != NULL);
388   bool is_doomed = false;
389   int doomed_cell = (m_world->GetConfig().WORLD_X.Get() * m_world->GetConfig().WORLD_Y.Get()) - 1; //Also at the end of cPopulation::ActivateOrganism
390   tArray<cOrganism*> offspring_array;
391   tArray<cMerit> merit_array;
392 
393   // If divide method is split, parent will be reset to completely tolerant
394   // must remove their intolerance from the group's cached total.
395   if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) {
396     if (m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
397       int tol_max = m_world->GetConfig().MAX_TOLERANCE.Get();
398       int group_id = parent_organism->GetOpinion().first;
399       int org_imm_tolerance = parent_organism->GetPhenotype().CalcToleranceImmigrants();
400       m_group_intolerances[group_id][0].second -= tol_max - org_imm_tolerance;
401       if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
402         if (parent_organism->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) {
403           m_group_intolerances_females[group_id][0].second -= tol_max - org_imm_tolerance;
404         } else if (parent_organism->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) {
405           m_group_intolerances_males[group_id][0].second -= tol_max - org_imm_tolerance;
406         } else if (parent_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) {
407           m_group_intolerances_juvs[group_id][0].second -= tol_max - org_imm_tolerance;
408         }
409       }
410       m_group_intolerances[group_id][1].second -= tol_max - parent_organism->GetPhenotype().CalcToleranceOffspringOthers();
411     }
412   }
413 
414   // Update the parent's phenotype.
415   // This needs to be done before the parent goes into the birth chamber
416   // or the merit doesn't get passed onto the offspring correctly
417   cPhenotype& parent_phenotype = parent_organism->GetPhenotype();
418   UpdateQs(parent_organism, true);
419   parent_phenotype.DivideReset(parent_organism->GetGenome().GetSequence());
420 
421   birth_chamber.SubmitOffspring(ctx, offspring_genome, parent_organism, offspring_array, merit_array);
422 
423   // First, setup the genotype of all of the offspring.
424   const int parent_id = parent_organism->GetOrgInterface().GetCellID();
425   assert(parent_id >= 0 && parent_id < cell_array.GetSize());
426   cPopulationCell& parent_cell = cell_array[parent_id];
427 
428   // If this is multi-process Avida, test to see if we should send the offspring
429   // to a different world.  We check this here so that 1) we avoid all the extra
430   // work below in the case of a migration event and 2) so that we don't mess up
431   // and mistakenly kill the parent.
432   if (m_world->GetConfig().ENABLE_MP.Get()) {
433     tArray<cOrganism*> non_migrants;
434     tArray<cMerit> non_migrant_merits;
435     for (int i=0; i<offspring_array.GetSize(); ++i) {
436       if (m_world->TestForMigration()) {
437         // this offspring is outta here!
438         m_world->MigrateOrganism(offspring_array[i], parent_cell, merit_array[i], parent_organism->GetLineageLabel());
439         delete offspring_array[i]; // this offspring isn't hanging around.
440       } else {
441         // boring; stay here.
442         non_migrants.Push(offspring_array[i]);
443         non_migrant_merits.Push(merit_array[i]);
444       }
445     }
446     offspring_array = non_migrants;
447     merit_array = non_migrant_merits;
448   }
449 
450   tArray<int> target_cells(offspring_array.GetSize());
451 
452   // Loop through choosing the later placement of each offspring in the population.
453   bool parent_alive = true;  // Will the parent live through this process?
454 
455   for (int i = 0; i < offspring_array.GetSize(); i++) {
456     /*
457      THIS code will remove zero merit orgnaisms, thus never putting them into the scheduler.
458      WARNING: uncommenting this code will break consistancy, but will generalize the solution.
459      Currently, only asexual organisms that use the energy model are removed when they have zero merit.
460      If this code gets added then remove the "if (merit_array[0].GetDouble() <= 0.0)" block from cBirthChamber::DoAsexBirth,
461      does not break consistancy for test energy_deme_level_res
462 
463      if (merit_array[i].GetDouble() <= 0.0) {
464      // no weaklings!
465      if (offspring_array.GetSize() > 1) {
466      offspring_array.Swap(i, offspring_array.GetSize()-1);
467      offspring_array = offspring_array.Subset(0, offspring_array.GetSize()-2);
468      } else {
469      offspring_array.ResizeClear(0);
470      break;
471      }
472      --i;
473      continue;
474      }
475      */
476     target_cells[i] = PositionOffspring(parent_cell, ctx, m_world->GetConfig().ALLOW_PARENT.Get()).GetID();
477     // Catch the corner case where birth method = 3 and there are
478     // no empty cells. Here, we set the cell to -1 so that the rest of the
479     // method can proceed, but we can avoid trying to rotate it.
480     if ((target_cells[i] == parent_cell.GetID()) &&
481         m_world->GetConfig().ALLOW_PARENT.Get()==0) {
482       target_cells[i] = -1;
483       continue;
484     }
485     // If we replaced the parent, make a note of this.
486     if (target_cells[i] == parent_cell.GetID()) {
487       parent_alive = false;
488       if (m_world->GetConfig().USE_AVATARS.Get()) parent_organism->GetOrgInterface().RemoveAllAV();
489     }
490     const int mut_source = m_world->GetConfig().MUT_RATE_SOURCE.Get();
491     if (mut_source == 1) {
492       // Update the mutation rates of each offspring from the environment....
493       offspring_array[i]->MutationRates().Copy(GetCell(target_cells[i]).MutationRates());
494     }
495     else {
496       // Update the mutation rates of each offspring from its parent.
497       offspring_array[i]->MutationRates().Copy(parent_organism->MutationRates());
498       // If there is a meta-mutation rate, do tests for it.
499       if (offspring_array[i]->MutationRates().GetMetaCopyMutProb() > 0.0) {
500         offspring_array[i]->MutationRates().DoMetaCopyMut(ctx);
501       }
502     }
503 
504     // Update the phenotypes of each offspring....
505     const Sequence& genome = offspring_array[i]->GetGenome().GetSequence();
506     offspring_array[i]->GetPhenotype().SetupOffspring(parent_phenotype, genome);
507     offspring_array[i]->GetPhenotype().SetMerit(merit_array[i]);
508     offspring_array[i]->SetLineageLabel(parent_organism->GetLineageLabel());
509 
510     //By default, store the parent cclade, this may get modified in ActivateOrgansim (@MRR)
511     offspring_array[i]->SetCCladeLabel(parent_organism->GetCCladeLabel());
512 
513     // If inherited reputation is turned on, set the offspring's reputation
514     // to that of its parent.
515     if (m_world->GetConfig().INHERIT_REPUTATION.Get() == 1) {
516       offspring_array[i]->SetReputation(parent_organism->GetReputation());
517     }
518     else if (m_world->GetConfig().INHERIT_REPUTATION.Get() == 2) {
519       offspring_array[i]->SetTag(parent_organism->GetTag());
520     }
521     else if (m_world->GetConfig().INHERIT_REPUTATION.Get() == 3) {
522       offspring_array[i]->SetTag(parent_organism->GetTag());
523       offspring_array[i]->SetReputation(parent_organism->GetReputation());
524     }
525 
526     // If spatial groups are used, put the offspring in the
527     // parents' group, if tolerances are used check if the offspring
528     // is successfully born into the parent's group or successfully immigrates
529     // into another group.
530     if (m_world->GetConfig().USE_FORM_GROUPS.Get()) {
531       if (parent_organism->HasOpinion()) offspring_array[i]->SetParentGroup(parent_organism->GetOpinion().first);
532       // If tolerances are on ...
533       if (m_world->GetConfig().TOLERANCE_WINDOW.Get() != 0 && m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 0) {
534         bool joins_group = AttemptOffspringParentGroup(ctx, parent_organism, offspring_array[i]);
535         if (!joins_group) {
536           target_cells[i] = doomed_cell;
537           is_doomed = true;
538         }
539       }
540       else {
541         // If not using tolerances or using immigrant only tolerance, put the offspring in the parent's group.
542         assert(parent_organism->HasOpinion());
543         if (m_world->GetConfig().INHERIT_OPINION.Get()) {
544           int group = parent_organism->GetOpinion().first;
545           offspring_array[i]->SetOpinion(group);
546           JoinGroup(offspring_array[i], group);
547         }
548       }
549     }
550     // if parent org has executed teach_offspring intruction, allow the offspring to learn parent's foraging/targeting behavior
551     if (parent_organism->IsTeacher()) offspring_array[i]->SetParentTeacher(true);
552     offspring_array[i]->SetParentFT(parent_organism->GetForageTarget());
553     // and some rebirth stuff
554     offspring_array[i]->SetParentMerit(parent_organism->GetPhenotype().GetMerit().GetDouble());
555     offspring_array[i]->SetParentMultiThreaded(parent_organism->GetPhenotype().IsMultiThread());
556   }
557 
558   // If we're not about to kill the parent, do some extra work on it.
559   if (parent_alive == true) {
560     if (parent_phenotype.GetMerit().GetDouble() <= 0.0 || m_world->GetConfig().BIRTH_METHOD.Get() == 13) {
561       // no weakling parents either!
562       parent_organism->GetPhenotype().SetToDie();
563       parent_alive = false;
564     }
565     else {
566       // Reset inputs and re-calculate merit if required
567       if (m_world->GetConfig().RESET_INPUTS_ON_DIVIDE.Get() > 0){
568         environment.SetupInputs(ctx, parent_cell.m_inputs);
569 
570         int pc_phenotype = m_world->GetConfig().PRECALC_PHENOTYPE.Get();
571         if (pc_phenotype) {
572           cCPUTestInfo test_info;
573           cTestCPU* test_cpu = m_world->GetHardwareManager().CreateTestCPU(ctx);
574           test_info.UseManualInputs(parent_cell.GetInputs()); // Test using what the environment will be
575           Genome mg(parent_organism->GetGenome());
576           mg.SetSequence(parent_organism->GetHardware().GetMemory());
577           test_cpu->TestGenome(ctx, test_info, mg); // Use the true genome
578           if (pc_phenotype & 1) {  // If we must update the merit
579             parent_phenotype.SetMerit(test_info.GetTestPhenotype().GetMerit());
580           }
581           if (pc_phenotype & 2) {  // If we must update the gestation time
582             parent_phenotype.SetGestationTime(test_info.GetTestPhenotype().GetGestationTime());
583           }
584           if (pc_phenotype & 4) {  // If we must update the last instruction counts
585             parent_phenotype.SetTestCPUInstCount(test_info.GetTestPhenotype().GetLastInstCount());
586           }
587           parent_phenotype.SetFitness(parent_phenotype.GetMerit().CalcFitness(parent_phenotype.GetGestationTime())); // Update fitness
588           delete test_cpu;
589         }
590       }
591       AdjustSchedule(parent_cell, parent_phenotype.GetMerit());
592 
593       if (!is_doomed) {
594         // In a local run, face the offspring toward the parent.
595         const int birth_method = m_world->GetConfig().BIRTH_METHOD.Get();
596         if (birth_method < NUM_LOCAL_POSITION_OFFSPRING || birth_method == POSITION_OFFSPRING_PARENT_FACING) {
597           for (int i = 0; i < offspring_array.GetSize(); i++) {
598             if (target_cells[i] != -1) {
599               GetCell(target_cells[i]).Rotate(parent_cell);
600             }
601           }
602         }
603       }
604       // Purge the mutations since last division
605       parent_organism->OffspringGenome().GetSequence().GetMutationSteps().Clear();
606     }
607   }
608 
609   // Do any statistics on the parent that just gave birth...
610   parent_organism->HandleGestation();
611 
612   // Place all of the offspring...
613   for (int i = 0; i < offspring_array.GetSize(); i++) {
614     if (target_cells[i] != -1) {
615       //@JEB - we may want to pass along some state information from parent to offspring
616       if ( (m_world->GetConfig().EPIGENETIC_METHOD.Get() == EPIGENETIC_METHOD_OFFSPRING)
617           || (m_world->GetConfig().EPIGENETIC_METHOD.Get() == EPIGENETIC_METHOD_BOTH) ) {
618         offspring_array[i]->GetHardware().InheritState(parent_organism->GetHardware());
619       }
620       bool org_survived = ActivateOrganism(ctx, offspring_array[i], GetCell(target_cells[i]));
621       // only assign an avatar cell if the org lived through birth and it isn't the parent
622       if (m_world->GetConfig().USE_AVATARS.Get() && org_survived) {
623         int avatar_target_cell = PlaceAvatar(parent_organism);
624         offspring_array[i]->GetPhenotype().SetAVBirthCellID(avatar_target_cell);
625         if (offspring_array[i] != parent_organism) {
626           offspring_array[i]->GetOrgInterface().AddPredPreyAV(avatar_target_cell);
627         }
628       }
629     } else {
630       delete offspring_array[i];
631     }
632   }
633   return parent_alive;
634 }
635 
UpdateQs(cOrganism * org,bool reproduced)636 void cPopulation::UpdateQs(cOrganism* org, bool reproduced)
637 {
638   // yank the org out of any current trace queues, as appropriate (i.e. if dead (==!reproduced) or if reproduced and splitting on divide)
639   bool split = m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT;
640 
641   if (!reproduced || (reproduced && split)) {
642     org->GetHardware().PrintMicroTrace(org->GetBioGroup("genotype")->GetID());
643     org->GetHardware().DeleteMiniTrace(print_mini_trace_reacs);
644   }
645 
646   if (org->GetHardware().IsReproTrace() && repro_q.GetSize()) {
647     for (int i = 0; i < repro_q.GetSize(); i++) {
648       if (repro_q[i] == org) {
649         if (reproduced) m_world->GetStats().PrintReproData(org);
650         if (!reproduced || (reproduced && split)) {
651           int last = repro_q.GetSize() - 1;
652           repro_q.Swap(i, last);
653           repro_q.Pop();
654           org->GetHardware().SetReproTrace(false);
655         }
656         break;
657       }
658     }
659   }
660   if (org->GetHardware().IsTopNavTrace() && topnav_q.GetSize()) {
661     for (int i = 0; i < topnav_q.GetSize(); i++) {
662       if (topnav_q[i] == org) {
663         if (reproduced) m_world->GetStats().UpdateTopNavTrace(org);
664         if (!reproduced || (reproduced && split)) {
665           int last = topnav_q.GetSize() - 1;
666           topnav_q.Swap(i, last);
667           topnav_q.Pop();
668           org->GetHardware().SetTopNavTrace(false);
669         }
670         break;
671       }
672     }
673   }
674 }
675 
TestForParasiteInteraction(cOrganism * infected_host,cOrganism * target_host)676 bool cPopulation::TestForParasiteInteraction(cOrganism* infected_host, cOrganism* target_host)
677 {
678   //default to failing the interaction
679   bool interaction_fails = true;
680   int infection_mechanism = m_world->GetConfig().INFECTION_MECHANISM.Get();
681 
682   cPhenotype& parent_phenotype = infected_host->GetPhenotype();
683 
684   tArray<int> host_task_counts = target_host->GetPhenotype().GetLastHostTaskCount();
685   tArray<int> parasite_task_counts = parent_phenotype.GetLastParasiteTaskCount();
686 
687 
688   if (infection_mechanism == 0) {
689     interaction_fails = false;
690   }
691 
692   // 1: Parasite must match at least 1 task the host does (Overlap)
693   if (infection_mechanism == 1) {
694     //handle skipping of first task
695     int start = 0;
696     if (m_world->GetConfig().INJECT_SKIP_FIRST_TASK.Get()) {
697       start += 1;
698     }
699 
700     //find if there is a matching task
701     for (int i = start; i < host_task_counts.GetSize(); i++) {
702       if (host_task_counts[i] > 0 && parasite_task_counts[i] > 0) {
703         //inject should succeed if there is a matching task
704         interaction_fails = false;
705       }
706     }
707   }
708 
709   // 2: Parasite must perform at least one task the host does not (Inverse Overlap)
710   if (infection_mechanism == 2) {
711     //handle skipping of first task
712     int start = 0;
713     if (m_world->GetConfig().INJECT_SKIP_FIRST_TASK.Get()) {
714       start += 1;
715     }
716 
717     //find if there is a parasite task that the host isn't doing
718     for (int i = start; i < host_task_counts.GetSize(); i++) {
719       if (host_task_counts[i] == 0 && parasite_task_counts[i] > 0) {
720         //inject should succeed if there is a matching task
721         interaction_fails = false;
722       }
723     }
724   }
725 
726   // 3: Parasite tasks must match host tasks exactly. (Matching Alleles)
727   if (infection_mechanism == 3) {
728     //handle skipping of first task
729     int start = 0;
730     if (m_world->GetConfig().INJECT_SKIP_FIRST_TASK.Get()) {
731       start += 1;
732     }
733 
734     //This time if we trigger the if statments we DO fail.
735     interaction_fails = false;
736     for (int i = start; i < host_task_counts.GetSize(); i++) {
737       if ((host_task_counts[i] == 0 && parasite_task_counts[i] > 0) ||
738           (host_task_counts[i] > 0 && parasite_task_counts[i] == 0)) {
739         //inject should fail if either the host or parasite is doing a task the other isn't.
740         interaction_fails = true;
741       }
742     }
743   }
744 
745   // 4: Parasite tasks must overcome hosts. (GFG)
746   if (infection_mechanism == 4) {
747     //handle skipping of first task
748     int start = 0;
749     if (m_world->GetConfig().INJECT_SKIP_FIRST_TASK.Get()) {
750       start += 1;
751     }
752 
753     //This time if we trigger the if statments we DO fail.
754     interaction_fails = false;
755     bool parasite_overcomes = false;
756     for (int i = start; i < host_task_counts.GetSize(); i++) {
757       if (host_task_counts[i] > 0 && parasite_task_counts[i] == 0 ) {
758         //inject should fail if the host overcomes the parasite.
759         interaction_fails = true;
760       }
761 
762       //check if parasite overcomes at least one task
763       if (parasite_task_counts[i] > 0 && host_task_counts[i] == 0) {
764         parasite_overcomes = true;
765       }
766     }
767 
768     //if host doesn't overcome, infection may still fail if the parasite doesn't overcome the host
769     if (interaction_fails == false && parasite_overcomes == false) {
770       interaction_fails = true;
771     }
772   }
773 
774   // 5: Quantitative Matching Allele -- probability of infection based on phenotype overlap
775   if (infection_mechanism == 5) {
776     //handle skipping of first task
777     int start = 0;
778     if(m_world->GetConfig().INJECT_SKIP_FIRST_TASK.Get()) {
779       start += 1;
780     }
781 
782     //calculate how many tasks have the same binary phenotype (i.e. how much overlap)
783     int num_overlap = 0;
784     for (int i = start; i < host_task_counts.GetSize(); i++) {
785       if ((host_task_counts[i] > 0 && parasite_task_counts[i] > 0) ||
786           (host_task_counts[i] == 0 && parasite_task_counts[i] == 0)) {
787         num_overlap += 1;
788       }
789     }
790 
791     //turn number into proportion of available tasks that match
792     double prop_overlap = double(num_overlap) / (host_task_counts.GetSize() - start);
793 
794     //use config exponent and calculate probability of infection
795     double infection_exponent = m_world->GetConfig().INJECT_QMA_EXPONENT.Get();
796     double prob_success = pow(prop_overlap, infection_exponent);
797 
798     //check if infection should fail based on probability
799     double rand = m_world->GetRandom().GetDouble();
800     interaction_fails = rand > prob_success;
801   }
802 
803   // TODO: Add other infection mechanisms -LZ
804   // : Probabilistic infection based on overlap. (GFG)
805   // : Multiplicative GFG (special case of above?)
806   // : Randomization of tasks that match between hosts and parasites?
807   // : ??
808   if (interaction_fails) {
809     double prob_success = m_world->GetConfig().INJECT_DEFAULT_SUCCESS.Get();
810     double rand = m_world->GetRandom().GetDouble();
811 
812     if (rand > prob_success) {
813       return false;
814     }
815   }
816 
817   return true;
818 }
819 
ActivateParasite(cOrganism * host,cBioUnit * parent,const cString & label,const Sequence & injected_code)820 bool cPopulation::ActivateParasite(cOrganism* host, cBioUnit* parent, const cString& label, const Sequence& injected_code)
821 {
822   assert(parent != NULL);
823 
824   // Quick check for empty parasites
825   if (injected_code.GetSize() == 0) return false;
826 
827 
828   // Pull the host cell
829   const int host_id = host->GetOrgInterface().GetCellID();
830   assert(host_id >= 0 && host_id < cell_array.GetSize());
831   cPopulationCell& host_cell = cell_array[host_id];
832 
833 
834   // Select a target organism
835   // @TODO - activate parasite target selection should account for hardware type
836   cOrganism* target_organism = NULL;
837 
838    // If there's any migration turned on ... try this first
839    if(m_world->GetConfig().NUM_DEMES.Get() > 1 && m_world->GetConfig().DEMES_PARASITE_MIGRATION_RATE.Get() > 0.0 && m_world->GetConfig().DEMES_MIGRATION_METHOD.Get() == 4 && m_world->GetRandom().P(m_world->GetConfig().DEMES_PARASITE_MIGRATION_RATE.Get())){
840        // MIGRATION_MATRIX
841      cDeme& deme = GetDeme(m_world->GetMigrationMatrix().GetProbabilisticDemeID(host_cell.GetDemeID(), m_world->GetRandom(),true));
842 
843      // Implementation #1 - Picks randomly of ALL cells in to-deme and then finds if the one it chose was occupied
844      // -- Not ensured to infect an individual
845      cPopulationCell& rand_cell = deme.GetCell(m_world->GetRandom().GetInt(deme.GetSize()));
846      if(rand_cell.IsOccupied()){
847        target_organism = rand_cell.GetOrganism();
848      }
849    }
850    else{
851      // Else there was no migration ... Resort to the default BIRTH_METHOD
852      if (m_world->GetConfig().BIRTH_METHOD.Get() ==  POSITION_OFFSPRING_FULL_SOUP_RANDOM) {
853        target_organism = GetCell(m_world->GetRandom().GetUInt(cell_array.GetSize())).GetOrganism();
854      }
855      else if(m_world->GetConfig().BIRTH_METHOD.Get() == POSITION_OFFSPRING_DEME_RANDOM){
856        cDeme& deme = GetDeme(host_cell.GetDemeID());
857        cPopulationCell& rand_cell = deme.GetCell(m_world->GetRandom().GetInt(deme.GetSize()));
858        if(rand_cell.IsOccupied()){
859          target_organism = rand_cell.GetOrganism();
860        }
861      }
862      else {
863        target_organism =
864        host_cell.ConnectionList().GetPos(m_world->GetRandom().GetUInt(host->GetNeighborhoodSize()))->GetOrganism();
865      }
866   }
867 
868   if (target_organism == NULL) return false;
869 
870 
871   // Pre-check target hardware
872   const cHardwareBase& hw = target_organism->GetHardware();
873   if (hw.GetType() != parent->GetGenome().GetHardwareType() ||
874       hw.GetInstSet().GetInstSetName() != parent->GetGenome().GetInstSet() ||
875       hw.GetNumThreads() == m_world->GetConfig().MAX_CPU_THREADS.Get()) return false;
876 
877   //Handle host specific injection
878   if(TestForParasiteInteraction(host, target_organism) == false)
879     return false;
880 
881 
882   // Attempt actual parasite injection
883 
884   Genome mg(parent->GetGenome().GetHardwareType(), parent->GetGenome().GetInstSet(), injected_code);
885   cParasite* parasite = new cParasite(m_world, mg, parent->GetPhenotype().GetGeneration(), SRC_PARASITE_INJECT, label);
886 
887   //Handle potential virulence evolution if this parasite is comming from a parasite
888   //and virulence is inhereted from the parent (source == 1)
889   if (parent->IsParasite() && m_world->GetConfig().VIRULENCE_SOURCE.Get() == 1)
890   {
891     //mutate virulence
892     // m_world->GetConfig().PARASITE_VIRULENCE.Get()
893     double oldVir = dynamic_cast<cParasite*>(parent)->GetVirulence();
894 
895     //default to not mutating
896     double newVir = oldVir;
897 
898     //but if we do mutate...
899     if (m_world->GetRandom().GetDouble() < m_world->GetConfig().VIRULENCE_MUT_RATE.Get())
900     {
901       //get this in a temp variable so we don't have to make the next line huge
902       double vir_sd = m_world->GetConfig().VIRULENCE_SD.Get();
903 
904       //sd^2 = varience
905       newVir = m_world->GetRandom().GetRandNormal(oldVir, vir_sd * vir_sd);
906 
907     }
908     parasite->SetVirulence(Max(Min(newVir, 1.0), 0.0));
909   }
910   else
911   {
912     //get default virulence
913     parasite->SetVirulence(m_world->GetConfig().PARASITE_VIRULENCE.Get());
914   }
915   if (!target_organism->ParasiteInfectHost(parasite)) {
916     delete parasite;
917     return false;
918   }
919 
920   //If parasite was successfully injected, update the phenotype for the parasite in new organism
921   target_organism->GetPhenotype().SetLastParasiteTaskCount(host->GetPhenotype().GetLastParasiteTaskCount());
922 
923   // Classify the parasite
924   tArray<const tArray<cBioGroup*>*> pgrps(1);
925   pgrps[0] = &parent->GetBioGroups();
926   parasite->SelfClassify(pgrps);
927 
928   // Handle post injection actions
929   if (m_world->GetConfig().INJECT_STERILIZES_HOST.Get()) target_organism->GetPhenotype().Sterilize();
930 
931   return true;
932 }
933 
ActivateOrganism(cAvidaContext & ctx,cOrganism * in_organism,cPopulationCell & target_cell,bool assign_group,bool is_inject)934 bool cPopulation::ActivateOrganism(cAvidaContext& ctx, cOrganism* in_organism, cPopulationCell& target_cell, bool assign_group, bool is_inject)
935 {
936   assert(in_organism != NULL);
937   assert(in_organism->GetGenome().GetSize() >= 1);
938 
939   in_organism->SetOrgInterface(ctx, new cPopulationInterface(m_world));
940 
941   // Update the contents of the target cell.
942   KillOrganism(target_cell, ctx);
943   target_cell.InsertOrganism(in_organism, ctx);
944   AddLiveOrg(in_organism);
945 
946   // Setup the inputs in the target cell.
947   environment.SetupInputs(ctx, target_cell.m_inputs);
948 
949   // Precalculate the phenotype if requested
950   int pc_phenotype = m_world->GetConfig().PRECALC_PHENOTYPE.Get();
951   if (pc_phenotype){
952     cCPUTestInfo test_info;
953     cTestCPU* test_cpu = m_world->GetHardwareManager().CreateTestCPU(ctx);
954     test_info.UseManualInputs(target_cell.GetInputs()); // Test using what the environment will be
955     Genome mg(in_organism->GetGenome());
956     mg.SetSequence(in_organism->GetHardware().GetMemory());
957     test_cpu->TestGenome(ctx, test_info, mg);  // Use the true genome
958 
959     if (pc_phenotype & 1)
960       in_organism->GetPhenotype().SetMerit(test_info.GetTestPhenotype().GetMerit());
961     if (pc_phenotype & 2)
962       in_organism->GetPhenotype().SetGestationTime(test_info.GetTestPhenotype().GetGestationTime());
963     in_organism->GetPhenotype().SetFitness(in_organism->GetPhenotype().GetMerit().CalcFitness(in_organism->GetPhenotype().GetGestationTime()));
964     delete test_cpu;
965   }
966   // Update the archive...
967 
968 
969   // Initialize the time-slice for this new organism.
970   AdjustSchedule(target_cell, in_organism->GetPhenotype().GetMerit());
971 
972   // Special handling for certain birth methods.
973   if (m_world->GetConfig().BIRTH_METHOD.Get() == POSITION_OFFSPRING_FULL_SOUP_ELDEST) {
974     reaper_queue.Push(&target_cell);
975   }
976 
977   // If neural networking, add input and output avatars.. @JJB**
978   if (m_world->GetConfig().USE_AVATARS.Get() && m_world->GetConfig().NEURAL_NETWORKING.Get()) {
979     // Add input avatar
980     in_organism->GetOrgInterface().AddIOAV(target_cell.GetID(), 2, true, false);
981     // Add input avatar
982     in_organism->GetOrgInterface().AddIOAV(target_cell.GetID(), 2, false, true);
983   }
984 
985   // Keep track of statistics for organism counts...
986   num_organisms++;
987   if (m_world->GetConfig().PRED_PREY_SWITCH.Get() == -2 || m_world->GetConfig().PRED_PREY_SWITCH.Get() > -1) {
988     // ft should be nearly always -1 so long as it is not being inherited
989     if (in_organism->GetForageTarget() > -2) num_prey_organisms++;
990     else num_pred_organisms++;
991   }
992   if (deme_array.GetSize() > 0) {
993     deme_array[target_cell.GetDemeID()].IncOrgCount();
994   }
995 
996   // Statistics...
997   m_world->GetStats().RecordBirth(in_organism->GetPhenotype().ParentTrue());
998 
999   // @MRR Do coalescence clade setup for new organisms.
1000   CCladeSetupOrganism(in_organism );
1001 
1002   //count how many times MERIT_BONUS_INST (rewarded instruction) is in the genome
1003   //only relevant if merit is proportional to # times MERIT_BONUS_INST is in the genome
1004   int rewarded_instruction = m_world->GetConfig().MERIT_BONUS_INST.Get();
1005   int num_rewarded_instructions = 0;
1006   int genome_length = in_organism->GetGenome().GetSize();
1007 
1008   if (rewarded_instruction == -1){
1009     //no key instruction, so no bonus
1010     in_organism->GetPhenotype().SetCurBonusInstCount(0);
1011   }
1012   else{
1013     for(int i = 1; i <= genome_length; i++){
1014       if (in_organism->GetGenome().GetSequence()[i-1].GetOp() == rewarded_instruction){
1015         num_rewarded_instructions++;
1016       }
1017     }
1018     in_organism->GetPhenotype().SetCurBonusInstCount(num_rewarded_instructions);
1019   }
1020   // ok, after we've gone through all that, there's a catch.  It is possible that the
1021   // cell into which this organism has been injected is in fact a "gateway" to another
1022   // world.  if so, we then migrate this organism out of this world and empty the cell.
1023   if(m_world->IsWorldBoundary(target_cell)) {
1024     m_world->MigrateOrganism(in_organism, target_cell, in_organism->GetPhenotype().GetMerit(), in_organism->GetLineageLabel());
1025     KillOrganism(target_cell, ctx);
1026   }
1027 
1028   if (assign_group) {
1029     int op = m_world->GetConfig().DEFAULT_GROUP.Get();
1030     if (m_world->GetConfig().USE_FORM_GROUPS.Get() != 0) {
1031       if (!in_organism->HasOpinion()) {
1032         if (m_world->GetConfig().DEFAULT_GROUP.Get() != -1) {
1033           in_organism->SetOpinion(m_world->GetConfig().DEFAULT_GROUP.Get());
1034           JoinGroup(in_organism, m_world->GetConfig().DEFAULT_GROUP.Get());
1035         }
1036         else {
1037           if (m_world->GetConfig().USE_FORM_GROUPS.Get() == 1) {
1038             op = (int) abs(ctx.GetRandom().GetDouble());
1039             in_organism->SetOpinion(op);
1040             JoinGroup(in_organism, op);
1041           }
1042           else if (m_world->GetConfig().USE_FORM_GROUPS.Get() == 2) {
1043             op = ctx.GetRandom().GetInt(0, m_world->GetEnvironment().GetResourceLib().GetSize() + 1);
1044             in_organism->SetOpinion(op);
1045             JoinGroup(in_organism, op);
1046           }
1047         }
1048       }
1049       else op = in_organism->GetOpinion().first;
1050     }
1051 
1052     in_organism->GetPhenotype().SetBirthCellID(target_cell.GetID());
1053     if (m_world->GetConfig().INHERIT_OPINION.Get()) in_organism->GetPhenotype().SetBirthGroupID(op);
1054     else in_organism->GetPhenotype().SetBirthGroupID(in_organism->GetParentGroup());
1055     in_organism->GetPhenotype().SetBirthForagerType(in_organism->GetParentFT());
1056 
1057     cBGGenotype* genotype = dynamic_cast<cBGGenotype*>(in_organism->GetBioGroup("genotype"));
1058     assert(genotype);
1059 
1060     genotype->SetLastBirthCell(target_cell.GetID());
1061     if (m_world->GetConfig().INHERIT_OPINION.Get()) genotype->SetLastGroupID(op);
1062     else genotype->SetLastGroupID(in_organism->GetParentGroup());
1063     genotype->SetLastForagerType(in_organism->GetParentFT());
1064   }
1065 
1066   bool org_survived = true;
1067   // For tolerance_window, we cheated by dumping doomed offspring into cell (X * Y) - 1 ...now that we updated the stats, we need to
1068   // kill that org.
1069   int doomed_cell = (m_world->GetConfig().WORLD_X.Get() * m_world->GetConfig().WORLD_Y.Get()) - 1;
1070   if ((m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) && (target_cell.GetID() == doomed_cell) && (m_world->GetStats().GetUpdate() > 0)) {
1071     KillOrganism(target_cell, ctx);
1072     org_survived = false;
1073   }
1074   // Kill org born on deadly world boundaries
1075   if (m_world->GetConfig().DEADLY_BOUNDARIES.Get() == 1 && m_world->GetConfig().WORLD_GEOMETRY.Get() == 1 && target_cell.GetID() >= 0) {
1076     int dest_x = target_cell.GetID() % m_world->GetConfig().WORLD_X.Get();
1077     int dest_y = target_cell.GetID() / m_world->GetConfig().WORLD_X.Get();
1078     if (dest_x == 0 || dest_y == 0 || dest_x == m_world->GetConfig().WORLD_X.Get() - 1 || dest_y == m_world->GetConfig().WORLD_Y.Get() - 1) {
1079       KillOrganism(target_cell, ctx);
1080       org_survived = false;
1081     }
1082   }
1083   // don't kill our test org, just it's offspring
1084   if ((m_world->GetConfig().BIRTH_METHOD.Get() == 12 || m_world->GetConfig().BIRTH_METHOD.Get() == 13) && !is_inject) {
1085       KillOrganism(target_cell, ctx);
1086       org_survived = false;
1087   }
1088   // are there traces we need to test for?
1089   if (org_survived) {
1090     if (m_next_prey_q > 0 && in_organism->GetParentFT() > -2) {
1091       SetupMiniTrace(in_organism);
1092       m_next_prey_q--;
1093     }
1094     else if (m_next_pred_q > 0 && in_organism->GetParentFT() <= -2) {
1095       SetupMiniTrace(in_organism);
1096       m_next_pred_q--;
1097     }
1098     else if (minitrace_queue.GetSize() > 0) TestForMiniTrace(in_organism);
1099   }
1100   return org_survived;
1101 }
1102 
TestForMiniTrace(cOrganism * in_organism)1103 void cPopulation::TestForMiniTrace(cOrganism* in_organism)
1104 {
1105   // if the org's genotype is on our to do list, setup the trace and remove the instance of the genotype from the list
1106   int org_bg_id = in_organism->GetBioGroup("genotype")->GetID();
1107   for (int i = 0; i < minitrace_queue.GetSize(); i++) {
1108     if (org_bg_id == minitrace_queue[i]) {
1109       unsigned int last = minitrace_queue.GetSize() - 1;
1110       minitrace_queue.Swap(i, last);
1111       minitrace_queue.Pop();
1112       SetupMiniTrace(in_organism);
1113       break;
1114     }
1115   }
1116 }
1117 
SetupMiniTrace(cOrganism * in_organism)1118 void cPopulation::SetupMiniTrace(cOrganism* in_organism)
1119 {
1120   const int target = in_organism->GetParentFT();
1121   const int id = in_organism->GetID();
1122   int group_id = m_world->GetConfig().DEFAULT_GROUP.Get();
1123   if (in_organism->HasOpinion()) group_id = in_organism->GetOpinion().first;
1124   else group_id = in_organism->GetParentGroup();
1125 
1126   cString filename = cStringUtil::Stringf("minitraces/org%d-ud%d-grp%d_ft%d-gt%d.trc", id, m_world->GetStats().GetUpdate(), group_id, target, in_organism->GetBioGroup("genotype")->GetID());
1127 
1128   if (!use_micro_traces) in_organism->GetHardware().SetMiniTrace(filename, in_organism->GetBioGroup("genotype")->GetID(), in_organism->GetBioGroup("genotype")->GetProperty("name").AsString());
1129   else in_organism->GetHardware().SetMicroTrace();
1130 
1131   if (print_mini_trace_genomes) {
1132     cString gen_file =  cStringUtil::Stringf("minitraces/trace_genomes/org%d-ud%d-grp%d_ft%d-gt%d.trcgeno", id, m_world->GetStats().GetUpdate(), group_id, target, in_organism->GetBioGroup("genotype")->GetID());
1133     PrintMiniTraceGenome(in_organism, gen_file);
1134   }
1135 }
1136 
PrintMiniTraceGenome(cOrganism * in_organism,cString & filename)1137 void cPopulation::PrintMiniTraceGenome(cOrganism* in_organism, cString& filename)
1138 {
1139   // need a random number generator to pass to testcpu that does not affect any other random number pulls (since this is just for printing the genome)
1140   cRandom rng(0);
1141   cAvidaContext ctx2(m_world, rng);
1142 
1143   cTestCPU* testcpu = m_world->GetHardwareManager().CreateTestCPU(ctx2);
1144   testcpu->PrintGenome(ctx2, Genome(in_organism->GetBioGroup("genotype")->GetProperty("genome").AsString()), filename, m_world->GetStats().GetUpdate());
1145   delete testcpu;
1146 }
1147 
SetMiniTraceQueue(tSmartArray<int> new_queue,const bool print_genomes,const bool print_reacs,const bool use_micro)1148 void cPopulation::SetMiniTraceQueue(tSmartArray<int> new_queue, const bool print_genomes, const bool print_reacs, const bool use_micro)
1149 {
1150   minitrace_queue.Resize(0);
1151   for (int i = 0; i < new_queue.GetSize(); i++) minitrace_queue.Push(new_queue[i]);
1152   print_mini_trace_genomes = print_genomes;
1153   print_mini_trace_reacs = print_reacs;
1154   use_micro_traces = use_micro;
1155 }
1156 
AppendMiniTraces(tSmartArray<int> new_queue,const bool print_genomes,const bool print_reacs,const bool use_micro)1157 void cPopulation::AppendMiniTraces(tSmartArray<int> new_queue, const bool print_genomes, const bool print_reacs, const bool use_micro)
1158 {
1159   for (int i = 0; i < new_queue.GetSize(); i++) minitrace_queue.Push(new_queue[i]);
1160   print_mini_trace_genomes = print_genomes;
1161   print_mini_trace_reacs = print_reacs;
1162   use_micro_traces = use_micro;
1163 }
1164 
LoadMiniTraceQ(cString & filename,int orgs_per,bool print_genomes,bool print_reacs)1165 void cPopulation::LoadMiniTraceQ(cString& filename, int orgs_per, bool print_genomes, bool print_reacs)
1166 {
1167   cInitFile input_file(filename, m_world->GetWorkingDir());
1168   if (!input_file.WasOpened()) {
1169     const cUserFeedback& feedback = input_file.GetFeedback();
1170     for (int i = 0; i < feedback.GetNumMessages(); i++) {
1171       switch (feedback.GetMessageType(i)) {
1172         case cUserFeedback::UF_ERROR:    m_world->GetDriver().RaiseException(feedback.GetMessage(i)); break;
1173         case cUserFeedback::UF_WARNING:  m_world->GetDriver().NotifyWarning(feedback.GetMessage(i)); break;
1174         default:                      m_world->GetDriver().NotifyComment(feedback.GetMessage(i)); break;
1175       };
1176     }
1177   }
1178 
1179   tSmartArray<int> bg_id_list;
1180   tSmartArray<int> queue = m_world->GetPopulation().GetMiniTraceQueue();
1181   for (int line_id = 0; line_id < input_file.GetNumLines(); line_id++) {
1182     cString cur_line = input_file.GetLine(line_id);
1183 
1184     tDictionary<cString>* line = input_file.GetLineAsDict(line_id);
1185     int gen_id_num = line->Get("id").AsInt();
1186 
1187     // setup the genotype 'list' which will be checked in activateorg
1188     // skip if enough already in the existing trace queue (e.g if loading multiple genotype id files that overlap)
1189     int add_num = orgs_per;
1190     for (int i = 0; i < queue.GetSize(); i++) {
1191       if (gen_id_num == queue[i]) {
1192         add_num--;
1193         if (add_num <= 0) break;
1194       }
1195     }
1196     for (int j = 0; j < add_num; j++) {
1197       bg_id_list.Push(gen_id_num);
1198     }
1199   }
1200 
1201   if (queue.GetSize() > 0) {
1202     AppendMiniTraces(bg_id_list, print_genomes, print_reacs);
1203   }
1204   else {
1205     SetMiniTraceQueue(bg_id_list, print_genomes, print_reacs);
1206   }
1207 }
1208 
SetRandomTraceQ(int max_samples)1209 tSmartArray<int> cPopulation::SetRandomTraceQ(int max_samples)
1210 {
1211   // randomly sample (w/ replacement) bgs in pop
1212   tSmartArray<int> bg_id_list;
1213   const tSmartArray <cOrganism*> live_orgs = live_org_list;
1214 
1215   int max_bgs = 1;
1216   if (max_samples) max_bgs = max_samples;
1217   if (max_samples > live_orgs.GetSize()) max_bgs = live_orgs.GetSize();
1218 
1219   tArray<bool> used_orgs;
1220   used_orgs.Resize(live_orgs.GetSize());
1221   used_orgs.SetAll(false);
1222 
1223   while (bg_id_list.GetSize() < max_bgs) {
1224     int this_rand_sample = m_world->GetRandomSample().GetInt(0, live_orgs.GetSize());
1225     if (!used_orgs[this_rand_sample]) {
1226       cOrganism* rand_org = live_orgs[this_rand_sample];
1227       bg_id_list.Push(rand_org->GetBioGroup("genotype")->GetID());
1228       used_orgs[this_rand_sample] = true;
1229     }
1230   }
1231   return bg_id_list;
1232 }
1233 
SetRandomPreyTraceQ(int max_samples)1234 tSmartArray<int> cPopulation::SetRandomPreyTraceQ(int max_samples)
1235 {
1236   // randomly sample (w/ replacement) bgs in pop
1237   tSmartArray<int> bg_id_list;
1238   const tSmartArray <cOrganism*> live_orgs = live_org_list;
1239 
1240   int max_bgs = 1;
1241   if (max_samples) max_bgs = max_samples;
1242   if (max_samples > num_prey_organisms) max_bgs = num_prey_organisms;
1243 
1244   tArray<bool> used_orgs;
1245   used_orgs.Resize(live_orgs.GetSize());
1246   used_orgs.SetAll(false);
1247 
1248   while (bg_id_list.GetSize() < max_bgs) {
1249     int this_rand_sample = m_world->GetRandomSample().GetInt(0, live_orgs.GetSize());
1250     if (!used_orgs[this_rand_sample]) {
1251       cOrganism* rand_org = live_orgs[this_rand_sample];
1252       if (rand_org->GetForageTarget() > -2) {
1253         bg_id_list.Push(rand_org->GetBioGroup("genotype")->GetID());
1254         used_orgs[this_rand_sample] = true;
1255       }
1256     }
1257   }
1258   return bg_id_list;
1259 }
1260 
SetRandomPredTraceQ(int max_samples)1261 tSmartArray<int> cPopulation::SetRandomPredTraceQ(int max_samples)
1262 {
1263   // randomly sample (w/ replacement) bgs in pop
1264   tSmartArray<int> bg_id_list;
1265   const tSmartArray <cOrganism*> live_orgs = live_org_list;
1266 
1267   int max_bgs = 1;
1268   if (max_samples) max_bgs = max_samples;
1269   if (max_samples > num_pred_organisms) max_bgs = num_pred_organisms;
1270 
1271   tArray<bool> used_orgs;
1272   used_orgs.Resize(live_orgs.GetSize());
1273   used_orgs.SetAll(false);
1274 
1275   while (bg_id_list.GetSize() < max_bgs) {
1276     int this_rand_sample = m_world->GetRandomSample().GetInt(0, live_orgs.GetSize());
1277     if (!used_orgs[this_rand_sample]) {
1278       cOrganism* rand_org = live_orgs[this_rand_sample];
1279       if (rand_org->GetForageTarget() <= -2) {
1280         bg_id_list.Push(rand_org->GetBioGroup("genotype")->GetID());
1281         used_orgs[this_rand_sample] = true;
1282       }
1283     }
1284   }
1285   return bg_id_list;
1286 }
1287 
SetNextPreyQ(int num_prey,bool print_genomes,bool print_reacs,bool use_micro)1288 void cPopulation::SetNextPreyQ(int num_prey, bool print_genomes, bool print_reacs, bool use_micro)
1289 {
1290   m_next_prey_q = num_prey;
1291   print_mini_trace_genomes = print_genomes;
1292   print_mini_trace_reacs = print_reacs;
1293   use_micro_traces = use_micro;
1294 }
1295 
SetNextPredQ(int num_pred,bool print_genomes,bool print_reacs,bool use_micro)1296 void cPopulation::SetNextPredQ(int num_pred, bool print_genomes, bool print_reacs, bool use_micro)
1297 {
1298   m_next_pred_q = num_pred;
1299   print_mini_trace_genomes = print_genomes;
1300   print_mini_trace_reacs = print_reacs;
1301   use_micro_traces = use_micro;
1302 }
1303 
SetTraceQ(int save_dominants,int save_groups,int save_foragers,int orgs_per,int max_samples)1304 tSmartArray<int> cPopulation::SetTraceQ(int save_dominants, int save_groups, int save_foragers, int orgs_per, int max_samples)
1305 {
1306   // setup the genotype 'list' which will be checked in activateorg
1307   // this should setup a 'list' of genotypes at each event update which should be followed (e.g. if orgs_per = 10, save top 10 prey genotypes + top 10 predator genotypes at this update or one org from top 10 most common genotypes over all)
1308   // items should be removed from list once an org of that type is set to be traced
1309   // number of items in list should be capped by max_samples, filling the list with the more dominant genotypes first (this is necessary in the case of saving groups because we may not know how many groups there will be at any time during a run and so cannot set orgs_per to function as an absolute cap...should not be neccessary for saving by dominants or saving by foragers)
1310   // when we go to check if an org is to be traced, all we need to then do is remove the genotype from the list if the org's genotype is there
1311   // in activateorganism we can just check the size of this array,
1312   // if it is 0, there is nothing to check, if it is > 0, there are genotypes waiting
1313   // this will allow genotypes to wait until the next event (which will overwrite the array contents)
1314   // only tracing for orgs within threshold (unless none are, then just use first bg)
1315 
1316   tSmartArray<int> bg_id_list;
1317   tAutoRelease<tIterator<cBioGroup> > it(m_world->GetClassificationManager().GetBioGroupManager("genotype")->Iterator());
1318   cBioGroup* bg = it->Next();
1319   tSmartArray<int> fts_to_use;
1320   tSmartArray<int> groups_to_use;
1321   int num_doms = 0;
1322   int fts_left = 0;
1323   int groups_left = 0;
1324 
1325   if (save_dominants) num_doms = orgs_per;
1326 
1327   // get forager types in pop
1328   tSmartArray<int> ft_check_counts;
1329   ft_check_counts.Resize(0);
1330   if (save_foragers) {
1331     if (m_world->GetConfig().PRED_PREY_SWITCH.Get() == -2 || m_world->GetConfig().PRED_PREY_SWITCH.Get() > -1) fts_to_use.Push(-2);
1332     fts_to_use.Push(-1);  // account for -1 default's
1333     std::set<int> fts_avail = m_world->GetEnvironment().GetTargetIDs();
1334     set <int>::iterator itr;
1335     for(itr = fts_avail.begin();itr!=fts_avail.end();itr++) if (*itr != -1 && *itr != -2) fts_to_use.Push(*itr);
1336     ft_check_counts.Resize(fts_to_use.GetSize());
1337     ft_check_counts.SetAll(orgs_per);
1338     fts_left = orgs_per * fts_to_use.GetSize();
1339   }
1340 
1341   // get groups in pop
1342   tSmartArray<int> group_check_counts;
1343   group_check_counts.Resize(0);
1344   if (save_groups) {
1345     map<int,int> groups_formed = m_world->GetPopulation().GetFormedGroups();
1346     map <int,int>::iterator itr;
1347     for(itr = groups_formed.begin();itr!=groups_formed.end();itr++) {
1348       double cur_size = itr->second;
1349       if (cur_size > 0) groups_to_use.Push(itr->first);
1350     }
1351     group_check_counts.Resize(groups_to_use.GetSize());
1352     group_check_counts.SetAll(orgs_per);
1353     groups_left = orgs_per * groups_to_use.GetSize();
1354   }
1355 
1356   // this will add biogroup genotypes up to max_bgs with priority on dominants, then forager types, then group ids, without repeats
1357   // priority is non-issue if you don't double up on the settings in one go
1358   int max_bgs = 1;
1359   if (max_samples) max_bgs = max_samples;
1360   else max_bgs = num_doms + (orgs_per * fts_to_use.GetSize()) + (orgs_per * groups_to_use.GetSize());
1361   int num_types = 3;
1362   bool doms_done = false;
1363   bool fts_done = false;
1364   bool grps_done = false;
1365   if (!save_dominants) doms_done = true;
1366   if (!save_foragers) fts_done = true;
1367   if (!save_groups) grps_done = true;
1368   for (int i = 0; i < num_types; i++) {
1369     if (bg_id_list.GetSize() < max_bgs && (!doms_done || !fts_done || !grps_done)) {
1370       if (i == 0 && save_dominants && num_doms > 0) {
1371         for (int j = 0; j < num_doms; j++) {
1372           if (bg && (bg->GetProperty("threshold").AsBool() || bg_id_list.GetSize() == 0)) {
1373             bg_id_list.Push(bg->GetID());
1374             if (save_foragers) {
1375               int ft = bg->GetProperty("last_forager_type").AsInt();
1376               if (fts_left > 0) {
1377                 for (int k = 0; k < fts_to_use.GetSize(); k++) {
1378                   if (ft == fts_to_use[k]) {
1379                     ft_check_counts[k]--;
1380                     if (ft_check_counts[k] == 0) {
1381                       unsigned int last = fts_to_use.GetSize() - 1;
1382                       fts_to_use.Swap(k, last);
1383                       fts_to_use.Pop();
1384                       ft_check_counts.Swap(k, last);
1385                       ft_check_counts.Pop();
1386                     }
1387                     fts_left--;
1388                     break;
1389                   }
1390                 }
1391               }
1392             }
1393             if (save_groups) {
1394               int grp = bg->GetProperty("last_group_id").AsInt();
1395               if (groups_left > 0) {
1396                 for (int k = 0; k < groups_to_use.GetSize(); k++) {
1397                   if (grp == groups_to_use[k]) {
1398                     group_check_counts[k]--;
1399                     if (group_check_counts[k] == 0) {
1400                       unsigned int last = groups_to_use.GetSize() - 1;
1401                       groups_to_use.Swap(k, last);
1402                       groups_to_use.Pop();
1403                       group_check_counts.Swap(k, last);
1404                       group_check_counts.Pop();
1405                     }
1406                     groups_left--;
1407                     break;
1408                   }
1409                 }
1410               }
1411             }
1412             if (bg == it->Next()) { // no more to check
1413               doms_done = true;
1414               break;
1415             }
1416             else bg = it->Next();
1417           }
1418           else if (bg && !bg->GetProperty("threshold").AsBool()) {      // no more above threshold
1419             doms_done = true;
1420             break;
1421           }
1422         }
1423         if (doms_done) continue;
1424       } // end of dominants
1425 
1426       else if (i == 1 && save_foragers && fts_left > 0) {
1427         for (int j = 0; j < fts_left; j++) {
1428           if (bg && (bg->GetProperty("threshold").AsBool() || bg_id_list.GetSize() == 0)) {
1429             int ft = bg->GetProperty("last_forager_type").AsInt();
1430             bool found_one = false;
1431             for (int k = 0; k < fts_to_use.GetSize(); k++) {
1432               if (ft == fts_to_use[k]) {
1433                 bg_id_list.Push(bg->GetID());
1434                 ft_check_counts[k]--;
1435                 if (ft_check_counts[k] == 0) {
1436                   unsigned int last = fts_to_use.GetSize() - 1;
1437                   fts_to_use.Swap(k, last);
1438                   fts_to_use.Pop();
1439                   ft_check_counts.Swap(k, last);
1440                   ft_check_counts.Pop();
1441                 }
1442                 found_one = true;
1443                 break;
1444               }
1445             }
1446             if (save_groups) {
1447               int grp = bg->GetProperty("last_group_id").AsInt();
1448               if (groups_left > 0) {
1449                 for (int k = 0; k < groups_to_use.GetSize(); k++) {
1450                   if (grp == groups_to_use[k]) {
1451                     group_check_counts[k]--;
1452                     if (group_check_counts[k] == 0) {
1453                       unsigned int last = groups_to_use.GetSize() - 1;
1454                       groups_to_use.Swap(k, last);
1455                       groups_to_use.Pop();
1456                       group_check_counts.Swap(k, last);
1457                       group_check_counts.Pop();
1458                     }
1459                     groups_left--;
1460                     break;
1461                   }
1462                 }
1463               }
1464             }
1465             if (bg == it->Next()) { // no more to check
1466               fts_done = true;
1467               break;
1468             }
1469             else bg = it->Next();
1470             if (!found_one) j--;
1471           }
1472           else if (bg && !bg->GetProperty("threshold").AsBool()) {  // no more above threshold
1473             fts_done = true;
1474             break;
1475           }
1476         }
1477         if (fts_done) continue;
1478       } // end of forage types
1479 
1480       else if (i == 2 && save_groups && groups_left > 0) {
1481         for (int j = 0; j < groups_left; j++) {
1482           if (bg && (bg->GetProperty("threshold").AsBool() || bg_id_list.GetSize() == 0)) {
1483             int grp = bg->GetProperty("last_group_id").AsInt();
1484             bool found_one = false;
1485             for (int k = 0; k < groups_to_use.GetSize(); k++) {
1486               if (grp == groups_to_use[k]) {
1487                 bg_id_list.Push(bg->GetID());
1488                 group_check_counts[k]--;
1489                 if (group_check_counts[k] == 0) {
1490                   unsigned int last = groups_to_use.GetSize() - 1;
1491                   groups_to_use.Swap(k, last);
1492                   groups_to_use.Pop();
1493                   group_check_counts.Swap(k, last);
1494                   group_check_counts.Pop();
1495                 }
1496                 found_one = true;
1497                 break;
1498               }
1499             }
1500             if (bg == it->Next()) { // no more to check
1501               grps_done = true;
1502               break;
1503             }
1504             else bg = it->Next();
1505             if (!found_one) j--;
1506           }
1507           else if (bg && !bg->GetProperty("threshold").AsBool()) {  // no more above threshold
1508             grps_done = true;
1509             break;
1510           }
1511         }
1512         if (grps_done) break;     // no more of last type we have
1513       } // end of group id types
1514     } // end of while < max_bgs
1515   }
1516   return bg_id_list;
1517 }
1518 
SetTopNavQ()1519 void cPopulation::SetTopNavQ()
1520 {
1521   topnav_q.Resize(live_org_list.GetSize());
1522   for (int i = 0; i < live_org_list.GetSize(); i++) {
1523     live_org_list[i]->GetHardware().SetTopNavTrace(true);
1524     topnav_q[i] = live_org_list[i];
1525   }
1526 }
1527 
AppendRecordReproQ(cOrganism * new_org)1528 void cPopulation::AppendRecordReproQ(cOrganism* new_org)
1529 {
1530   repro_q.Push(new_org);
1531   new_org->GetHardware().SetReproTrace(true);
1532 }
1533 
1534 // @WRE 2007/07/05 Helper function to take care of side effects of Avidian
1535 // movement that cannot be directly handled in cHardwareCPU.cc
MoveOrganisms(cAvidaContext & ctx,int src_cell_id,int dest_cell_id,int true_cell)1536 bool cPopulation::MoveOrganisms(cAvidaContext& ctx, int src_cell_id, int dest_cell_id, int true_cell)
1537 {
1538   cPopulationCell& src_cell = GetCell(src_cell_id);
1539   cPopulationCell& dest_cell = GetCell(dest_cell_id);
1540 
1541   const int dest_x = dest_cell_id % m_world->GetConfig().WORLD_X.Get();
1542   const int dest_y = dest_cell_id / m_world->GetConfig().WORLD_X.Get();
1543 
1544   // check for boundary effects on movement
1545   if (m_world->GetConfig().DEADLY_BOUNDARIES.Get() == 1 && m_world->GetConfig().WORLD_GEOMETRY.Get() == 1) {
1546     // Fail if we're running in the test CPU.
1547     if (src_cell_id < 0) return false;
1548     bool faced_is_boundary = false;
1549     if (dest_x == 0 || dest_y == 0 ||
1550         dest_x == m_world->GetConfig().WORLD_X.Get() - 1 ||
1551         dest_y == m_world->GetConfig().WORLD_Y.Get() - 1) faced_is_boundary = true;
1552     if (faced_is_boundary) {
1553       if (true_cell != -1) KillOrganism(GetCell(true_cell), ctx);
1554       else if (true_cell == -1) KillOrganism(src_cell, ctx);
1555       return false;
1556     }
1557   }
1558 
1559   // get the resource library
1560   const cResourceLib& resource_lib = environment.GetResourceLib();
1561   // get the destination cell resource levels
1562   tArray<double> dest_cell_resources = m_world->GetPopulation().GetCellResources(dest_cell_id, ctx);
1563   // get the current cell resource levels
1564   tArray<double> src_cell_resources = m_world->GetPopulation().GetCellResources(src_cell_id, ctx);
1565 
1566   // test for death by predatory resource
1567   for (int i = 0; i < resource_lib.GetSize(); i++) {
1568     if (resource_lib.GetResource(i)->IsPredatory() && dest_cell_resources[i] > 0) {
1569       // if you step on a predatory resource, we're going to try to kill you regardless of whether there is a den there
1570       if (ctx.GetRandom().P(resource_lib.GetResource(i)->GetPredatorResOdds())) {
1571         if (true_cell != -1) KillOrganism(GetCell(true_cell), ctx);
1572         else if (true_cell == -1) KillOrganism(src_cell, ctx);
1573         return false;
1574       }
1575     }
1576   }
1577 
1578   // movement fails if there are any barrier resources in the faced cell (unless the org is already on a barrier,
1579   // which would happen if we built a new barrier under an org and we need to let it get off)
1580   bool curr_is_barrier = false;
1581   for (int i = 0; i < resource_lib.GetSize(); i++) {
1582     if (resource_lib.GetResource(i)->GetHabitat() == 2 && src_cell_resources[i] > 0) {
1583       curr_is_barrier = true;
1584       break;
1585     }
1586   }
1587   if (!curr_is_barrier) {
1588     for (int i = 0; i < resource_lib.GetSize(); i++) {
1589       if (resource_lib.GetResource(i)->GetHabitat() == 2 && resource_lib.GetResource(i)->GetResistance() != 0) {
1590         // fail if faced cell has this wall resource
1591         if (dest_cell_resources[i] > 0) return false;
1592       }
1593     }
1594   }
1595   // if any of the resources in current cells are hills, find the id of the most resistant resource
1596   int steepest_hill = 0;
1597   double curr_resistance = 1.0;
1598   for (int i = 0; i < resource_lib.GetSize(); i++) {
1599     if (resource_lib.GetResource(i)->GetHabitat() == 1 && src_cell_resources[i] != 0) {
1600       if (resource_lib.GetResource(i)->GetResistance() > curr_resistance) {
1601         curr_resistance = resource_lib.GetResource(i)->GetResistance();
1602         steepest_hill = i;
1603       }
1604     }
1605   }
1606   // apply the chance of move failing for the steepest hill in this cell, if there is a hill at all
1607   if (resource_lib.GetResource(steepest_hill)->GetHabitat() == 1 && src_cell_resources[steepest_hill] > 0) {
1608     // we use resistance to determine chance of movement succeeding: 'resistance == # move instructions executed, on average, to move one step/cell'
1609     int chance_move_success = int(((1/curr_resistance) * 100) + 0.5);
1610     if (ctx.GetRandom().GetInt(0,101) > chance_move_success) return false;
1611   }
1612 
1613   // effects not applied to avatars:
1614   if (true_cell == -1) {
1615     if (m_world->GetConfig().MOVEMENT_COLLISIONS_LETHAL.Get() && dest_cell.IsOccupied()) {
1616       if (m_world->GetConfig().MOVEMENT_COLLISIONS_LETHAL.Get() == 2) return false;
1617       bool kill_source = true;
1618       switch (m_world->GetConfig().MOVEMENT_COLLISIONS_SELECTION_TYPE.Get()) {
1619         case 0: // 50% chance, no modifiers
1620         default:
1621           kill_source = ctx.GetRandom().P(0.5);
1622           break;
1623 
1624         case 1: // binned vitality based on age
1625           double src_vitality = src_cell.GetOrganism()->GetVitality();
1626           double dest_vitality = dest_cell.GetOrganism()->GetVitality();
1627           kill_source = (src_vitality < ctx.GetRandom().GetDouble(src_vitality + dest_vitality));
1628           break;
1629       }
1630       if (kill_source) {
1631         KillOrganism(src_cell, ctx);
1632         // Killing the moving organism means that we shouldn't actually do the swap, so return
1633         return false;
1634       }
1635       KillOrganism(dest_cell, ctx);
1636     }
1637     SwapCells(src_cell_id, dest_cell_id, ctx);
1638 
1639     // Declarations
1640     int actualNeighborhoodSize, fromFacing, destFacing, newFacing, success;
1641 #ifdef DEBBUG
1642     int sID, dID, xx1, yy1, xx2, yy2;
1643 #endif
1644 
1645     // Swap inputs between cells to fix bus error when Avidian moves into an unoccupied cell
1646     // LHZ: Moved to SwapCells function
1647     //environment.SwapInputs(ctx, src_cell.m_inputs, dest_cell.m_inputs);
1648 
1649     // Find neighborhood size for facing
1650     if (NULL != dest_cell.GetOrganism()) {
1651       actualNeighborhoodSize = dest_cell.GetOrganism()->GetNeighborhoodSize();
1652     } else {
1653       if (NULL != src_cell.GetOrganism()) {
1654         actualNeighborhoodSize = src_cell.GetOrganism()->GetNeighborhoodSize();
1655       } else {
1656         // Punt
1657         actualNeighborhoodSize = 8;
1658       }
1659     }
1660 
1661     // Swap cell facings between cells, so that if movement is directed, it continues to be associated with
1662     // the same organism
1663     // Determine absolute facing for each cell
1664     fromFacing = src_cell.GetFacing();
1665     destFacing = dest_cell.GetFacing();
1666 
1667     // Set facing in source cell
1668     success = 0;
1669     newFacing = destFacing;
1670     for(int i = 0; i < actualNeighborhoodSize; i++) {
1671       if (src_cell.GetFacing() != newFacing) {
1672         src_cell.ConnectionList().CircNext();
1673         //cout << "MO: src_cell facing not yet at " << newFacing << endl;
1674       } else {
1675         //cout << "MO: src_cell facing successfully set to " << newFacing << endl;
1676         success = 1;
1677         break;
1678       }
1679     }
1680 
1681     // Set facing in destinatiion cell
1682     success = 0;
1683     newFacing = fromFacing;
1684     for(int i = 0; i < actualNeighborhoodSize; i++) {
1685       if (dest_cell.GetFacing() != newFacing) {
1686         dest_cell.ConnectionList().CircNext();
1687         // cout << "MO: dest_cell facing not yet at " << newFacing << endl;
1688       } else {
1689         // cout << "MO: dest_cell facing successfully set to " << newFacing << endl;
1690         success = 1;
1691         break;
1692       }
1693     }
1694   }
1695   return true;
1696 }
1697 
1698 // Kill Random Organism in Group (But Not Self)!!
KillGroupMember(cAvidaContext & ctx,int group_id,cOrganism * org)1699 void cPopulation::KillGroupMember(cAvidaContext& ctx, int group_id, cOrganism *org)
1700 {
1701   //Check to make sure we are not killing self!
1702   if (group_list[group_id].GetSize() == 1 && group_list[group_id][0] == org) return;
1703   if (group_list[group_id].GetSize() == 0) return;
1704   int index;
1705   while(true) {
1706     index = ctx.GetRandom().GetUInt(group_list[group_id].GetSize());
1707     if (group_list[group_id][index] == org) continue;
1708     else break;
1709   }
1710 
1711   int cell_id = group_list[group_id][index]->GetCellID();
1712   KillOrganism(cell_array[cell_id], ctx);
1713 }
1714 
1715 // Attack organism faced by this one, if there is an organism in front.
AttackFacedOrg(cAvidaContext & ctx,int loser)1716 void cPopulation::AttackFacedOrg(cAvidaContext& ctx, int loser)
1717 {
1718   cPopulationCell& loser_cell = GetCell(loser);
1719   KillOrganism(loser_cell, ctx);
1720 }
1721 
KillOrganism(cPopulationCell & in_cell,cAvidaContext & ctx)1722 void cPopulation::KillOrganism(cPopulationCell& in_cell, cAvidaContext& ctx)
1723 {
1724   // do we actually have something to kill?
1725   if (in_cell.IsOccupied() == false) return;
1726 
1727   // Statistics...
1728   cOrganism* organism = in_cell.GetOrganism();
1729   m_world->GetStats().RecordDeath();
1730 
1731   // orgs killed during birth wont have avatars
1732   if (m_world->GetConfig().USE_AVATARS.Get() && organism->GetOrgInterface().GetAVCellID() != -1) {
1733     organism->GetOrgInterface().RemoveAllAV();
1734   }
1735 
1736   // If neural networking remove all input/output avatars @JJB**
1737   if (m_world->GetConfig().USE_AVATARS.Get() && m_world->GetConfig().NEURAL_NETWORKING.Get()) {
1738     organism->GetOrgInterface().RemoveAllAV();
1739   }
1740 
1741   bool is_prey = true;
1742   if (organism->GetForageTarget() <= -2) is_prey = false;
1743 
1744   RemoveLiveOrg(organism);
1745   UpdateQs(organism, false);
1746 
1747   int cellID = in_cell.GetID();
1748 
1749   organism->NotifyDeath(ctx);
1750 
1751   // @TODO @DMB - this should really move to cOrganism::NotifyDeath
1752   if (m_world->GetConfig().LOG_SLEEP_TIMES.Get() == 1) {
1753     if (sleep_log[cellID].Size() > 0) {
1754       pair<int,int> p = sleep_log[cellID][sleep_log[cellID].Size()-1];
1755       if (p.second == -1) {
1756         AddEndSleep(cellID,m_world->GetStats().GetUpdate());
1757       }
1758     }
1759   }
1760 
1761   // @TODO @DMB - this should really move to cOrganism::NotifyDeath
1762   tList<tListNode<cSaleItem> >* sold_items = organism->GetSoldItems();
1763   if (sold_items)
1764   {
1765     tListIterator<tListNode<cSaleItem> > sold_it(*sold_items);
1766     tListNode<cSaleItem> * test_node;
1767 
1768     while ( (test_node = sold_it.Next()) != NULL)
1769     {
1770       tListIterator<cSaleItem> market_it(market[test_node->data->GetLabel()]);
1771       market_it.Set(test_node);
1772       delete market_it.Remove();
1773     }
1774   }
1775 
1776   // Update count statistics...
1777   num_organisms--;
1778   if (m_world->GetConfig().PRED_PREY_SWITCH.Get() == -2 || m_world->GetConfig().PRED_PREY_SWITCH.Get() > -1) {
1779     if (is_prey) num_prey_organisms--;
1780     else num_pred_organisms--;
1781   }
1782 
1783   // Handle deme updates.
1784   if (deme_array.GetSize() > 0) {
1785     deme_array[in_cell.GetDemeID()].DecOrgCount();
1786     deme_array[in_cell.GetDemeID()].OrganismDeath(in_cell);
1787   }
1788 
1789   // If HGT is turned on and there's a possibility of natural competence,
1790 	// this organism's genome needs to be split up into fragments
1791   // and deposited in its cell.  We then also have to add the size of this genome to
1792   // the HGT resource.
1793   if (m_world->GetConfig().ENABLE_HGT.Get()
1794 		 && (m_world->GetConfig().HGT_COMPETENCE_P.Get() > 0.0)) {
1795     in_cell.AddGenomeFragments(ctx, organism->GetGenome().GetSequence());
1796   }
1797 
1798   // And clear it!
1799   in_cell.RemoveOrganism(ctx);
1800   if (!organism->IsRunning()) delete organism;
1801   else organism->GetPhenotype().SetToDelete();
1802 
1803   // Alert the scheduler that this cell has a 0 merit.
1804   AdjustSchedule(in_cell, cMerit(0));
1805 }
1806 
Kaboom(cPopulationCell & in_cell,cAvidaContext & ctx,int distance)1807 void cPopulation::Kaboom(cPopulationCell& in_cell, cAvidaContext& ctx, int distance)
1808 {
1809   m_world->GetStats().IncKaboom();
1810   m_world->GetStats().AddHamDistance(distance);
1811   cOrganism* organism = in_cell.GetOrganism();
1812   cString ref_genome = organism->GetGenome().GetSequence().AsString();
1813   int bgid = organism->GetBioGroup("genotype")->GetID();
1814 
1815   int radius = 2;
1816 
1817   for (int i = -1 * radius; i <= radius; i++) {
1818     for (int j = -1 * radius; j <= radius; j++) {
1819       cPopulationCell& death_cell = cell_array[GridNeighbor(in_cell.GetID(), world_x, world_y, i, j)];
1820 
1821       //do we actually have something to kill?
1822       if (death_cell.IsOccupied() == false) continue;
1823 
1824         m_world->GetStats().IncKaboomKills();
1825       cOrganism* org_temp = death_cell.GetOrganism();
1826 
1827       if (distance == 0) {
1828         int temp_id = org_temp->GetBioGroup("genotype")->GetID();
1829         if (temp_id != bgid) KillOrganism(death_cell, ctx);
1830       } else {
1831         cString genome_temp = org_temp->GetGenome().GetSequence().AsString();
1832         int diff = 0;
1833         for (int i = 0; i < genome_temp.GetSize(); i++) if (genome_temp[i] != ref_genome[i]) diff++;
1834         if (diff > distance) KillOrganism(death_cell, ctx);
1835       }
1836     }
1837   }
1838   KillOrganism(in_cell, ctx);
1839   // @SLG my prediction = 92% and, 28 get equals
1840 }
1841 
AddSellValue(const int data,const int label,const int sell_price,const int org_id,const int cell_id)1842 void cPopulation::AddSellValue(const int data, const int label, const int sell_price, const int org_id, const int cell_id)
1843 {
1844   // find list under appropriate label, labels more than 8 nops long are simply the same
1845   // as a smaller label modded by the market size
1846   //int pos = label % market.GetSize();
1847 
1848   //// id of genotype currently residing in cell that seller live(d) in compared to
1849   //// id of genotype of actual seller, if different than seller is dead, remove item from list
1850   //while ( market[pos].GetSize() > 0 &&
1851   //	(!GetCell(market[pos].GetFirst()->GetCellID()).IsOccupied() ||
1852   //	GetCell(market[pos].GetFirst()->GetCellID()).GetOrganism()->GetID()
1853   //	!= 	market[pos].GetFirst()->GetOrgID()) )
1854   //{
1855   //	market[pos].Pop();
1856   //}
1857 
1858   // create sale item
1859   cSaleItem *new_item = new cSaleItem(data, label, sell_price, org_id, cell_id);
1860 
1861   // place into array by label, array is big enough for labels up to 8 nops long
1862   tListNode<cSaleItem>* sell_node = market[label].PushRear(new_item);
1863   tListNode<tListNode<cSaleItem> >* org_node = GetCell(cell_id).GetOrganism()->AddSoldItem(sell_node);
1864   sell_node->data->SetNodePtr(org_node);
1865 
1866   //:7 for Kolby
1867 }
1868 
BuyValue(const int label,const int buy_price,const int cell_id)1869 int cPopulation::BuyValue(const int label, const int buy_price, const int cell_id)
1870 {
1871   // find list under appropriate label, labels more than 8 nops long are simply the same
1872   // as a smaller label modded by the market size
1873   //int pos = label % market.GetSize();
1874 
1875   //// id of genotype currently residing in cell that seller live(d) in compared to
1876   //// id of genotype of actual seller, if different than seller is dead, remove item from list
1877   //while ( market[pos].GetSize() > 0 &&
1878   //	(!GetCell(market[pos].GetFirst()->GetCellID()).IsOccupied() ||
1879   //	GetCell(market[pos].GetFirst()->GetCellID()).GetOrganism()->GetID()
1880   //	!= 	market[pos].GetFirst()->GetOrgID()) )
1881   //{
1882   //	market[pos].Pop();
1883   //}
1884 
1885   // if there's nothing in the list don't bother with rest
1886   if (market[label].GetSize() <= 0)
1887     return 0;
1888 
1889   // if the sell price is higher than we're willing to pay no purchase made
1890   if (market[label].GetFirst()->GetPrice() > buy_price)
1891     return 0;
1892 
1893   // if the buy price is higher than buying org's current merit no purchase made
1894   if (GetCell(cell_id).GetOrganism()->GetPhenotype().GetMerit().GetDouble() < buy_price)
1895     return 0;
1896 
1897   // otherwise transaction should be completed!
1898   cSaleItem* chosen = market[label].Pop();
1899   tListIterator<tListNode<cSaleItem> > sold_it(*GetCell(chosen->GetCellID()).GetOrganism()->GetSoldItems());
1900   sold_it.Set(chosen->GetNodePtr());
1901   sold_it.Remove();
1902 
1903   // first update sellers merit
1904   double cur_merit = GetCell(chosen->GetCellID()).GetOrganism()->GetPhenotype().GetMerit().GetDouble();
1905   cur_merit += buy_price;
1906 
1907   GetCell(chosen->GetCellID()).GetOrganism()->UpdateMerit(cur_merit);
1908 
1909   // next remove sold item from list in market
1910   //market[pos].Remove(chosen);
1911 
1912 
1913   // finally return recieve value, buyer merit will be updated if return a valid value here
1914   int receive_value = chosen->GetData();
1915   return receive_value;
1916 }
1917 
SwapCells(int cell_id1,int cell_id2,cAvidaContext & ctx)1918 void cPopulation::SwapCells(int cell_id1, int cell_id2, cAvidaContext& ctx)
1919 {
1920   // Sanity checks: Don't process if the cells are the same
1921   if (cell_id1 == cell_id2) return;
1922 
1923   cPopulationCell& cell1 = GetCell(cell_id1);
1924   cPopulationCell& cell2 = GetCell(cell_id2);
1925 
1926   // Clear current contents of cells
1927   cOrganism* org1 = cell1.RemoveOrganism(ctx);
1928   cOrganism* org2 = cell2.RemoveOrganism(ctx);
1929 
1930   if (org2 != NULL) {
1931     cell1.InsertOrganism(org2, ctx);
1932     AdjustSchedule(cell1, org2->GetPhenotype().GetMerit());
1933   } else {
1934     AdjustSchedule(cell1, cMerit(0));
1935   }
1936 
1937   if (org1 != NULL) {
1938     cell2.InsertOrganism(org1, ctx);
1939     cell2.IncVisits();  // Increment visit count
1940     AdjustSchedule(cell2, org1->GetPhenotype().GetMerit());
1941   } else {
1942     AdjustSchedule(cell2, cMerit(0));
1943   }
1944 
1945   //LHZ: Take organism imputs from the PopulationCell along with the organisms
1946   environment.SwapInputs(ctx, cell1.m_inputs, cell2.m_inputs);
1947 
1948 }
1949 
1950 // CompeteDemes  probabilistically copies demes into the next generation
1951 // based on their fitness. How deme fitness is estimated is specified by
1952 // competition_type input argument as:
1953 /*
1954  0: deme fitness = 1 (control, random deme selection)
1955  1: deme fitness = number of births since last competition (default)
1956  2: deme fitness = average organism fitness at the current update (uses parent's fitness, so
1957  does not work with donations)
1958  3: deme fitness = average mutation rate at the current update
1959  4: deme fitness = strong rank selection on (parents) fitness (2^-deme fitness rank)
1960  5: deme fitness = average organism life (current, not parents) fitness (works with donations)
1961  6: deme fitness = strong rank selection on life (current, not parents) fitness
1962  */
1963 //  For ease of use, each organism
1964 // is setup as if it we just injected into the population.
1965 
CompeteDemes(cAvidaContext & ctx,int competition_type)1966 void cPopulation::CompeteDemes(cAvidaContext& ctx, int competition_type)
1967 {
1968   const int num_demes = deme_array.GetSize();
1969 
1970   double total_fitness = 0;
1971   tArray<double> deme_fitness(num_demes);
1972 
1973   switch(competition_type) {
1974     case 0:    // deme fitness = 1;
1975       total_fitness = (double) num_demes;
1976       deme_fitness.SetAll(1);
1977       break;
1978     case 1:     // deme fitness = number of births
1979       // Determine the scale for fitness by totaling births across demes.
1980       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
1981         double cur_fitness = (double) deme_array[deme_id].GetBirthCount();
1982         deme_fitness[deme_id] = cur_fitness;
1983         total_fitness += cur_fitness;
1984       }
1985       break;
1986     case 2:    // deme fitness = average organism fitness at the current update
1987       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
1988         cDoubleSum single_deme_fitness;
1989         const cDeme & cur_deme = deme_array[deme_id];
1990         for (int i = 0; i < cur_deme.GetSize(); i++) {
1991           int cur_cell = cur_deme.GetCellID(i);
1992           if (cell_array[cur_cell].IsOccupied() == false) continue;
1993           cPhenotype & phenotype =
1994           GetCell(cur_cell).GetOrganism()->GetPhenotype();
1995           single_deme_fitness.Add(phenotype.GetFitness());
1996         }
1997         deme_fitness[deme_id] = single_deme_fitness.Ave();
1998         total_fitness += deme_fitness[deme_id];
1999       }
2000       break;
2001     case 3: 	// deme fitness = average mutation rate at the current update
2002       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2003         cDoubleSum single_deme_div_type;
2004         const cDeme & cur_deme = deme_array[deme_id];
2005         for (int i = 0; i < cur_deme.GetSize(); i++) {
2006           int cur_cell = cur_deme.GetCellID(i);
2007           if (cell_array[cur_cell].IsOccupied() == false) continue;
2008           cPhenotype & phenotype =
2009           GetCell(cur_cell).GetOrganism()->GetPhenotype();
2010           assert(phenotype.GetDivType()>0);
2011           single_deme_div_type.Add(1/phenotype.GetDivType());
2012         }
2013         deme_fitness[deme_id] = single_deme_div_type.Ave();
2014         total_fitness += deme_fitness[deme_id];
2015       }
2016       break;
2017     case 4: 	// deme fitness = 2^(-deme fitness rank)
2018       // first find all the deme fitness values ...
2019     {
2020       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2021         cDoubleSum single_deme_fitness;
2022         const cDeme & cur_deme = deme_array[deme_id];
2023         for (int i = 0; i < cur_deme.GetSize(); i++) {
2024           int cur_cell = cur_deme.GetCellID(i);
2025           if (cell_array[cur_cell].IsOccupied() == false) continue;
2026           cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
2027           single_deme_fitness.Add(phenotype.GetFitness());
2028         }
2029         deme_fitness[deme_id] = single_deme_fitness.Ave();
2030       }
2031       // ... then determine the rank of each deme based on its fitness
2032       tArray<double> deme_rank(num_demes);
2033       deme_rank.SetAll(1);
2034       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2035         for (int test_deme = 0; test_deme < num_demes; test_deme++) {
2036           if (deme_fitness[deme_id] < deme_fitness[test_deme]) {
2037             deme_rank[deme_id]++;
2038           }
2039         }
2040       }
2041       // ... finally, make deme fitness 2^(-deme rank)
2042       deme_fitness.SetAll(1);
2043       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2044         for (int i = 0; i < deme_rank[deme_id]; i++) {
2045           deme_fitness[deme_id] = deme_fitness[deme_id]/2;
2046         }
2047         total_fitness += deme_fitness[deme_id];
2048       }
2049     }
2050       break;
2051     case 5:    // deme fitness = average organism life fitness at the current update
2052       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2053         cDoubleSum single_deme_life_fitness;
2054         const cDeme & cur_deme = deme_array[deme_id];
2055         for (int i = 0; i < cur_deme.GetSize(); i++) {
2056           int cur_cell = cur_deme.GetCellID(i);
2057           if (cell_array[cur_cell].IsOccupied() == false) continue;
2058           cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
2059           single_deme_life_fitness.Add(phenotype.GetLifeFitness());
2060         }
2061         deme_fitness[deme_id] = single_deme_life_fitness.Ave();
2062         total_fitness += deme_fitness[deme_id];
2063       }
2064       break;
2065     case 6:     // deme fitness = 2^(-deme life fitness rank) (same as 4, but with life fitness)
2066       // first find all the deme fitness values ...
2067     {
2068       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2069         cDoubleSum single_deme_life_fitness;
2070         const cDeme & cur_deme = deme_array[deme_id];
2071         for (int i = 0; i < cur_deme.GetSize(); i++) {
2072           int cur_cell = cur_deme.GetCellID(i);
2073           if (cell_array[cur_cell].IsOccupied() == false) continue;
2074           cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
2075           single_deme_life_fitness.Add(phenotype.GetLifeFitness());
2076         }
2077         deme_fitness[deme_id] = single_deme_life_fitness.Ave();
2078       }
2079       // ... then determine the rank of each deme based on its fitness
2080       tArray<double> deme_rank(num_demes);
2081       deme_rank.SetAll(1);
2082       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2083         for (int test_deme = 0; test_deme < num_demes; test_deme++) {
2084           if (deme_fitness[deme_id] < deme_fitness[test_deme]) {
2085             deme_rank[deme_id]++;
2086           }
2087         }
2088       }
2089       // ... finally, make deme fitness 2^(-deme rank)
2090       deme_fitness.SetAll(1);
2091       for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2092         for (int i = 0; i < deme_rank[deme_id]; i++) {
2093           deme_fitness[deme_id] = deme_fitness[deme_id]/2;
2094         }
2095         total_fitness += deme_fitness[deme_id];
2096       }
2097     }
2098       break;
2099   }
2100 
2101   // Pick which demes should be in the next generation.
2102   tArray<int> new_demes(num_demes);
2103   for (int i = 0; i < num_demes; i++) {
2104     double birth_choice = (double) m_world->GetRandom().GetDouble(total_fitness);
2105     double test_total = 0;
2106     for (int test_deme = 0; test_deme < num_demes; test_deme++) {
2107       test_total += deme_fitness[test_deme];
2108       if (birth_choice < test_total) {
2109         new_demes[i] = test_deme;
2110         break;
2111       }
2112     }
2113   }
2114 
2115   // Track how many of each deme we should have.
2116   tArray<int> deme_count(num_demes);
2117   deme_count.SetAll(0);
2118   for (int i = 0; i < num_demes; i++) {
2119     deme_count[new_demes[i]]++;
2120   }
2121 
2122   tArray<bool> is_init(num_demes);
2123   is_init.SetAll(false);
2124 
2125   // Copy demes until all deme counts are 1.
2126   while (true) {
2127     // Find the next deme to copy...
2128     int from_deme_id, to_deme_id;
2129     for (from_deme_id = 0; from_deme_id < num_demes; from_deme_id++) {
2130       if (deme_count[from_deme_id] > 1) break;
2131     }
2132 
2133     // Stop If we didn't find another deme to copy
2134     if (from_deme_id == num_demes) break;
2135 
2136     for (to_deme_id = 0; to_deme_id < num_demes; to_deme_id++) {
2137       if (deme_count[to_deme_id] == 0) break;
2138     }
2139 
2140     // We now have both a from and a to deme....
2141     deme_count[from_deme_id]--;
2142     deme_count[to_deme_id]++;
2143 
2144     cDeme& from_deme = deme_array[from_deme_id];
2145     cDeme& to_deme   = deme_array[to_deme_id];
2146 
2147     // Ideally, the below bit of code would be replaced with a call to ReplaceDeme:
2148     // ReplaceDeme(from_deme, to_deme);
2149     //
2150     // But, use of InjectClone messes that up, breaking consistency.  So the next
2151     // time that someone comes in here looking to refactor, consider fixing this.
2152 
2153     // Do the actual copy!
2154     for (int i = 0; i < from_deme.GetSize(); i++) {
2155       int from_cell_id = from_deme.GetCellID(i);
2156       int to_cell_id = to_deme.GetCellID(i);
2157       if (cell_array[from_cell_id].IsOccupied() == true) {
2158         InjectClone(to_cell_id, *(cell_array[from_cell_id].GetOrganism()), SRC_DEME_COMPETE);
2159       }
2160     }
2161     is_init[to_deme_id] = true;
2162   }
2163 
2164   // Now re-inject all remaining demes into themselves to reset them.
2165   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2166     if (is_init[deme_id] == true) continue;
2167     cDeme & cur_deme = deme_array[deme_id];
2168 
2169     for (int i = 0; i < cur_deme.GetSize(); i++) {
2170       int cur_cell_id = cur_deme.GetCellID(i);
2171       if (cell_array[cur_cell_id].IsOccupied() == false) continue;
2172       InjectClone(cur_cell_id, *(cell_array[cur_cell_id].GetOrganism()), cell_array[cur_cell_id].GetOrganism()->GetUnitSource());
2173     }
2174   }
2175 
2176   // Reset all deme stats to zero.
2177   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
2178     deme_array[deme_id].Reset(ctx, deme_array[deme_id].GetGeneration()); // increase deme generation by 1
2179   }
2180 }
2181 
2182 
2183 /*! Compete all demes with each other based on the given vector of fitness values.
2184 
2185  This form of compete demes supports both fitness-proportional selection and a
2186  variant of tournament selection.  It integrates with the various deme replication options
2187  used in ReplicateDemes.
2188 
2189  Note: New deme competition fitness functions are added in PopulationActions.cc by subclassing
2190  cActionAbstractCompeteDemes and overriding cActionAbstractCompeteDemes::Fitness(cDeme&).  (Don't forget
2191  to register the action and add it to the events file).
2192 
2193  Another note: To mimic the behavior of the other version of CompeteDemes (which is kept around
2194  for backwards compatibility), change the config option DEMES_REPLICATE_SIZE to be the size of
2195  each deme.
2196  */
CompeteDemes(const std::vector<double> & calculated_fitness,cAvidaContext & ctx)2197 void cPopulation::CompeteDemes(const std::vector<double>& calculated_fitness, cAvidaContext& ctx) {
2198   // it's possible that we'll be changing the fitness values of some demes, so make a copy:
2199   std::vector<double> fitness(calculated_fitness);
2200 
2201   // Each deme must have a fitness:
2202   assert((int)fitness.size() == deme_array.GetSize());
2203 
2204   // To prevent sterile demes from replicating, we're going to replace the fitness
2205   // of all sterile demes with 0; this effectively makes it impossible for a sterile
2206   // deme to be selected via fitness proportional selection.
2207   if (m_world->GetConfig().DEMES_PREVENT_STERILE.Get()) {
2208     for(int i=0; i<deme_array.GetSize(); ++i) {
2209       if (deme_array[i].GetBirthCount() == 0) {
2210         fitness[i] = 0.0;
2211       }
2212     }
2213   }
2214 
2215   // Stat-tracking:
2216   m_world->GetStats().CompeteDemes(fitness);
2217 
2218   // This is to facilitate testing.  Obviously we can't do competition if there's
2219   // only one deme, but we do want the stat-tracking.
2220   if (fitness.size() == 1) {
2221     return;
2222   }
2223 
2224   // to facilitate control runs, sometimes we want to know what the fitness values
2225   // are, but we don't want competition to depend on them.
2226   if (m_world->GetConfig().DEMES_OVERRIDE_FITNESS.Get()) {
2227     for(int i=0; i<static_cast<int>(fitness.size()); ++i) {
2228       fitness[i] = 1.0;
2229     }
2230   }
2231 
2232   // Number of demes (at index) which should wind up in the next generation.
2233   std::vector<unsigned int> deme_counts(deme_array.GetSize(), 0);
2234   // Now, compete all demes based on the competition style.
2235   switch(m_world->GetConfig().DEMES_COMPETITION_STYLE.Get()) {
2236     case SELECTION_TYPE_PROPORTIONAL: {
2237       // Fitness-proportional selection.
2238       // Each deme has a probability equal to its fitness / sum(deme fitnesses)
2239       // of proceeding to the next generation.
2240 
2241       const double total_fitness = std::accumulate(fitness.begin(), fitness.end(), 0.0);
2242       assert(total_fitness > 0.0); // Must have *some* positive fitnesses...
2243 
2244       // Sum up the fitnesses until we reach or exceed the target fitness.
2245       // Then we're marking that deme as being part of the next generation.
2246       for (int i=0; i<deme_array.GetSize(); ++i) {
2247         double running_sum = 0.0;
2248         double target_sum = m_world->GetRandom().GetDouble(total_fitness);
2249         for (int j=0; j<deme_array.GetSize(); ++j) {
2250           running_sum += fitness[j];
2251           if (running_sum >= target_sum) {
2252             // j'th deme will be replicated.
2253             ++deme_counts[j];
2254             break;
2255           }
2256         }
2257       }
2258       break;
2259     }
2260     case SELECTION_TYPE_TOURNAMENT: {
2261       // Tournament selection.
2262       //
2263       // We run NUM_DEMES tournaments of size DEME_TOURNAMENT_SIZE, and select the
2264       // **single** winner of the tournament to proceed to the next generation.
2265 
2266       // construct a list of all possible deme ids that could participate in a tournament,
2267       // pruning out sterile and empty demes:
2268       std::vector<int> deme_ids;
2269       for (int i=0; i<deme_array.GetSize(); ++i) {
2270         if ((deme_array[i].GetOrgCount() > 0) &&
2271             (!m_world->GetConfig().DEMES_PREVENT_STERILE.Get() ||
2272              (deme_array[i].GetBirthCount() > 0))) {
2273               deme_ids.push_back(i);
2274             }
2275       }
2276 
2277       // better have more than deme tournament size, otherwise something is *really* screwed up:
2278       if (m_world->GetConfig().DEMES_TOURNAMENT_SIZE.Get() > static_cast<int>(deme_ids.size())) {
2279         m_world->GetDriver().RaiseFatalException(-1,
2280                                                  "Number of demes available to participate in a tournament < the deme tournament size.");
2281       }
2282 
2283       // Run the tournaments.
2284       for (int i=0; i<m_world->GetConfig().NUM_DEMES.Get(); ++i) {
2285         // Which demes are in this tournament?
2286         std::vector<int> tournament(m_world->GetConfig().DEMES_TOURNAMENT_SIZE.Get());
2287         sample_without_replacement(deme_ids.begin(), deme_ids.end(),
2288                                    tournament.begin(), tournament.end(),
2289                                    cRandomStdAdaptor(m_world->GetRandom()));
2290 
2291         // Now, iterate through the fitnesses of each of the tournament players,
2292         // capturing the winner's index and fitness.
2293         //
2294         // If no deme actually won, meaning no one had fitness greater than 0.0,
2295         // then the winner is selected at random from the tournament.
2296         std::pair<int, double> winner(tournament[m_world->GetRandom().GetInt(tournament.size())], 0.0);
2297         for(std::vector<int>::iterator j=tournament.begin(); j!=tournament.end(); ++j) {
2298           if (fitness[*j] > winner.second) {
2299             winner = std::make_pair(*j, fitness[*j]);
2300           }
2301         }
2302 
2303         // We have a winner!  Increment his replication count.
2304         ++deme_counts[winner.first];
2305       }
2306       break;
2307     }
2308     default: {
2309       // should never get here.
2310       assert(false);
2311     }
2312   }
2313 
2314   // Housekeeping: re-inject demes with count of 1 back into self (energy-related).
2315   for (int i = 0; i < (int)deme_counts.size(); i++) {
2316     if (deme_counts[i] == 1)
2317       ReplaceDeme(deme_array[i], deme_array[i], ctx);
2318   }
2319 
2320   // Ok, the below algorithm relies upon the fact that we have a strict weak ordering
2321   // of fitness values for all demes.  We're going to loop through, find demes with a
2322   // count greater than one, and insert them into demes with a count of zero.
2323   while (true) {
2324     int source_id=0;
2325     for(; source_id<(int)deme_counts.size(); ++source_id) {
2326       if (deme_counts[source_id] > 1) {
2327         --deme_counts[source_id];
2328         break;
2329       }
2330     }
2331 
2332     if (source_id == (int)deme_counts.size()) {
2333       break; // All done; we looped through the whole list of counts, and didn't find any > 1.
2334     }
2335 
2336     int target_id=0;
2337     for(; target_id<(int)deme_counts.size(); ++target_id) {
2338       if (deme_counts[target_id] == 0) {
2339         ++deme_counts[target_id];
2340         break;
2341       }
2342     }
2343 
2344     assert(source_id < deme_array.GetSize());
2345     assert(target_id < deme_array.GetSize());
2346     assert(source_id != target_id);
2347 
2348     // Replace the target with a copy of the source:
2349     ReplaceDeme(deme_array[source_id], deme_array[target_id], ctx);
2350   }
2351 }
2352 
2353 
2354 /* Check if any demes have met the critera to be replicated and do so.
2355  There are several bases this can be checked on:
2356 
2357  0: 'all'       - ...all non-empty demes in the population.
2358  1: 'full_deme' - ...demes that have been filled up.
2359  2: 'corners'   - ...demes with upper left and lower right corners filled.
2360  3: 'deme-age'  - ...demes who have reached their maximum age
2361  4: 'birth-count' ...demes that have had a certain number of births.
2362  5: 'sat-mov-pred'...demes whose movement predicate was previously satisfied
2363  6: 'events-killed' ...demes that have killed a certian number of events
2364  7: 'sat-msg-pred'...demes whose movement predicate was previously satisfied
2365  8: 'sat-deme-predicate'...demes whose predicate has been satisfied; does not include movement or message predicates as those are organisms-level
2366  9: 'perf-reactions' ...demes that have performed X number of each task are replicated
2367  10:'consume-res' ...demes that have consumed a sufficienct amount of resources
2368  */
ReplicateDemes(int rep_trigger,cAvidaContext & ctx)2369 void cPopulation::ReplicateDemes(int rep_trigger, cAvidaContext& ctx)
2370 {
2371   assert(GetNumDemes()>1); // Sanity check.
2372 
2373   // Loop through all candidate demes...
2374   const int num_demes = GetNumDemes();
2375   for (int deme_id=0; deme_id<num_demes; ++deme_id) {
2376     cDeme& source_deme = deme_array[deme_id];
2377 
2378     // Test this deme to determine if it should be replicated.  If not,
2379     // continue on to the next deme.
2380     switch (rep_trigger) {
2381       case DEME_TRIGGER_ALL: {
2382         // Replicate all non-empty demes.
2383         if (source_deme.IsEmpty()) continue;
2384         break;
2385       }
2386       case DEME_TRIGGER_FULL: {
2387         // Replicate all full demes.
2388         if (!source_deme.IsFull()) continue;
2389         break;
2390       }
2391       case DEME_TRIGGER_CORNERS: {
2392         // Replicate all demes with the corners filled in.
2393         // The first and last IDs represent the two corners.
2394         const int id1 = source_deme.GetCellID(0);
2395         const int id2 = source_deme.GetCellID(source_deme.GetSize() - 1);
2396         if (cell_array[id1].IsOccupied() == false ||
2397             cell_array[id2].IsOccupied() == false) continue;
2398         break;
2399       }
2400       case DEME_TRIGGER_AGE: {
2401         // Replicate old demes.
2402         if (source_deme.GetAge() < m_world->GetConfig().DEMES_MAX_AGE.Get()) continue;
2403         break;
2404       }
2405       case DEME_TRIGGER_BIRTHS: {
2406         // Replicate demes that have had a certain number of births.
2407         if (source_deme.GetBirthCount() < m_world->GetConfig().DEMES_MAX_BIRTHS.Get()) continue;
2408         break;
2409       }
2410       case DEME_TRIGGER_MOVE_PREDATORS: {
2411         if (!(source_deme.MovPredSatisfiedPreviously())) continue;
2412         break;
2413       }
2414       case DEME_TRIGGER_GROUP_KILL: {
2415         int currentSlotSuccessful = 0;
2416         double kill_ratio = 0.0;
2417 
2418         if (source_deme.GetSlotFlowRate() == 0) {
2419           kill_ratio = 1.0;
2420         } else {
2421           kill_ratio = static_cast<double>(source_deme.GetEventsKilledThisSlot()) /
2422           static_cast<double>(source_deme.GetSlotFlowRate());
2423         }
2424 
2425         if (kill_ratio >= m_world->GetConfig().DEMES_MIM_EVENTS_KILLED_RATIO.Get()) {
2426           currentSlotSuccessful = 1;
2427         }
2428 
2429         // Replicate demes that have killed a certain number of event.
2430         if (source_deme.GetConsecutiveSuccessfulEventPeriods() + currentSlotSuccessful
2431             < m_world->GetConfig().DEMES_MIM_SUCCESSFUL_EVENT_PERIODS.Get()) {
2432           continue;
2433         }
2434         break;
2435       }
2436       case DEME_TRIGGER_MESSAGE_PREDATORS: {
2437         if (!(source_deme.MsgPredSatisfiedPreviously())) continue;
2438         break;
2439       }
2440       case DEME_TRIGGER_PREDICATE: {
2441         if (!(source_deme.DemePredSatisfiedPreviously())) continue;
2442         break;
2443       }
2444       case DEME_TRIGGER_PERFECT_REACTIONS: {
2445         // loop through each reaction. Make sure each has been performed X times.
2446         if (source_deme.MinNumTimesReactionPerformed() < m_world->GetConfig().REACTION_THRESH.Get()) {
2447           continue;
2448         }
2449         break;
2450       }
2451       case DEME_TRIGGER_CONSUME_RESOURCES: {
2452         // check how many resources have been consumed by the deme
2453         if (source_deme.GetTotalResourceAmountConsumed() <
2454             m_world->GetConfig().RES_FOR_DEME_REP.Get()) {
2455           continue;
2456         }
2457         break;
2458       }
2459       default: {
2460         cerr << "ERROR: Invalid replication trigger " << rep_trigger
2461         << " in cPopulation::ReplicateDemes()" << endl;
2462         assert(false);
2463       }
2464     }
2465 
2466     ReplicateDeme(source_deme, ctx);
2467   }
2468 }
2469 
2470 
2471 /*! ReplicateDeme is a helper method for replicating a source deme.
2472  */
ReplicateDeme(cDeme & source_deme,cAvidaContext & ctx)2473 void cPopulation::ReplicateDeme(cDeme& source_deme, cAvidaContext& ctx)
2474 {
2475   // Doesn't make sense to try and replicate a deme that *has no organisms*.
2476   if (source_deme.IsEmpty()) return;
2477 
2478 	source_deme.UpdateShannonAll();
2479 
2480   // Prevent sterile demes from replicating.
2481   if (m_world->GetConfig().DEMES_PREVENT_STERILE.Get() && (source_deme.GetBirthCount() == 0)) {
2482     // assumes that all group level tasks cannot be solved by a single organism
2483     source_deme.KillAll(ctx);
2484     return;
2485   }
2486 
2487   // Update stats calculate how many different reactions the deme performed.
2488   double deme_performed_rx=0;
2489   tArray<int> deme_reactions = source_deme.GetCurReactionCount();
2490   for(int i=0; i< deme_reactions.GetSize(); ++i) {
2491     //HJG
2492     if (deme_reactions[i] > 0){
2493       deme_performed_rx++;
2494     }
2495   }
2496 
2497   // calculate how many penalties were accrued by the orgs on average
2498   double switch_penalties = source_deme.GetNumSwitchingPenalties();
2499   double num_orgs_perf_reaction = source_deme.GetNumOrgsPerformedReaction();
2500   double shannon_div = source_deme.GetShannonMutualInformation();
2501   double per_reproductives = source_deme.GetPercentReproductives();
2502 
2503   if (switch_penalties > 0) {
2504     switch_penalties = (switch_penalties)/(source_deme.GetInjectedCount() + source_deme.GetBirthCount());
2505   }
2506 
2507 
2508   m_world->GetStats().IncDemeReactionDiversityReplicationData(deme_performed_rx, switch_penalties, shannon_div, num_orgs_perf_reaction, per_reproductives);
2509 
2510   //Option to bridge between kin and group selection.
2511   if (m_world->GetConfig().DEMES_REPLICATION_ONLY_RESETS.Get()) {
2512     //Reset deme (resources and births, among other things)
2513     bool source_deme_resource_reset = m_world->GetConfig().DEMES_RESET_RESOURCES.Get() == 0;
2514     source_deme.DivideReset(ctx, source_deme, source_deme_resource_reset);
2515 
2516     //Reset all organisms in deme, by re-injecting them?
2517     if (m_world->GetConfig().DEMES_REPLICATION_ONLY_RESETS.Get() == 2) {
2518       for (int i=0; i<source_deme.GetSize(); i++) {
2519         int cellid = source_deme.GetCellID(i);
2520         if (GetCell(cellid).IsOccupied()) {
2521           int lineage = GetCell(cellid).GetOrganism()->GetLineageLabel();
2522           const Genome& genome = GetCell(cellid).GetOrganism()->GetGenome();
2523           InjectGenome(cellid, SRC_DEME_REPLICATE, genome, ctx, lineage);
2524         }
2525       }
2526     }
2527     return;
2528   }
2529 
2530   // Pick a target deme to replicate to, making sure that
2531   // we don't try to replicate over ourself, i.e. DEMES_REPLACE_PARENT 0
2532 
2533   int target_id = -1;
2534   if (m_world->GetConfig().DEMES_PREFER_EMPTY.Get()) {
2535 
2536     //@JEB -- use empty_cell_id_array to hold empty demes
2537     //so we don't have to allocate a list
2538     int num_empty = 0;
2539     for (int i=0; i<GetNumDemes(); i++) {
2540       if (GetDeme(i).IsEmpty()) {
2541         empty_cell_id_array[num_empty] = i;
2542         num_empty++;
2543       }
2544     }
2545     if (num_empty > 0) {
2546       target_id = empty_cell_id_array[m_world->GetRandom().GetUInt(num_empty)];
2547     }
2548   }
2549 
2550   // if we haven't found one yet, choose a random one
2551   if (target_id == -1) {
2552     target_id = source_deme.GetID();
2553     const int num_demes = GetNumDemes();
2554     while(target_id == source_deme.GetID()) {
2555       target_id = m_world->GetRandom().GetUInt(num_demes);
2556     }
2557   }
2558 
2559   // Write some logging information if LOG_DEMES_REPLICATE is set.
2560   if ( (m_world->GetConfig().LOG_DEMES_REPLICATE.Get() == 1) &&
2561       (m_world->GetStats().GetUpdate() >= m_world->GetConfig().DEMES_REPLICATE_LOG_START.Get()) ) {
2562     cString tmpfilename = cStringUtil::Stringf("deme_replication.dat");
2563     cDataFile& df = m_world->GetDataFile(tmpfilename);
2564 
2565     cString UpdateStr = cStringUtil::Stringf("%d,%d,%d",
2566                                              m_world->GetStats().GetUpdate(),
2567                                              source_deme.GetDemeID(), target_id);
2568     df.WriteRaw(UpdateStr);
2569   }
2570 
2571   if (m_world->GetConfig().DEMES_USE_GERMLINE.Get() == 3) {
2572     // hjg - this hack is decidedly ugly. However, the current ReplaceDemes method
2573     // does some strange things to support the energy model (such as resetting demes prior
2574     // to assessing whether the replication will work) that cause strange behavior as
2575     // part of the germ line sequestration code.
2576     ReplaceDemeFlaggedGermline(source_deme, deme_array[target_id], ctx);
2577   } else {
2578     ReplaceDeme(source_deme, deme_array[target_id], ctx);
2579   }
2580 
2581 }
2582 
2583 /*! ReplaceDeme is a helper method that handles all the different configuration
2584  options related to the replacement of a target deme by a source.  It works with
2585  both CompeteDemes and ReplicateDemes (and can be called directly via an event if
2586  so desired).
2587 
2588  @refactor Replace manual mutation with strategy pattern.
2589  */
ReplaceDeme(cDeme & source_deme,cDeme & target_deme,cAvidaContext & ctx2)2590 void cPopulation::ReplaceDeme(cDeme& source_deme, cDeme& target_deme, cAvidaContext& ctx2)
2591 {
2592   // Stats tracking; pre-replication hook.
2593   m_world->GetStats().DemePreReplication(source_deme, target_deme);
2594 
2595   // used to pass energy to offspring demes (set to zero if energy model is not enabled)
2596   double source_deme_energy(0.0), deme_energy_decay(0.0), parent_deme_energy(0.0), offspring_deme_energy(0.0);
2597   if (m_world->GetConfig().ENERGY_ENABLED.Get()) {
2598     double energyRemainingInSourceDeme = source_deme.CalculateTotalEnergy(ctx2);
2599     source_deme.SetEnergyRemainingInDemeAtReplication(energyRemainingInSourceDeme);
2600     source_deme_energy = energyRemainingInSourceDeme + source_deme.GetTotalEnergyTestament();
2601 
2602     m_world->GetStats().SumEnergyTestamentAcceptedByDeme().Add(source_deme.GetTotalEnergyTestament());
2603     deme_energy_decay = 1.0 - m_world->GetConfig().FRAC_ENERGY_DECAY_AT_DEME_BIRTH.Get();
2604     parent_deme_energy = source_deme_energy * deme_energy_decay * (1.0 - m_world->GetConfig().FRAC_PARENT_ENERGY_GIVEN_TO_DEME_AT_BIRTH.Get());
2605     offspring_deme_energy = source_deme_energy * deme_energy_decay * m_world->GetConfig().FRAC_PARENT_ENERGY_GIVEN_TO_DEME_AT_BIRTH.Get();
2606   }
2607 
2608   bool target_successfully_seeded = true;
2609 
2610 
2611   bool source_deme_resource_reset(true), target_deme_resource_reset(true);
2612   switch(m_world->GetConfig().DEMES_RESET_RESOURCES.Get()) {
2613     case 0:
2614       // reset resource in both demes
2615       source_deme_resource_reset = target_deme_resource_reset = true;
2616       break;
2617     case 1:
2618       // reset resource only in target deme
2619       source_deme_resource_reset = false;
2620       target_deme_resource_reset = true;
2621       break;
2622     case 2:
2623       // do not reset either deme resource
2624       source_deme_resource_reset = target_deme_resource_reset = false;
2625       break;
2626     default:
2627       cout << "Undefined value " << m_world->GetConfig().DEMES_RESET_RESOURCES.Get() << " for DEMES_RESET_RESOURCES\n";
2628       exit(1);
2629   }
2630 
2631   // Reset both demes, in case they have any cleanup work to do.
2632   // Must reset target first for stats to be correctly updated!
2633   if (m_world->GetConfig().ENERGY_ENABLED.Get() == 1) {
2634     // Transfer energy from source to target if we're using the energy model.
2635     if (target_successfully_seeded) target_deme.DivideReset(ctx2, source_deme, target_deme_resource_reset, offspring_deme_energy);
2636     source_deme.DivideReset(ctx2, source_deme, source_deme_resource_reset, parent_deme_energy);
2637   } else {
2638     // Default; reset both source and target.
2639     if (target_successfully_seeded) target_deme.DivideReset(ctx2, source_deme, target_deme_resource_reset);
2640     source_deme.DivideReset(ctx2, source_deme, source_deme_resource_reset);
2641   }
2642 
2643 
2644   // Are we using germlines?  If so, we need to mutate the germline to get the
2645   // genome that we're going to seed the target with.
2646   if (m_world->GetConfig().DEMES_USE_GERMLINE.Get() == 1) {
2647     // @JEB Original germlines
2648     Genome next_germ(source_deme.GetGermline().GetLatest());
2649     const cInstSet& instset = m_world->GetHardwareManager().GetInstSet(next_germ.GetInstSet());
2650     cAvidaContext ctx(m_world, m_world->GetRandom());
2651 
2652     if (m_world->GetConfig().GERMLINE_COPY_MUT.Get() > 0.0) {
2653       for(int i=0; i<next_germ.GetSize(); ++i) {
2654         if (m_world->GetRandom().P(m_world->GetConfig().GERMLINE_COPY_MUT.Get())) {
2655           next_germ.GetSequence()[i] = instset.GetRandomInst(ctx);
2656         }
2657       }
2658     }
2659 
2660     if ((m_world->GetConfig().GERMLINE_INS_MUT.Get() > 0.0)
2661         && m_world->GetRandom().P(m_world->GetConfig().GERMLINE_INS_MUT.Get())) {
2662       const unsigned int mut_line = ctx.GetRandom().GetUInt(next_germ.GetSize() + 1);
2663       next_germ.GetSequence().Insert(mut_line, instset.GetRandomInst(ctx));
2664     }
2665 
2666     if ((m_world->GetConfig().GERMLINE_DEL_MUT.Get() > 0.0)
2667         && m_world->GetRandom().P(m_world->GetConfig().GERMLINE_DEL_MUT.Get())) {
2668       const unsigned int mut_line = ctx.GetRandom().GetUInt(next_germ.GetSize());
2669       next_germ.GetSequence().Remove(mut_line);
2670     }
2671 
2672     // Replace the target deme's germline with the source deme's, and add the newly-
2673     // mutated germ to ONLY the target's germline.  The source remains unchanged.
2674     target_deme.ReplaceGermline(source_deme.GetGermline());
2675     target_deme.GetGermline().Add(next_germ);
2676 
2677     // Germline stats tracking.
2678     m_world->GetStats().GermlineReplication(source_deme.GetGermline(), target_deme.GetGermline());
2679 
2680     // All done with the germline manipulation; seed each deme.
2681     SeedDeme(source_deme, source_deme.GetGermline().GetLatest(), SRC_DEME_GERMLINE, ctx2);
2682 
2683     /* MJM - source and target deme could be the same!
2684      * Seeding the same deme twice probably shouldn't happen.
2685      */
2686     if (source_deme.GetDemeID() != target_deme.GetDemeID()) {
2687       SeedDeme(target_deme, target_deme.GetGermline().GetLatest(), SRC_DEME_GERMLINE, ctx2);
2688     }
2689 
2690   } else if (m_world->GetConfig().DEMES_USE_GERMLINE.Get() == 2) {
2691     // @JEB -- New germlines using cGenotype
2692 
2693     // get germline genotype
2694     int germline_genotype_id = source_deme.GetGermlineGenotypeID();
2695     cBioGroup* germline_genotype = m_world->GetClassificationManager().GetBioGroupManager("genotype")->GetBioGroup(germline_genotype_id);
2696     assert(germline_genotype);
2697 
2698     // create a new genome by mutation
2699     Genome mg(germline_genotype->GetProperty("genome").AsString());
2700     cCPUMemory new_genome(mg.GetSequence());
2701     const cInstSet& instset = m_world->GetHardwareManager().GetInstSet(mg.GetInstSet());
2702     cAvidaContext ctx(m_world, m_world->GetRandom());
2703 
2704     if (m_world->GetConfig().GERMLINE_COPY_MUT.Get() > 0.0) {
2705       for(int i=0; i<new_genome.GetSize(); ++i) {
2706         if (m_world->GetRandom().P(m_world->GetConfig().GERMLINE_COPY_MUT.Get())) {
2707           new_genome[i] = instset.GetRandomInst(ctx);
2708         }
2709       }
2710     }
2711 
2712     if ((m_world->GetConfig().GERMLINE_INS_MUT.Get() > 0.0)
2713         && m_world->GetRandom().P(m_world->GetConfig().GERMLINE_INS_MUT.Get())) {
2714       const unsigned int mut_line = ctx.GetRandom().GetUInt(new_genome.GetSize() + 1);
2715       new_genome.Insert(mut_line, instset.GetRandomInst(ctx));
2716     }
2717 
2718     if ((m_world->GetConfig().GERMLINE_DEL_MUT.Get() > 0.0)
2719         && m_world->GetRandom().P(m_world->GetConfig().GERMLINE_DEL_MUT.Get())) {
2720       const unsigned int mut_line = ctx.GetRandom().GetUInt(new_genome.GetSize());
2721       new_genome.Remove(mut_line);
2722     }
2723 
2724     mg.SetSequence(new_genome);
2725 
2726     //Create a new genotype which is daughter to the old one.
2727     cDemePlaceholderUnit unit(SRC_DEME_GERMLINE, mg);
2728     tArray<cBioGroup*> parents;
2729     parents.Push(germline_genotype);
2730     cBioGroup* new_germline_genotype = germline_genotype->ClassifyNewBioUnit(&unit, &parents);
2731     source_deme.ReplaceGermline(new_germline_genotype);
2732     target_deme.ReplaceGermline(new_germline_genotype);
2733     SeedDeme(source_deme, new_germline_genotype, SRC_DEME_GERMLINE, ctx2);
2734     SeedDeme(target_deme, new_germline_genotype, SRC_DEME_GERMLINE, ctx2);
2735     new_germline_genotype->RemoveBioUnit(&unit);
2736   } else {
2737     // Not using germlines; things are much simpler.  Seed the target from the source.
2738     target_successfully_seeded = SeedDeme(source_deme, target_deme, ctx2);
2739   }
2740 
2741 
2742 	// split energy from parent deme evenly among orgs in child deme
2743 	if (m_world->GetConfig().ENERGY_ENABLED.Get() == 1 && m_world->GetConfig().ENERGY_PASSED_ON_DEME_REPLICATION_METHOD.Get() == 0) {
2744 		assert(source_deme.GetOrgCount() > 0 && target_deme.GetOrgCount() > 0);
2745     if (offspring_deme_energy > 0.0) {
2746       // split deme energy evenly between organisms in target deme
2747       double totalEnergyInjectedIntoOrganisms(0.0);
2748       for (int i=0; i < target_deme.GetSize(); i++) {
2749         int cellid = target_deme.GetCellID(i);
2750         cPopulationCell& cell = m_world->GetPopulation().GetCell(cellid);
2751         if (cell.IsOccupied()) {
2752           cOrganism* organism = cell.GetOrganism();
2753           cPhenotype& phenotype = organism->GetPhenotype();
2754           phenotype.SetEnergy(phenotype.GetStoredEnergy() + offspring_deme_energy/static_cast<double>(target_deme.GetOrgCount()));
2755           phenotype.SetMerit(cMerit(phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy() * phenotype.GetEnergyUsageRatio())));
2756           totalEnergyInjectedIntoOrganisms += phenotype.GetStoredEnergy();
2757         }
2758       }
2759       target_deme.SetEnergyInjectedIntoOrganisms(totalEnergyInjectedIntoOrganisms);
2760     }
2761     if (parent_deme_energy > 0.0) {
2762       // split deme energy evenly between organisms in source deme
2763       double totalEnergyInjectedIntoOrganisms(0.0);
2764       for (int i=0; i < source_deme.GetSize(); i++) {
2765         int cellid = source_deme.GetCellID(i);
2766         cPopulationCell& cell = m_world->GetPopulation().GetCell(cellid);
2767         if (cell.IsOccupied()) {
2768           cOrganism* organism = cell.GetOrganism();
2769           cPhenotype& phenotype = organism->GetPhenotype();
2770           phenotype.SetEnergy(phenotype.GetStoredEnergy() + parent_deme_energy/static_cast<double>(source_deme.GetOrgCount()));
2771           phenotype.SetMerit(cMerit(phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy() * phenotype.GetEnergyUsageRatio())));
2772           totalEnergyInjectedIntoOrganisms += phenotype.GetStoredEnergy();
2773         }
2774       }
2775       source_deme.SetEnergyInjectedIntoOrganisms(totalEnergyInjectedIntoOrganisms);
2776     }
2777   }
2778 
2779 
2780 
2781   // The source's merit must be transferred to the target, and then the source has
2782   // to rotate its heritable merit to its current merit.
2783   if (target_successfully_seeded) target_deme.UpdateDemeMerit(source_deme);
2784   source_deme.UpdateDemeMerit();
2785   source_deme.ClearShannonInformationStats();
2786   target_deme.ClearShannonInformationStats();
2787 
2788   // do our post-replication stats tracking.
2789   m_world->GetStats().DemePostReplication(source_deme, target_deme);
2790 }
2791 
2792 /*! ReplaceDemeFlaggedGermline is a helper method that handles deme replication when the organisms are flagging their own germ line. It is similar to ReplaceDeme, but some events are reordered. (Demes are reset only after we know that the replication will work. In addition, it only supports a small subset of the deme replication options.)
2793  */
ReplaceDemeFlaggedGermline(cDeme & source_deme,cDeme & target_deme,cAvidaContext & ctx2)2794 void cPopulation::ReplaceDemeFlaggedGermline(cDeme& source_deme, cDeme& target_deme, cAvidaContext& ctx2)
2795 {
2796 
2797   bool target_successfully_seeded = true;
2798 
2799   /* Seed deme part... */
2800   cRandom& random = m_world->GetRandom();
2801   //bool successfully_seeded = true;
2802   tArray<cOrganism*> target_founders; // List of organisms we're going to transfer.
2803 
2804   // Grab a random org from the set of orgs that have
2805   // flagged themselves as part of the germline.
2806   tArray<cOrganism*> potential_founders; // List of organisms we might transfer.
2807 
2808   // Get list of potential founders
2809   for (int i = 0; i<source_deme.GetSize(); ++i) {
2810     int cellid = source_deme.GetCellID(i);
2811     if (cell_array[cellid].IsOccupied()) {
2812       cOrganism* o = cell_array[cellid].GetOrganism();
2813       if (o->IsGermline()) {
2814         potential_founders.Push(o);
2815       }
2816     }
2817   }
2818 
2819 
2820   if (m_world->GetConfig().DEMES_ORGANISM_SELECTION.Get() == 8) {
2821     // pick a random founder...
2822     if (potential_founders.GetSize() > 0) {
2823       int r = random.GetUInt(potential_founders.GetSize());
2824       target_founders.Push(potential_founders[r]);
2825     } else {
2826       return;
2827     }
2828   } else {
2829     target_founders = potential_founders;
2830   }
2831   // Stats tracking; pre-replication hook.
2832   m_world->GetStats().DemePreReplication(source_deme, target_deme);
2833 
2834 
2835   bool source_deme_resource_reset(true), target_deme_resource_reset(true);
2836   switch(m_world->GetConfig().DEMES_RESET_RESOURCES.Get()) {
2837     case 0:
2838       // reset resource in both demes
2839       source_deme_resource_reset = target_deme_resource_reset = true;
2840       break;
2841     case 1:
2842       // reset resource only in target deme
2843       source_deme_resource_reset = false;
2844       target_deme_resource_reset = true;
2845       break;
2846     case 2:
2847       // do not reset either deme resource
2848       source_deme_resource_reset = target_deme_resource_reset = false;
2849       break;
2850     default:
2851       cout << "Undefined value " << m_world->GetConfig().DEMES_RESET_RESOURCES.Get() << " for DEMES_RESET_RESOURCES\n";
2852       exit(1);
2853   }
2854 
2855   if (target_successfully_seeded) target_deme.DivideReset(ctx2, source_deme, target_deme_resource_reset);
2856   source_deme.DivideReset(ctx2, source_deme, source_deme_resource_reset);
2857 
2858 
2859   target_deme.ClearFounders();
2860   target_deme.UpdateStats();
2861   target_deme.KillAll(ctx2);
2862   std::vector<std::pair<int, std::string> > track_founders;
2863 
2864   for(int i=0; i<target_founders.GetSize(); i++) {
2865 
2866     // this is the genome we need to use. However, we only need part of it...since it can include an offspring
2867     cCPUMemory in_memory_genome = target_founders[i]->GetHardware().GetMemory();
2868 
2869     // this is the genotype of the organism, which does not reflect any point mutations that have occurred.
2870     // we need to use it to get the right length for the genome
2871     cBioGroup* parent_bg = target_founders[i]->GetBioGroup("genotype");
2872     Genome mg(parent_bg->GetProperty("genome").AsString());
2873     cCPUMemory new_genome(mg.GetSequence());
2874 
2875     const cInstSet& instset = m_world->GetHardwareManager().GetInstSet(mg.GetInstSet());
2876     cAvidaContext ctx(m_world, m_world->GetRandom());
2877 
2878     if (m_world->GetConfig().GERMLINE_COPY_MUT.Get() > 0.0) {
2879       for(int i=0; i<new_genome.GetSize(); ++i) {
2880         if (m_world->GetRandom().P(m_world->GetConfig().GERMLINE_COPY_MUT.Get())) {
2881           new_genome[i] = instset.GetRandomInst(ctx);
2882         } else if (in_memory_genome.GetSize() > i){
2883           // this line copies the mutations accured as a result of performing tasks to the new genome
2884           new_genome[i] = in_memory_genome[i];
2885 
2886         }
2887       }
2888     }
2889 
2890     if ((m_world->GetConfig().GERMLINE_INS_MUT.Get() > 0.0)
2891         && m_world->GetRandom().P(m_world->GetConfig().GERMLINE_INS_MUT.Get())) {
2892       const unsigned int mut_line = ctx.GetRandom().GetUInt(new_genome.GetSize() + 1);
2893       new_genome.Insert(mut_line, instset.GetRandomInst(ctx));
2894     }
2895 
2896     if ((m_world->GetConfig().GERMLINE_DEL_MUT.Get() > 0.0)
2897         && m_world->GetRandom().P(m_world->GetConfig().GERMLINE_DEL_MUT.Get())) {
2898       const unsigned int mut_line = ctx.GetRandom().GetUInt(new_genome.GetSize());
2899       new_genome.Remove(mut_line);
2900     }
2901     mg.SetSequence(new_genome);
2902 
2903     int cellid = DemeSelectInjectionCell(target_deme, i);
2904     InjectGenome(cellid, SRC_DEME_REPLICATE, mg, ctx, target_founders[i]->GetLineageLabel());
2905 
2906 
2907     // At this point, the cell had better be occupied...
2908     assert(GetCell(cellid).IsOccupied());
2909     cOrganism * organism = GetCell(cellid).GetOrganism();
2910 
2911     // For now, just copy the generation...
2912     organism->GetPhenotype().SetGeneration(target_founders[i]->GetPhenotype().GetGeneration() );
2913 
2914     target_deme.AddFounder(organism->GetBioGroup("genotype"), &organism->GetPhenotype());
2915 
2916     track_founders.push_back(make_pair(organism->GetBioGroup("genotype")->GetID(), new_genome.AsString()));
2917 
2918     DemePostInjection(target_deme, cell_array[cellid]);
2919   }
2920 
2921 
2922   // For source deme...
2923   if (m_world->GetConfig().DEMES_DIVIDE_METHOD.Get() == 1) {
2924 
2925     source_deme.UpdateStats();
2926     source_deme.KillAll(ctx2);
2927     // do not clear or change founder list
2928 
2929     // use it to recreate ancestral state of genotypes
2930     tArray<int>& source_founders = source_deme.GetFounderGenotypeIDs();
2931     tArray<cPhenotype>& source_founder_phenotypes = source_deme.GetFounderPhenotypes();
2932     for(int i=0; i<source_founders.GetSize(); i++) {
2933 
2934       int cellid = DemeSelectInjectionCell(source_deme, i);
2935       //cout << "founder: " << source_founders[i] << endl;
2936       cBioGroup* bg = m_world->GetClassificationManager().GetBioGroupManager("genotype")->GetBioGroup(source_founders[i]);
2937       SeedDeme_InjectDemeFounder(cellid, bg, ctx2, &source_founder_phenotypes[i], -1, true);
2938       DemePostInjection(source_deme, cell_array[cellid]);
2939     }
2940 
2941   }
2942 
2943   source_deme.ClearTotalResourceAmountConsumed();
2944 
2945   source_deme.ClearShannonInformationStats();
2946   target_deme.ClearShannonInformationStats();
2947 
2948   // do our post-replication stats tracking.
2949   m_world->GetStats().DemePostReplication(source_deme, target_deme);
2950   m_world->GetStats().TrackDemeGLSReplication(source_deme.GetID(), target_deme.GetID(), track_founders);
2951 
2952 
2953 }
2954 
2955 /*! Helper method to seed a deme from the given genome.
2956  If the passed-in deme is populated, all resident organisms are terminated.  The
2957  deme's germline is left unchanged.
2958 
2959  @todo Fix lineage label on injected genomes.
2960  @todo Different strategies for non-random placement.
2961  */
SeedDeme(cDeme & deme,Genome & genome,eBioUnitSource src,cAvidaContext & ctx)2962 void cPopulation::SeedDeme(cDeme& deme, Genome& genome, eBioUnitSource src, cAvidaContext& ctx) {
2963   // Kill all the organisms in the deme.
2964   deme.KillAll(ctx);
2965 
2966   // Create the specified number of organisms in the deme.
2967   for(int i=0; i< m_world->GetConfig().DEMES_REPLICATE_SIZE.Get(); ++i) {
2968     int cellid = DemeSelectInjectionCell(deme, i);
2969     InjectGenome(cellid, src, genome, ctx, 0);
2970     DemePostInjection(deme, cell_array[cellid]);
2971   }
2972 }
2973 
SeedDeme(cDeme & _deme,cBioGroup * bg,eBioUnitSource src,cAvidaContext & ctx)2974 void cPopulation::SeedDeme(cDeme& _deme, cBioGroup* bg, eBioUnitSource src, cAvidaContext& ctx) {
2975   // Kill all the organisms in the deme.
2976   _deme.KillAll(ctx);
2977   _deme.ClearFounders();
2978 
2979   // Create the specified number of organisms in the deme.
2980   for(int i=0; i< m_world->GetConfig().DEMES_REPLICATE_SIZE.Get(); ++i) {
2981     int cellid = DemeSelectInjectionCell(_deme, i);
2982     InjectGenome(cellid, src, Genome(bg->GetProperty("genome").AsString()), ctx);
2983     DemePostInjection(_deme, cell_array[cellid]);
2984     _deme.AddFounder(bg);
2985   }
2986 
2987 }
2988 
2989 /*! Helper method to seed a target deme from the organisms in the source deme.
2990  All organisms in the target deme are terminated, and a subset of the organisms in
2991  the source will be cloned to the target. Returns whether target deme was successfully seeded.
2992  */
SeedDeme(cDeme & source_deme,cDeme & target_deme,cAvidaContext & ctx)2993 bool cPopulation::SeedDeme(cDeme& source_deme, cDeme& target_deme, cAvidaContext& ctx) {
2994   cRandom& random = m_world->GetRandom();
2995 
2996   bool successfully_seeded = true;
2997 
2998   // Check to see if we're doing probabilistic organism replication from source
2999   // to target deme.
3000   if (m_world->GetConfig().DEMES_PROB_ORG_TRANSFER.Get() == 0.0) {
3001 
3002     //@JEB -- old method is default for consistency!
3003     if (m_world->GetConfig().DEMES_SEED_METHOD.Get() == 0) {
3004       // Here's the idea: store up a list of the genotypes from the source that we
3005       // need to copy to the target. Then clear both the source and target demes,
3006       // and finally inject organisms from the saved genotypes into both the source
3007       // and target.
3008       //
3009       // This is a little ugly - Note that if you're trying to get something a little
3010       // more random, there's also the "fruiting body" option (DEMES_PROB_ORG_TRANSFER),
3011       // and the even less contrived MIGRATION_RATE.
3012       //
3013       // @todo In order to get lineage tracking to work again, we need to change this
3014       //       from tracking Genomes to tracking cGenotypes.  But that's a pain,
3015       //       because the cGenotype* from cOrganism::GetGenotype may not live after
3016       //       a call to cDeme::KillAll.
3017       std::vector<std::pair<Genome,int> > xfer; // List of genomes we're going to transfer.
3018 
3019       switch(m_world->GetConfig().DEMES_ORGANISM_SELECTION.Get()) {
3020         case 0: { // Random w/ replacement (meaning, we don't prevent the same genotype from
3021           // being selected more than once).
3022           while((int)xfer.size() < m_world->GetConfig().DEMES_REPLICATE_SIZE.Get()) {
3023             int cellid = source_deme.GetCellID(random.GetUInt(source_deme.GetSize()));
3024             if (cell_array[cellid].IsOccupied()) {
3025               xfer.push_back(std::make_pair(cell_array[cellid].GetOrganism()->GetGenome(),
3026                                             cell_array[cellid].GetOrganism()->GetLineageLabel()));
3027             }
3028           }
3029           break;
3030         }
3031         case 1: { // Sequential selection, from the beginning.  Good with DEMES_ORGANISM_PLACEMENT=3.
3032           for(int i=0; i<m_world->GetConfig().DEMES_REPLICATE_SIZE.Get(); ++i) {
3033             int cellid = source_deme.GetCellID(i);
3034             if (cell_array[cellid].IsOccupied()) {
3035               xfer.push_back(std::make_pair(cell_array[cellid].GetOrganism()->GetGenome(),
3036                                             cell_array[cellid].GetOrganism()->GetLineageLabel()));
3037             }
3038           }
3039           break;
3040         }
3041         default: {
3042           cout << "Undefined value (" << m_world->GetConfig().DEMES_ORGANISM_SELECTION.Get()
3043           << ") for DEMES_ORGANISM_SELECTION." << endl;
3044           exit(1);
3045         }
3046       }
3047       // We'd better have at *least* one genome.
3048       assert(xfer.size()>0);
3049 
3050       // Clear the demes.
3051       source_deme.UpdateStats();
3052       source_deme.KillAll(ctx);
3053 
3054       target_deme.UpdateStats();
3055       target_deme.KillAll(ctx);
3056 
3057       // And now populate the source and target.
3058       int j=0;
3059       for(std::vector<std::pair<Genome,int> >::iterator i=xfer.begin(); i!=xfer.end(); ++i, ++j) {
3060         int cellid = DemeSelectInjectionCell(source_deme, j);
3061         InjectGenome(cellid, SRC_DEME_REPLICATE, i->first, ctx, i->second);
3062         DemePostInjection(source_deme, cell_array[cellid]);
3063 
3064         if (source_deme.GetDemeID() != target_deme.GetDemeID()) {
3065           cellid = DemeSelectInjectionCell(target_deme, j);
3066           InjectGenome(cellid, SRC_DEME_REPLICATE, i->first, ctx, i->second);
3067           DemePostInjection(target_deme, cell_array[cellid]);
3068         }
3069 
3070       }
3071     } else /* if (m_world->GetConfig().DEMES_SEED_METHOD.Get() != 0) */{
3072 
3073       // @JEB
3074       // Updated seed deme method that maintains genotype inheritance.
3075 
3076       // deconstruct founders into two lists...
3077       tArray<cOrganism*> source_founders; // List of organisms we're going to transfer.
3078       tArray<cOrganism*> target_founders; // List of organisms we're going to transfer.
3079 
3080 
3081       switch(m_world->GetConfig().DEMES_ORGANISM_SELECTION.Get()) {
3082         case 0: { // Random w/ replacement (meaning, we don't prevent the same genotype from
3083           // being selected more than once).
3084           tArray<cOrganism*> founders; // List of organisms we're going to transfer.
3085           while(founders.GetSize() < m_world->GetConfig().DEMES_REPLICATE_SIZE.Get()) {
3086             int cellid = source_deme.GetCellID(random.GetUInt(source_deme.GetSize()));
3087             if (cell_array[cellid].IsOccupied()) {
3088               founders.Push(cell_array[cellid].GetOrganism());
3089             }
3090           }
3091           source_founders = founders;
3092           target_founders = founders;
3093           break;
3094         }
3095         case 1: { // Sequential selection, from the beginning.  Good with DEMES_ORGANISM_PLACEMENT=3.
3096           tArray<cOrganism*> founders; // List of organisms we're going to transfer.
3097           for(int i=0; i<m_world->GetConfig().DEMES_REPLICATE_SIZE.Get(); ++i) {
3098             int cellid = source_deme.GetCellID(i);
3099             if (cell_array[cellid].IsOccupied()) {
3100               founders.Push(cell_array[cellid].GetOrganism());
3101             }
3102           }
3103           source_founders = founders;
3104           target_founders = founders;
3105           break;
3106         }
3107         case 6: { // Random w/o replacement.  Take as many for each deme as DEME_REPLICATE_SIZE.
3108           tList<cOrganism> prospective_founders;
3109 
3110           //Die if not >= two organisms.
3111           if (source_deme.GetOrgCount() >= 2) {
3112 
3113             //Collect prospective founder organisms into a list
3114             for (int i=0; i < source_deme.GetSize(); i++) {
3115               if ( GetCell(source_deme.GetCellID(i)).IsOccupied() ) {
3116                 prospective_founders.Push( GetCell(source_deme.GetCellID(i)).GetOrganism() );
3117               }
3118             }
3119 
3120             //add orgs alternately to source and target founders until
3121             //we run out or each reaches DEMES_REPLICATE_SIZE.
3122             int num_chosen_orgs = 0;
3123             while( ((target_founders.GetSize() < m_world->GetConfig().DEMES_REPLICATE_SIZE.Get())
3124                     || (source_founders.GetSize() < m_world->GetConfig().DEMES_REPLICATE_SIZE.Get()))
3125                   && (prospective_founders.GetSize() > 0) ) {
3126 
3127               int chosen_org = random.GetUInt(prospective_founders.GetSize());
3128               if (num_chosen_orgs % 2 == 0) {
3129                 source_founders.Push(prospective_founders.PopPos(chosen_org));
3130               } else {
3131                 target_founders.Push(prospective_founders.PopPos(chosen_org));
3132               }
3133 
3134               num_chosen_orgs++;
3135             }
3136           }
3137           break;
3138         }
3139         case 7: { // Grab the organisms that have flagged themselves as
3140           // part of the germline. Ignores replicate size...
3141           tArray<cOrganism*> founders; // List of organisms we're going to transfer.
3142           for (int i = 0; i<source_deme.GetSize(); ++i) {
3143             cPopulationCell& cell = source_deme.GetCell(i);
3144             if (cell.IsOccupied()) {
3145               cOrganism* o = cell.GetOrganism();
3146               if (o->IsGermline()) {
3147                 founders.Push(o);
3148               }
3149             }
3150           }
3151 
3152           source_founders = founders;
3153           target_founders = founders;
3154           break;
3155         }
3156         case 8: { // Grab a random org from the set of orgs that have
3157           // flagged themselves as part of the germline.
3158           tArray<cOrganism*> potential_founders; // List of organisms we might transfer.
3159           tArray<cOrganism*> founders; // List of organisms we're going to transfer.
3160 
3161           // Get list of potential founders
3162           for (int i = 0; i<source_deme.GetSize(); ++i) {
3163             int cellid = source_deme.GetCellID(i);
3164             if (cell_array[cellid].IsOccupied()) {
3165               cOrganism* o = cell_array[cellid].GetOrganism();
3166               if (o->IsGermline()) {
3167                 potential_founders.Push(o);
3168               }
3169             }
3170           }
3171 
3172           // pick a random founder...
3173           if (potential_founders.GetSize() > 0) {
3174             int r = random.GetUInt(potential_founders.GetSize());
3175             founders.Push(potential_founders[r]);
3176           }
3177           source_founders = founders;
3178           target_founders = founders;
3179           break;
3180         }
3181         case 2:
3182         case 3:
3183         case 4:
3184         case 5:
3185         { // Selection based on germline propensities.
3186           // 2: sum the germline propensities of all organisms
3187           // and pick TWO based on each organism getting a
3188           // weighted probability of being germline
3189           // 3: treat germline propensities as zero or nonzero for picking
3190           // 4: same as 3: but replication to target fails if only one germ.
3191           // 5: same as 3: but replication fails and source dies if fewer than two germs.
3192           tArray<cOrganism*> founders; // List of organisms we're going to transfer.
3193 
3194           if (source_deme.GetOrgCount() >= 2) {
3195 
3196             if (m_world->GetConfig().DEMES_DIVIDE_METHOD.Get() != 0) {
3197               m_world->GetDriver().RaiseFatalException(1, "Germline DEMES_ORGANISM_SELECTION methods 2 and 3 can only be used with DEMES_DIVIDE_METHOD 0.");
3198             }
3199 
3200             tArray<cOrganism*> prospective_founders;
3201 
3202             cDoubleSum gp_sum;
3203             double min = -1;
3204             for (int i=0; i < source_deme.GetSize(); i++) {
3205               if ( GetCell(source_deme.GetCellID(i)).IsOccupied() ) {
3206                 double gp = GetCell(source_deme.GetCellID(i)).GetOrganism()->GetPhenotype().GetPermanentGermlinePropensity();
3207                 if (gp > 0.0) {
3208                   gp_sum.Add( gp );
3209                   prospective_founders.Push( GetCell(source_deme.GetCellID(i)).GetOrganism() );
3210                 }
3211                 //cout << gp << " ";
3212                 if ( (min == -1) || (gp < min) ) min = gp;
3213               }
3214             }
3215 
3216             if (m_world->GetVerbosity() >= VERBOSE_ON) cout << "Germline Propensity Sum: " << gp_sum.Sum() << endl;
3217             if (m_world->GetVerbosity() >= VERBOSE_ON) cout << "Num prospective founders: " << prospective_founders.GetSize() << endl;
3218 
3219             if (prospective_founders.GetSize() < 2) {
3220 
3221               // there were not enough orgs with nonzero germlines
3222               // pick additional orgs at random without replacement,
3223               // unless our method forbids this
3224 
3225               // leave the founder list empty for method 5
3226               if (m_world->GetConfig().DEMES_ORGANISM_SELECTION.Get() != 5) {
3227 
3228                 founders = prospective_founders;
3229 
3230                 //do not add additional founders randomly for method 4
3231                 if (m_world->GetConfig().DEMES_ORGANISM_SELECTION.Get() != 4) {
3232 
3233                   while(founders.GetSize() < 2) {
3234                     int cellid = source_deme.GetCellID(random.GetUInt(source_deme.GetSize()));
3235                     if ( cell_array[cellid].IsOccupied() ) {
3236                       cOrganism * org = cell_array[cellid].GetOrganism();
3237                       bool found = false;
3238                       for(int i=0; i< founders.GetSize(); i++) {
3239                         if (founders[i] == org) found = true;
3240                       }
3241                       if (!found) founders.Push(cell_array[cellid].GetOrganism());
3242                     }
3243                   }
3244                 }
3245               }
3246             } else {
3247 
3248               // pick two orgs based on germline propensities from prospective founders
3249 
3250               while(founders.GetSize() < 2) {
3251 
3252                 double choice = (m_world->GetConfig().DEMES_ORGANISM_SELECTION.Get() == 2)
3253                 ? random.GetDouble( gp_sum.Sum() ) : random.GetDouble( gp_sum.Count() );
3254 
3255 
3256                 //cout <<  "Count: " << gp_sum.Count() << endl;
3257 
3258                 // find the next organism to choose
3259                 cOrganism * org = NULL;
3260                 int on = 0;
3261                 while( (choice > 0) && (on < prospective_founders.GetSize()) ) {
3262                   org = prospective_founders[on];
3263 
3264                   // did we already have this org?
3265                   bool found = false;
3266                   for(int i=0; i< founders.GetSize(); i++) {
3267                     if (founders[i] == org) found = true;
3268                   }
3269 
3270                   // if it wasn't already chosen, then we count down...
3271                   if (!found) {
3272                     choice -= (m_world->GetConfig().DEMES_ORGANISM_SELECTION.Get() == 2)
3273                     ? org->GetPhenotype().GetPermanentGermlinePropensity()
3274                     : (org->GetPhenotype().GetPermanentGermlinePropensity() > 0);
3275                   }
3276                   on++;
3277                 }
3278 
3279                 gp_sum.Subtract(org->GetPhenotype().GetPermanentGermlinePropensity());
3280                 assert(org);
3281                 founders.Push(org);
3282               }
3283             }
3284 
3285             if (founders.GetSize() > 0) source_founders.Push(founders[0]);
3286             if (founders.GetSize() > 1) target_founders.Push(founders[1]);
3287 
3288             /*
3289              // Debug Code
3290              cout << endl;
3291              cout << "sum " << gp_sum.Sum() << endl;
3292              cout << "min " << min << endl;
3293              cout << "choice " << choice << endl;
3294              */
3295 
3296             //cout << "Chose germline propensity " << chosen_org->GetPhenotype().GetLastGermlinePropensity() << endl;
3297           } else {
3298             //Failure because we didn't have at least two organisms...
3299             //m_world->GetDriver().RaiseFatalException(1, "Germline DEMES_ORGANISM_SELECTION method didn't find at least two organisms in deme.");
3300           }
3301 
3302           break;
3303         }
3304         default: {
3305           cout << "Undefined value (" << m_world->GetConfig().DEMES_ORGANISM_SELECTION.Get()
3306           << ") for DEMES_ORGANISM_SELECTION." << endl;
3307           exit(1);
3308         }
3309       }
3310 
3311 
3312       // We'd better have at *least* one genome.
3313       // Methods that require a germline can sometimes come up short...
3314       //assert(source_founders.GetSize()>0);
3315       //assert(target_founders.GetSize()>0);
3316       if(source_founders.GetSize() == 0) {
3317         return false;
3318       }
3319 
3320       // We clear the deme, but trick cPopulation::KillOrganism
3321       // to NOT delete the organisms, by pretending
3322       // the orgs are running. This way we can still create
3323       // clones of them that will track stats correctly.
3324       // We also need to defer adjusting the genotype
3325       // or it will be prematurely deleted before we are done!
3326 
3327       // cDoubleSum gen;
3328       tArray<cOrganism*> old_source_organisms;
3329       for(int i=0; i<source_deme.GetSize(); ++i) {
3330         int cell_id = source_deme.GetCellID(i);
3331 
3332         if (cell_array[cell_id].IsOccupied()) {
3333           cOrganism * org = cell_array[cell_id].GetOrganism();
3334           old_source_organisms.Push(org);
3335           org->SetRunning(true);
3336         }
3337       }
3338 
3339 
3340       tArray<cOrganism*> old_target_organisms;
3341       for(int i=0; i<target_deme.GetSize(); ++i) {
3342         int cell_id = target_deme.GetCellID(i);
3343 
3344         if (cell_array[cell_id].IsOccupied()) {
3345           cOrganism * org = cell_array[cell_id].GetOrganism();
3346           old_target_organisms.Push(org);
3347           org->SetRunning(true);
3348         }
3349       }
3350 
3351       // Clear the target deme (if we have successfully replaced it).
3352       if (target_founders.GetSize() > 0) {
3353         target_deme.ClearFounders();
3354         target_deme.UpdateStats();
3355         target_deme.KillAll(ctx);
3356       } else {
3357         successfully_seeded = false;
3358       }
3359 
3360       //cout << founders.GetSize() << " founders." << endl;
3361 
3362       // Now populate the target (and optionally the source) using InjectGenotype.
3363       // In the future InjectClone could be used, but this would require the
3364       // deme keeping complete copies of the founder organisms when
3365       // we wanted to re-seed from the original founders.
3366       for(int i=0; i<target_founders.GetSize(); i++) {
3367         int cellid = DemeSelectInjectionCell(target_deme, i);
3368         SeedDeme_InjectDemeFounder(cellid, target_founders[i]->GetBioGroup("genotype"), ctx, &target_founders[i]->GetPhenotype(),  target_founders[i]->GetLineageLabel(), false);
3369        // target_deme.AddFounder(target_founders[i]->GetBioGroup("genotype"), &target_founders[i]->GetPhenotype());
3370         DemePostInjection(target_deme, cell_array[cellid]);
3371       }
3372 
3373       for(int i=0; i<target_deme.GetSize(); ++i) {
3374         cPopulationCell& cell = target_deme.GetCell(i);
3375         if(cell.IsOccupied()) {
3376           target_deme.AddFounder(cell.GetOrganism()->GetBioGroup("genotype"), &cell.GetOrganism()->GetPhenotype());
3377         }
3378       }
3379 
3380       // We either repeat this procedure in the source deme,
3381       // restart the source deme from its old founders,
3382       // or do nothing to the source deme...
3383 
3384       // source deme is replaced in the same way as the target
3385       if (m_world->GetConfig().DEMES_DIVIDE_METHOD.Get() == 0) {
3386 
3387         source_deme.ClearFounders();
3388         source_deme.UpdateStats();
3389         source_deme.KillAll(ctx);
3390 
3391         for(int i=0; i<source_founders.GetSize(); i++) {
3392           int cellid = DemeSelectInjectionCell(source_deme, i);
3393           SeedDeme_InjectDemeFounder(cellid, source_founders[i]->GetBioGroup("genotype"), ctx, &source_founders[i]->GetPhenotype(), source_founders[i]->GetLineageLabel(), false);
3394           source_deme.AddFounder(source_founders[i]->GetBioGroup("genotype"), &source_founders[i]->GetPhenotype());
3395           DemePostInjection(source_deme, cell_array[cellid]);
3396         }
3397       }
3398       // source deme is "reset" by re-injecting founder genotypes
3399       else if (m_world->GetConfig().DEMES_DIVIDE_METHOD.Get() == 1) {
3400         // Do not update the last founder generation, since the founders have not changed.
3401 
3402         source_deme.UpdateStats();
3403         source_deme.KillAll(ctx);
3404         // do not clear or change founder list
3405 
3406         // use it to recreate ancestral state of genotypes
3407         tArray<int>& source_founders = source_deme.GetFounderGenotypeIDs();
3408         tArray<cPhenotype>& source_founder_phenotypes = source_deme.GetFounderPhenotypes();
3409         for(int i=0; i<source_founders.GetSize(); i++) {
3410 
3411           int cellid = DemeSelectInjectionCell(source_deme, i);
3412           //cout << "founder: " << source_founders[i] << endl;
3413           cBioGroup* bg = m_world->GetClassificationManager().GetBioGroupManager("genotype")->GetBioGroup(source_founders[i]);
3414           SeedDeme_InjectDemeFounder(cellid, bg, ctx, &source_founder_phenotypes[i], -1, true);
3415           DemePostInjection(source_deme, cell_array[cellid]);
3416         }
3417 
3418         //cout << target_deme.GetOrgCount() << " target orgs." << endl;
3419         //cout << source_deme.GetOrgCount() << " source orgs." << endl;
3420       }
3421       // source deme is left untouched
3422       else if (m_world->GetConfig().DEMES_DIVIDE_METHOD.Get() == 2) {
3423       }
3424       else if (m_world->GetConfig().DEMES_DIVIDE_METHOD.Get() == 3) {
3425         source_deme.ClearTotalResourceAmountConsumed();
3426       }
3427       else if (m_world->GetConfig().DEMES_DIVIDE_METHOD.Get() == 4) {
3428         source_deme.ClearTotalResourceAmountConsumed();
3429         for(int i=0; i<source_founders.GetSize(); i++) {
3430           source_founders[i]->Die(ctx);
3431         }
3432       }
3433       else {
3434         m_world->GetDriver().RaiseFatalException(1, "Unknown DEMES_DIVIDE_METHOD");
3435       }
3436 
3437 
3438       // remember to delete the old target organisms and adjust their genotypes
3439       for(int i=0; i<old_target_organisms.GetSize(); ++i) {
3440         old_target_organisms[i]->SetRunning(false);
3441         // ONLY delete target orgs if seeding was successful
3442         // otherwise they still exist in the population!!!
3443         if (successfully_seeded) delete old_target_organisms[i];
3444       }
3445 
3446       for(int i=0; i<old_source_organisms.GetSize(); ++i) {
3447         old_source_organisms[i]->SetRunning(false);
3448 
3449         // delete old source organisms ONLY if source was replaced
3450         if ( (m_world->GetConfig().DEMES_DIVIDE_METHOD.Get() == 0)
3451             || (m_world->GetConfig().DEMES_DIVIDE_METHOD.Get() == 1) ) {
3452           delete old_source_organisms[i];
3453         }
3454       }
3455 
3456     } //End DEMES_PROB_ORG_TRANSFER > 0 methods
3457   } else {
3458     // Probabilistic organism replication -- aka "fruiting body."
3459     //
3460     // This is a little different than the other deme replication styles.  First,
3461     // in a fruiting body we don't reset the individuals in the source deme; we
3462     // leave them unchanged.  The idea is that we're pulling random organisms
3463     // out, and letting the source continue.
3464 
3465     // Kill all the organisms in the target deme.
3466     target_deme.KillAll(ctx);
3467 
3468     // Check all the organisms in the source deme to see if they get transferred
3469     // to the target.
3470     for(int i=0,j=0; i<source_deme.GetSize(); ++i) {
3471       int source_cellid = source_deme.GetCellID(i);
3472 
3473       // Does this organism stay with the source or move to the target?
3474       if (cell_array[source_cellid].IsOccupied() && random.P(m_world->GetConfig().DEMES_PROB_ORG_TRANSFER.Get())) {
3475         // Moves to the target; save the genome and lineage label of organism being transfered.
3476         cOrganism* seed = cell_array[source_cellid].GetOrganism();
3477         const Genome& genome = seed->GetGenome();
3478         int lineage = seed->GetLineageLabel();
3479         seed = 0; // We're done with the seed organism.
3480 
3481         // Remove this organism from the source.
3482         KillOrganism(cell_array[source_cellid], ctx);
3483 
3484         // And inject it into target deme.
3485         int target_cellid = DemeSelectInjectionCell(target_deme, j++);
3486         InjectGenome(target_cellid, SRC_DEME_REPLICATE, genome, ctx, lineage);
3487         DemePostInjection(target_deme, cell_array[target_cellid]);
3488       }
3489       //else {
3490       // Stays with the source.  Nothing to do here yet.
3491       //}
3492     }
3493   }
3494 
3495 	return successfully_seeded;
3496 }
3497 
SeedDeme_InjectDemeFounder(int _cell_id,cBioGroup * bg,cAvidaContext & ctx,cPhenotype * _phenotype,int lineage_label,bool reset)3498 void cPopulation::SeedDeme_InjectDemeFounder(int _cell_id, cBioGroup* bg, cAvidaContext& ctx, cPhenotype* _phenotype, int lineage_label, bool reset)
3499 {
3500   // Mutate the genome?
3501   if (m_world->GetConfig().DEMES_MUT_ORGS_ON_REPLICATION.Get() == 1 && !reset) {
3502     // MUTATE!
3503 
3504     // create a new genome by mutation
3505     Genome mg(bg->GetProperty("genome").AsString());
3506     cCPUMemory new_genome(mg.GetSequence());
3507     const cInstSet& instset = m_world->GetHardwareManager().GetInstSet(mg.GetInstSet());
3508     cAvidaContext ctx(m_world, m_world->GetRandom());
3509 
3510     if (m_world->GetConfig().GERMLINE_COPY_MUT.Get() > 0.0) {
3511       for(int i=0; i<new_genome.GetSize(); ++i) {
3512         if (m_world->GetRandom().P(m_world->GetConfig().GERMLINE_COPY_MUT.Get())) {
3513           new_genome[i] = instset.GetRandomInst(ctx);
3514         }
3515       }
3516     }
3517 
3518     if ((m_world->GetConfig().GERMLINE_INS_MUT.Get() > 0.0)
3519         && m_world->GetRandom().P(m_world->GetConfig().GERMLINE_INS_MUT.Get())) {
3520       const unsigned int mut_line = ctx.GetRandom().GetUInt(new_genome.GetSize() + 1);
3521       new_genome.Insert(mut_line, instset.GetRandomInst(ctx));
3522     }
3523 
3524     if ((m_world->GetConfig().GERMLINE_DEL_MUT.Get() > 0.0)
3525         && m_world->GetRandom().P(m_world->GetConfig().GERMLINE_DEL_MUT.Get())) {
3526       const unsigned int mut_line = ctx.GetRandom().GetUInt(new_genome.GetSize());
3527       new_genome.Remove(mut_line);
3528     }
3529     mg.SetSequence(new_genome);
3530 
3531     /*
3532 
3533      //Create a new genotype which is daughter to the old one.
3534      cDemePlaceholderUnit unit(SRC_DEME_GERMLINE, mg);
3535      tArray<cBioGroup*> parents;
3536      parents.Push(bg);
3537      cBioGroup* new_genotype = bg->ClassifyNewBioUnit(&unit, &parents);
3538      new_genotype->RemoveBioUnit(&unit);
3539      */
3540 
3541     InjectGenome(_cell_id, SRC_DEME_REPLICATE, mg, ctx, lineage_label);
3542 
3543   } else {
3544 
3545     // phenotype can be NULL
3546     InjectGenome(_cell_id, SRC_DEME_REPLICATE, Genome(bg->GetProperty("genome").AsString()), ctx, lineage_label);
3547 
3548   }
3549 
3550   // At this point, the cell had better be occupied...
3551   assert(GetCell(_cell_id).IsOccupied());
3552   cOrganism * organism = GetCell(_cell_id).GetOrganism();
3553 
3554 
3555   //Now we need to set up the phenotype of this organism...
3556   if (_phenotype) {
3557     //If we want founders to have their proper phenotypes
3558     // then we might do something like this... (untested)
3559     //organism->SetPhenotype(*_phenotype);
3560     // Re-initialize the time-slice for this new organism.
3561     //AdjustSchedule(_cell_id, organism->GetPhenotype().GetMerit());
3562 
3563     // For now, just copy the generation...
3564     organism->GetPhenotype().SetGeneration( _phenotype->GetGeneration() );
3565 
3566     // and germline propensity.
3567     organism->GetPhenotype().SetPermanentGermlinePropensity( _phenotype->GetPermanentGermlinePropensity()  );
3568 
3569     if (m_world->GetConfig().DEMES_FOUNDER_GERMLINE_PROPENSITY.Get() >= 0.0) {
3570       organism->GetPhenotype().SetPermanentGermlinePropensity( m_world->GetConfig().DEMES_FOUNDER_GERMLINE_PROPENSITY.Get() );
3571     }
3572   }
3573 
3574   /* It requires much more than this to correctly implement, do later if needed @JEB
3575    //Optionally, set the first organism's merit to a constant value
3576    //actually, we need to add so the first organism is seeded this way too...
3577    if (m_world->GetConfig().DEMES_DEFAULT_MERIT.Get()) {
3578    organism->GetPhenotype().SetMerit( cMerit(m_world->GetConfig().DEMES_DEFAULT_MERIT.Get()) );
3579    AdjustSchedule(GetCell(_cell_id), organism->GetPhenotype().GetMerit());
3580    }
3581    */
3582 }
3583 
3584 
3585 /*! Helper method that determines the cell into which an organism will be placed.
3586  Respects all of the different placement options that are relevant for deme replication.
3587 
3588  @param sequence The number of times DemeSelectInjectionCell has been called on this deme
3589  already.  Used for replicating multiple organisms from the source to the
3590  target deme in a sensible fashion.
3591  */
DemeSelectInjectionCell(cDeme & deme,int sequence)3592 int cPopulation::DemeSelectInjectionCell(cDeme& deme, int sequence) {
3593   int cellid = -1;
3594 
3595   assert(sequence < deme.GetSize()); // cannot inject a sequence bigger then the deme
3596 
3597   switch(m_world->GetConfig().DEMES_ORGANISM_PLACEMENT.Get()) {
3598     case 0: { // Array-middle.
3599       cellid = deme.GetCellID((deme.GetSize()/2 + sequence) % deme.GetSize());
3600       break;
3601     }
3602     case 1: { // Sequential placement, start in the center of the deme.
3603       assert(sequence == 0);  // not sure how to handle a sequence in this case (Ben)
3604       cellid = deme.GetCellID(deme.GetWidth()/2, deme.GetHeight()/2);
3605       break;
3606     }
3607     case 2: { // Random placement.
3608       cellid = deme.GetCellID(m_world->GetRandom().GetInt(0, deme.GetSize()));
3609       while(cell_array[cellid].IsOccupied()) {
3610         cellid = deme.GetCellID(m_world->GetRandom().GetInt(0, deme.GetSize()));
3611       }
3612       break;
3613     }
3614     case 3: { // Sequential.
3615       cellid = deme.GetCellID(sequence);
3616       break;
3617     }
3618     default: {
3619       assert(false); // Shouldn't ever reach here.
3620     }
3621   }
3622 
3623   assert(cellid >= 0 && cellid < cell_array.GetSize());
3624   assert(cellid >= deme.GetCellID(0));
3625   assert(cellid <= deme.GetCellID(deme.GetSize()-1));
3626   return cellid;
3627 }
3628 
3629 
3630 /*! Helper method to perform any post-injection fixups on the organism/cell that
3631  was injected into a deme.  Handles all the rotation / facing options. Also increments
3632  the number of organisms injected into the deme.
3633  */
DemePostInjection(cDeme & deme,cPopulationCell & cell)3634 void cPopulation::DemePostInjection(cDeme& deme, cPopulationCell& cell) {
3635   assert(cell.GetID() >= deme.GetCellID(0));
3636   assert(cell.GetID() <= deme.GetCellID(deme.GetSize()-1));
3637   deme.IncInjectedCount();
3638   switch(m_world->GetConfig().DEMES_ORGANISM_FACING.Get()) {
3639     case 0: { // Unchanged.
3640       break;
3641     }
3642     case 1: { // Spin cell to face NW.
3643       cell.Rotate(cell_array[GridNeighbor(cell.GetID()-deme.GetCellID(0),
3644                                           deme.GetWidth(),
3645                                           deme.GetHeight(), -1, -1)+deme.GetCellID(0)]);
3646       break;
3647     }
3648     case 2: { // Spin cell to face randomly.
3649       const int rotate_count = m_world->GetRandom().GetInt(0, cell.ConnectionList().GetSize());
3650       for(int i=0; i<rotate_count; ++i) {
3651         cell.ConnectionList().CircNext();
3652       }
3653       break;
3654     }
3655     default: {
3656       assert(false);
3657     }
3658   }
3659 }
3660 
3661 
3662 // Loop through all demes to determine if any are ready to be divided.  All
3663 // full demes have 1/2 of their organisms (the odd ones) moved into a new deme.
3664 
DivideDemes(cAvidaContext & ctx)3665 void cPopulation::DivideDemes(cAvidaContext& ctx)
3666 {
3667   // Determine which demes should be replicated.
3668   const int num_demes = GetNumDemes();
3669   cRandom & random = m_world->GetRandom();
3670 
3671   // Loop through all candidate demes...
3672   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
3673     cDeme & source_deme = deme_array[deme_id];
3674 
3675     // Only divide full demes.
3676     if (source_deme.IsFull() == false) continue;
3677 
3678     // Choose a random target deme to replicate to...
3679     int target_id = deme_id;
3680     while (target_id == deme_id) target_id = random.GetUInt(num_demes);
3681     cDeme & target_deme = deme_array[target_id];
3682     const int deme_size = target_deme.GetSize();
3683 
3684     // Clear out existing cells in target deme.
3685     for (int i = 0; i < deme_size; i++) {
3686       KillOrganism(cell_array[ target_deme.GetCellID(i) ], ctx);
3687     }
3688 
3689     // Setup an array to collect the total number of tasks performed.
3690     const int num_tasks = cell_array[source_deme.GetCellID(0)].GetOrganism()->
3691     GetPhenotype().GetLastTaskCount().GetSize();
3692     tArray<int> tot_tasks(num_tasks);
3693     tot_tasks.SetAll(0);
3694 
3695     // Move over the odd numbered cells.
3696     for (int pos = 0; pos < deme_size; pos += 2) {
3697       const int cell1_id = source_deme.GetCellID( pos+1 );
3698       const int cell2_id = target_deme.GetCellID( pos );
3699       cOrganism * org1 = cell_array[cell1_id].GetOrganism();
3700 
3701       // Keep track of what tasks have been done.
3702       const tArray<int> & cur_tasks = org1->GetPhenotype().GetLastTaskCount();
3703       for (int i = 0; i < num_tasks; i++) {
3704         tot_tasks[i] += cur_tasks[i];
3705       }
3706 
3707       // Inject a copy of the odd organisms into the even cells.
3708       InjectClone(cell2_id, *org1, SRC_DEME_REPLICATE);
3709 
3710       // Kill the organisms in the odd cells.
3711       KillOrganism( cell_array[cell1_id], ctx);
3712     }
3713 
3714     // Figure out the merit each organism should have.
3715     int merit = 100;
3716     for (int i = 0; i < num_tasks; i++) {
3717       if (tot_tasks[i] > 0) merit *= 2;
3718     }
3719 
3720     // Setup the merit of both old and new individuals.
3721     for (int pos = 0; pos < deme_size; pos += 2) {
3722       cell_array[source_deme.GetCellID(pos)].GetOrganism()->UpdateMerit(merit);
3723       cell_array[target_deme.GetCellID(pos)].GetOrganism()->UpdateMerit(merit);
3724     }
3725 
3726   }
3727 }
3728 
3729 
3730 // Reset Demes goes through each deme and resets the individual organisms as
3731 // if they were just injected into the population.
3732 
ResetDemes()3733 void cPopulation::ResetDemes()
3734 {
3735   // re-inject all demes into themselves to reset them.
3736   for (int deme_id = 0; deme_id < deme_array.GetSize(); deme_id++) {
3737     for (int i = 0; i < deme_array[deme_id].GetSize(); i++) {
3738       int cur_cell_id = deme_array[deme_id].GetCellID(i);
3739       if (cell_array[cur_cell_id].IsOccupied() == false) continue;
3740       InjectClone(cur_cell_id, *(cell_array[cur_cell_id].GetOrganism()), cell_array[cur_cell_id].GetOrganism()->GetUnitSource());
3741     }
3742   }
3743 }
3744 
3745 
3746 // Copy the full contents of one deme into another.
3747 
CopyDeme(int deme1_id,int deme2_id,cAvidaContext & ctx)3748 void cPopulation::CopyDeme(int deme1_id, int deme2_id, cAvidaContext& ctx)
3749 {
3750   cDeme & deme1 = deme_array[deme1_id];
3751   cDeme & deme2 = deme_array[deme2_id];
3752 
3753   for (int i = 0; i < deme1.GetSize(); i++) {
3754     int from_cell = deme1.GetCellID(i);
3755     int to_cell = deme2.GetCellID(i);
3756     if (cell_array[from_cell].IsOccupied() == false) {
3757       KillOrganism(cell_array[to_cell], ctx);
3758       continue;
3759     }
3760     InjectClone(to_cell, *(cell_array[from_cell].GetOrganism()), SRC_DEME_COPY);
3761   }
3762 }
3763 
3764 
3765 // Print out statistics about donations
3766 
PrintDonationStats()3767 void cPopulation::PrintDonationStats()
3768 {
3769   cDoubleSum donation_makers;
3770   cDoubleSum donation_receivers;
3771   cDoubleSum donation_cheaters;
3772 
3773   cDoubleSum edit_donation_makers;
3774   cDoubleSum edit_donation_receivers;
3775   cDoubleSum edit_donation_cheaters;
3776 
3777   cDoubleSum kin_donation_makers;
3778   cDoubleSum kin_donation_receivers;
3779   cDoubleSum kin_donation_cheaters;
3780 
3781   cDoubleSum threshgb_donation_makers;
3782   cDoubleSum threshgb_donation_receivers;
3783   cDoubleSum threshgb_donation_cheaters;
3784 
3785   cDoubleSum quanta_threshgb_donation_makers;
3786   cDoubleSum quanta_threshgb_donation_receivers;
3787   cDoubleSum quanta_threshgb_donation_cheaters;
3788 
3789   cStats& stats = m_world->GetStats();
3790 
3791   cDataFile & dn_donors = m_world->GetDataFile("donations.dat");
3792   dn_donors.WriteComment("Info about organisms giving donations in the population");
3793   dn_donors.WriteTimeStamp();
3794   dn_donors.Write(stats.GetUpdate(), "update");
3795 
3796 
3797   for (int i = 0; i < cell_array.GetSize(); i++)
3798   {
3799     // Only look at cells with organisms in them.
3800     if (cell_array[i].IsOccupied() == false) continue;
3801     cOrganism * organism = cell_array[i].GetOrganism();
3802     const cPhenotype & phenotype = organism->GetPhenotype();
3803 
3804     // donors & receivers in general
3805     if (phenotype.IsDonorLast()) donation_makers.Add(1);  // Found donor
3806     if (phenotype.IsReceiverLast()) {
3807       donation_receivers.Add(1);                          // Found receiver
3808       if (phenotype.IsDonorLast()==0) {
3809         donation_cheaters.Add(1);                         // Found receiver with non-donor parent
3810       }
3811     }
3812     // edit donors & receivers
3813     if (phenotype.IsDonorEditLast()) edit_donation_makers.Add(1);  // Found edit donor
3814     if (phenotype.IsReceiverEditLast()) {
3815       edit_donation_receivers.Add(1);                              // Found edit receiver
3816       if (phenotype.IsDonorEditLast()==0) {
3817         edit_donation_cheaters.Add(1);                             // Found edit receiver whose parent did not make a edit donation
3818       }
3819     }
3820 
3821     // kin donors & receivers
3822     if (phenotype.IsDonorKinLast()) kin_donation_makers.Add(1); //found a kin donor
3823     if (phenotype.IsReceiverKinLast()){
3824       kin_donation_receivers.Add(1);                            //found a kin receiver
3825       if (phenotype.IsDonorKinLast()==0){
3826         kin_donation_cheaters.Add(1);                           //found a kin receiver whose parent did not make a kin donation
3827       }
3828     }
3829 
3830     // threshgb donors & receivers
3831     if (phenotype.IsDonorThreshGbLast()) threshgb_donation_makers.Add(1); //found a threshgb donor
3832     if (phenotype.IsReceiverThreshGbLast()){
3833       threshgb_donation_receivers.Add(1);                              //found a threshgb receiver
3834       if (phenotype.IsDonorThreshGbLast()==0){
3835         threshgb_donation_cheaters.Add(1);                             //found a threshgb receiver whose parent did...
3836       }                                                              //...not make a threshgb donation
3837     }
3838 
3839     // quanta_threshgb donors & receivers
3840     if (phenotype.IsDonorQuantaThreshGbLast()) quanta_threshgb_donation_makers.Add(1); //found a quanta threshgb donor
3841     if (phenotype.IsReceiverQuantaThreshGbLast()){
3842       quanta_threshgb_donation_receivers.Add(1);                              //found a quanta threshgb receiver
3843       if (phenotype.IsDonorQuantaThreshGbLast()==0){
3844         quanta_threshgb_donation_cheaters.Add(1);                             //found a quanta threshgb receiver whose parent did...
3845       }                                                              //...not make a quanta threshgb donation
3846     }
3847 
3848   }
3849 
3850   dn_donors.Write(donation_makers.Sum(), "parent made at least one donation");
3851   dn_donors.Write(donation_receivers.Sum(), "parent received at least one donation");
3852   dn_donors.Write(donation_cheaters.Sum(),  "parent received at least one donation but did not make one");
3853   dn_donors.Write(edit_donation_makers.Sum(), "parent made at least one edit_donation");
3854   dn_donors.Write(edit_donation_receivers.Sum(), "parent received at least one edit_donation");
3855   dn_donors.Write(edit_donation_cheaters.Sum(),  "parent received at least one edit_donation but did not make one");
3856   dn_donors.Write(kin_donation_makers.Sum(), "parent made at least one kin_donation");
3857   dn_donors.Write(kin_donation_receivers.Sum(), "parent received at least one kin_donation");
3858   dn_donors.Write(kin_donation_cheaters.Sum(),  "parent received at least one kin_donation but did not make one");
3859   dn_donors.Write(threshgb_donation_makers.Sum(), "parent made at least one threshgb_donation");
3860   dn_donors.Write(threshgb_donation_receivers.Sum(), "parent received at least one threshgb_donation");
3861   dn_donors.Write(threshgb_donation_cheaters.Sum(),  "parent received at least one threshgb_donation but did not make one");
3862   dn_donors.Write(quanta_threshgb_donation_makers.Sum(), "parent made at least one quanta_threshgb_donation");
3863   dn_donors.Write(quanta_threshgb_donation_receivers.Sum(), "parent received at least one quanta_threshgb_donation");
3864   dn_donors.Write(quanta_threshgb_donation_cheaters.Sum(),  "parent received at least one quanta_threshgb_donation but did not make one");
3865 
3866   dn_donors.Endl();
3867 }
3868 // Copy a single indvidual out of a deme into a new one (which is first purged
3869 // of existing organisms.)
3870 
SpawnDeme(int deme1_id,cAvidaContext & ctx,int deme2_id)3871 void cPopulation::SpawnDeme(int deme1_id, cAvidaContext& ctx, int deme2_id)
3872 {
3873   // Must spawn into a different deme.
3874   assert(deme1_id != deme2_id);
3875 
3876   const int num_demes = deme_array.GetSize();
3877 
3878   // If the second argument is a -1, choose a deme at random.
3879   cRandom & random = m_world->GetRandom();
3880   while (deme2_id == -1 || deme2_id == deme1_id) {
3881     deme2_id = random.GetUInt(num_demes);
3882   }
3883 
3884   // Make sure we have all legal values...
3885   assert(deme1_id >= 0 && deme1_id < num_demes);
3886   assert(deme2_id >= 0 && deme2_id < num_demes);
3887 
3888   // Find the demes that we're working with.
3889   cDeme & deme1 = deme_array[deme1_id];
3890   cDeme & deme2 = deme_array[deme2_id];
3891 
3892   // Make sure that the deme we're copying from has at least 1 organism.
3893   assert(deme1.GetOrgCount() > 0);
3894 
3895   // Determine the cell to copy from.
3896   int cell1_id = deme1.GetCellID( random.GetUInt(deme1.GetSize()) );
3897   while (cell_array[cell1_id].IsOccupied() == false) {
3898     cell1_id = deme1.GetCellID( random.GetUInt(deme1.GetSize()) );
3899   }
3900 
3901   // Clear out existing cells in target deme.
3902   for (int i = 0; i < deme2.GetSize(); i++) {
3903     KillOrganism(cell_array[ deme2.GetCellID(i) ], ctx);
3904   }
3905 
3906   // And do the spawning.
3907   int cell2_id = deme2.GetCellID( random.GetUInt(deme2.GetSize()) );
3908   InjectClone( cell2_id, *(cell_array[cell1_id].GetOrganism()), SRC_DEME_SPAWN);
3909 }
3910 
AddDemePred(cString type,int times)3911 void cPopulation::AddDemePred(cString type, int times) {
3912   if (type == "EventReceivedCenter") {
3913     for (int deme_id = 0; deme_id < deme_array.GetSize(); deme_id++) {
3914       deme_array[deme_id].AddEventReceivedCenterPred(times);
3915     }
3916   } else if (type == "EventReceivedLeftSide") {
3917     for (int deme_id = 0; deme_id < deme_array.GetSize(); deme_id++) {
3918       deme_array[deme_id].AddEventReceivedLeftSidePred(times);
3919     }
3920   } else if (type == "EventMovedIntoCenter") {
3921     for (int deme_id = 0; deme_id < deme_array.GetSize(); deme_id++) {
3922       deme_array[deme_id].AddEventMoveCenterPred(times);
3923     }
3924   } else if (type == "EventMovedBetweenTargets") {
3925     for (int deme_id = 0; deme_id < deme_array.GetSize(); deme_id++) {
3926       deme_array[deme_id].AddEventMoveBetweenTargetsPred(times);
3927     }
3928   } else if (type == "EventNUniqueIndividualsMovedIntoTarget") {
3929     for (int deme_id = 0; deme_id < deme_array.GetSize(); deme_id++) {
3930       deme_array[deme_id].AddEventEventNUniqueIndividualsMovedIntoTargetPred(times);
3931     }
3932   } else {
3933     cout << "Unknown Predicate\n";
3934     exit(1);
3935   }
3936 }
3937 
CheckImplicitDemeRepro(cDeme & deme,cAvidaContext & ctx)3938 void cPopulation::CheckImplicitDemeRepro(cDeme& deme, cAvidaContext& ctx) {
3939 
3940   if (GetNumDemes() <= 1) return;
3941 
3942   if (m_world->GetConfig().DEMES_REPLICATE_CPU_CYCLES.Get()
3943       && (deme.GetTimeUsed() >= m_world->GetConfig().DEMES_REPLICATE_CPU_CYCLES.Get())) ReplicateDeme(deme, ctx);
3944   else if (m_world->GetConfig().DEMES_REPLICATE_TIME.Get()
3945            && (deme.GetNormalizedTimeUsed() >= m_world->GetConfig().DEMES_REPLICATE_TIME.Get())) ReplicateDeme(deme, ctx);
3946   else if (m_world->GetConfig().DEMES_REPLICATE_BIRTHS.Get()
3947            && (deme.GetBirthCount() >= m_world->GetConfig().DEMES_REPLICATE_BIRTHS.Get())) ReplicateDeme(deme, ctx);
3948   else if (m_world->GetConfig().DEMES_REPLICATE_ORGS.Get()
3949            && (deme.GetOrgCount() >= m_world->GetConfig().DEMES_REPLICATE_ORGS.Get())) ReplicateDeme(deme, ctx);
3950 }
3951 
3952 // Print out all statistics about individual demes
PrintDemeAllStats(cAvidaContext & ctx)3953 void cPopulation::PrintDemeAllStats(cAvidaContext& ctx)
3954 {
3955   PrintDemeFitness();
3956   PrintDemeLifeFitness();
3957   PrintDemeMerit();
3958   PrintDemeGestationTime();
3959   PrintDemeTasks();
3960   PrintDemeDonor();
3961   PrintDemeReceiver();
3962   PrintDemeMutationRate();
3963   PrintDemeResource(ctx);
3964   PrintDemeInstructions();
3965 
3966   if (m_world->GetConfig().ENERGY_ENABLED.Get() == 1) {
3967     PrintDemeSpatialEnergyData();
3968     PrintDemeSpatialSleepData();
3969   }
3970 }
3971 
PrintDemeTestamentStats(const cString & filename)3972 void cPopulation::PrintDemeTestamentStats(const cString& filename) {
3973   cStats& stats = m_world->GetStats();
3974 
3975   cDataFile& df = m_world->GetDataFile(filename);
3976   df.WriteTimeStamp();
3977   df.Write(m_world->GetStats().GetUpdate(), "Update");
3978   df.Write(stats.SumEnergyTestamentToDemeOrganisms().Average(),     "Energy Testament to Deme Organisms");
3979   df.Write(stats.SumEnergyTestamentToFutureDeme().Average(),        "Energy Testament to Future Deme");
3980   df.Write(stats.SumEnergyTestamentToNeighborOrganisms().Average(), "Energy Testament to Neighbor Organisms");
3981   df.Write(stats.SumEnergyTestamentAcceptedByDeme().Average(),      "Energy Testament Accepted by Future Deme");
3982   df.Write(stats.SumEnergyTestamentAcceptedByOrganisms().Average(), "Energy Testament Accepted by Organisms");
3983   df.Endl();
3984 
3985 
3986   stats.SumEnergyTestamentToDemeOrganisms().Clear();
3987   stats.SumEnergyTestamentToFutureDeme().Clear();
3988   stats.SumEnergyTestamentToNeighborOrganisms().Clear();
3989 }
3990 
PrintCurrentMeanDemeDensity(const cString & filename)3991 void cPopulation::PrintCurrentMeanDemeDensity(const cString& filename) {
3992 	cDoubleSum demeDensity;
3993 	demeDensity.Clear();
3994 	const int num_demes = deme_array.GetSize();
3995 	for (int deme_id = 0; deme_id < num_demes; ++deme_id) {
3996     const cDeme & cur_deme = deme_array[deme_id];
3997 		demeDensity.Add(cur_deme.GetDensity());
3998 	}
3999 
4000 	cDataFile& df = m_world->GetDataFile(filename);
4001   df.WriteTimeStamp();
4002   df.Write(m_world->GetStats().GetUpdate(), "Update");
4003 	df.Write(demeDensity.Average(), "Current mean deme density");
4004 	df.Endl();
4005 }
4006 
4007 // Print some stats about the energy sharing behavior of each deme
PrintDemeEnergySharingStats()4008 void cPopulation::PrintDemeEnergySharingStats() {
4009   const int num_demes = deme_array.GetSize();
4010   cStats& stats = m_world->GetStats();
4011   cDataFile & df_donor = m_world->GetDataFile("deme_energy_sharing.dat");
4012   df_donor.WriteComment("Average energy donation statistics for each deme in population");
4013   df_donor.WriteTimeStamp();
4014   df_donor.Write(stats.GetUpdate(), "update");
4015 
4016   double num_requestors = 0.0;
4017   double num_donors = 0.0;
4018   double num_receivers = 0.0;
4019   double num_donations = 0.0;
4020   double num_receptions = 0.0;
4021   double num_applications = 0.0;
4022   double amount_donated = 0.0;
4023   double amount_received = 0.0;
4024   double amount_applied = 0.0;
4025 
4026   for (int deme_id = 0; deme_id < num_demes; ++deme_id) {
4027     const cDeme & cur_deme = deme_array[deme_id];
4028 
4029     for (int i = 0; i < cur_deme.GetSize(); i++) {
4030       int cur_cell = cur_deme.GetCellID(i);
4031       if (cell_array[cur_cell].IsOccupied() == false) continue;
4032       cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
4033       if (phenotype.IsEnergyRequestor()) num_requestors++;
4034       if (phenotype.IsEnergyDonor()) num_donors++;
4035       if (phenotype.IsEnergyReceiver()) num_receivers++;
4036       num_donations += phenotype.GetNumEnergyDonations();
4037       num_receptions += phenotype.GetNumEnergyReceptions();
4038       num_applications += phenotype.GetNumEnergyApplications();
4039       amount_donated += phenotype.GetAmountEnergyDonated();
4040       amount_received += phenotype.GetAmountEnergyReceived();
4041       amount_applied += phenotype.GetAmountEnergyApplied();
4042     }
4043   }
4044 
4045   df_donor.Write(num_requestors/num_demes, "Average number of organisms that have requested energy");
4046   df_donor.Write(num_donors/num_demes, "Average number of organisms that have donated energy");
4047   df_donor.Write(num_receivers/num_demes, "Average number of organisms that have received energy");
4048   df_donor.Write(num_donations/num_demes, "Average number of donations per deme");
4049   df_donor.Write(num_receptions/num_demes, "Average number of receipts per deme");
4050   df_donor.Write(num_applications/num_demes, "Average number of applications per deme");
4051   df_donor.Write(amount_donated/num_demes, "Average total amount of energy donated per deme");
4052   df_donor.Write(amount_received/num_demes, "Average total amount of energy received per deme");
4053   df_donor.Write(amount_applied/num_demes, "Average total amount of donated energy applied per deme");
4054   df_donor.Endl();
4055 
4056 } //End PrintDemeEnergySharingStats()
4057 
4058 
4059 // Print some stats about the distribution of energy among the cells in a deme
4060 // If a cell is occupied, the amount returned is that of the organism in that cell
4061 // If a cell is not occupied, the amount returned is the amount of energy resource in the cell
PrintDemeEnergyDistributionStats(cAvidaContext & ctx)4062 void cPopulation::PrintDemeEnergyDistributionStats(cAvidaContext& ctx) {
4063   const int num_demes = deme_array.GetSize();
4064   cStats& stats = m_world->GetStats();
4065   cString comment;
4066 
4067   cDoubleSum deme_energy_distribution;
4068 
4069   cDoubleSum overall_average;
4070   cDoubleSum overall_variance;
4071   cDoubleSum overall_stddev;
4072 
4073   cDataFile & df_dist = m_world->GetDataFile("deme_energy_distribution.dat");
4074   comment.Set("Average distribution of energy among cells in each of %d %d x %d demes", num_demes, m_world->GetConfig().WORLD_X.Get(), m_world->GetConfig().WORLD_Y.Get()/num_demes);
4075   df_dist.WriteComment(comment);
4076   df_dist.WriteTimeStamp();
4077   df_dist.Write(stats.GetUpdate(), "Update");
4078 
4079   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4080     const cDeme & cur_deme = deme_array[deme_id];
4081 
4082     for (int i = 0; i < cur_deme.GetSize(); i++) {
4083 
4084       int cur_cell = cur_deme.GetCellID(i);
4085       if (cell_array[cur_cell].IsOccupied() == false) {
4086         deme_energy_distribution.Add(cur_deme.GetCellEnergy(cur_cell, ctx));
4087         continue;
4088       }
4089 
4090       deme_energy_distribution.Add(GetCell(cur_cell).GetOrganism()->GetPhenotype().GetStoredEnergy());
4091     }
4092 
4093     overall_average.Add(deme_energy_distribution.Average());
4094     overall_variance.Add(deme_energy_distribution.Variance());
4095     overall_stddev.Add(deme_energy_distribution.StdDeviation());
4096     deme_energy_distribution.Clear();
4097 
4098   }
4099 
4100   df_dist.Write(overall_average.Average(), "Average of Average Energy Level");
4101   df_dist.Write(overall_variance.Average(), "Average of Energy Level Variance");
4102   df_dist.Write(overall_stddev.Average(), "Average of Energy Level Standard Deviations");
4103 
4104   df_dist.Endl();
4105 
4106 } //End PrintDemeEnergyDistributionStats()
4107 
4108 
4109 // Print some stats about the distribution of energy among the organism in a deme
4110 // If a cell is occupied, the amount returned is that of the organism in that cell
4111 // If a cell is not occupied, 0 energy is returned for that cell.
PrintDemeOrganismEnergyDistributionStats()4112 void cPopulation::PrintDemeOrganismEnergyDistributionStats() {
4113   const int num_demes = deme_array.GetSize();
4114   cStats& stats = m_world->GetStats();
4115   cString comment;
4116 
4117   cDoubleSum deme_energy_distribution;
4118 
4119   cDoubleSum overall_average;
4120   cDoubleSum overall_variance;
4121   cDoubleSum overall_stddev;
4122 
4123   cDataFile & df_dist = m_world->GetDataFile("deme_org_energy_distribution.dat");
4124   comment.Set("Average distribution of energy among organisms in each of %d %d x %d demes", num_demes, m_world->GetConfig().WORLD_X.Get(), m_world->GetConfig().WORLD_Y.Get()/num_demes);
4125   df_dist.WriteComment(comment);
4126   df_dist.WriteTimeStamp();
4127   df_dist.Write(stats.GetUpdate(), "Update");
4128 
4129   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4130     const cDeme & cur_deme = deme_array[deme_id];
4131 
4132     for (int i = 0; i < cur_deme.GetSize(); i++) {
4133 
4134       int cur_cell = cur_deme.GetCellID(i);
4135       if (cell_array[cur_cell].IsOccupied() == false) {
4136         deme_energy_distribution.Add(0);
4137         continue;
4138       }
4139 
4140       deme_energy_distribution.Add(GetCell(cur_cell).GetOrganism()->GetPhenotype().GetStoredEnergy());
4141     }
4142 
4143     overall_average.Add(deme_energy_distribution.Average());
4144     overall_variance.Add(deme_energy_distribution.Variance());
4145     overall_stddev.Add(deme_energy_distribution.StdDeviation());
4146     deme_energy_distribution.Clear();
4147 
4148   }
4149 
4150   df_dist.Write(overall_average.Average(), "Average of Average Energy Level");
4151   df_dist.Write(overall_variance.Average(), "Average of Energy Level Variance");
4152   df_dist.Write(overall_stddev.Average(), "Average of Energy Level Standard Deviations");
4153 
4154   df_dist.Endl();
4155 
4156 } //End PrintDemeOrganismEnergyDistributionStats()
4157 
4158 
PrintDemeDonor()4159 void cPopulation::PrintDemeDonor() {
4160   cStats& stats = m_world->GetStats();
4161   const int num_demes = deme_array.GetSize();
4162   cDataFile & df_donor = m_world->GetDataFile("deme_donor.dat");
4163   df_donor.WriteComment("Num orgs doing doing a donate for each deme in population");
4164   df_donor.WriteTimeStamp();
4165   df_donor.Write(stats.GetUpdate(), "update");
4166 
4167   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4168     cString comment;
4169     const cDeme & cur_deme = deme_array[deme_id];
4170     cDoubleSum single_deme_donor;
4171 
4172     for (int i = 0; i < cur_deme.GetSize(); i++) {
4173       int cur_cell = cur_deme.GetCellID(i);
4174       if (cell_array[cur_cell].IsOccupied() == false) continue;
4175       cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
4176       single_deme_donor.Add(phenotype.IsDonorLast());
4177     }
4178     comment.Set("Deme %d", deme_id);
4179     df_donor.Write(single_deme_donor.Sum(), comment);
4180   }
4181   df_donor.Endl();
4182 }
4183 
PrintDemeFitness()4184 void cPopulation::PrintDemeFitness() {
4185   cStats& stats = m_world->GetStats();
4186   const int num_demes = deme_array.GetSize();
4187   cDataFile & df_fit = m_world->GetDataFile("deme_fitness.dat");
4188   df_fit.WriteComment("Average fitnesses for each deme in the population");
4189   df_fit.WriteTimeStamp();
4190   df_fit.Write(stats.GetUpdate(), "update");
4191 
4192   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4193     cString comment;
4194     const cDeme & cur_deme = deme_array[deme_id];
4195     cDoubleSum single_deme_fitness;
4196 
4197     for (int i = 0; i < cur_deme.GetSize(); i++) {
4198       int cur_cell = cur_deme.GetCellID(i);
4199       if (cell_array[cur_cell].IsOccupied() == false) continue;
4200       cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
4201       single_deme_fitness.Add(phenotype.GetFitness());
4202     }
4203     comment.Set("Deme %d", deme_id);
4204     df_fit.Write(single_deme_fitness.Ave(), comment);
4205   }
4206   df_fit.Endl();
4207 }
4208 
PrintDemeTotalAvgEnergy(cAvidaContext & ctx)4209 void cPopulation::PrintDemeTotalAvgEnergy(cAvidaContext& ctx) {
4210   cStats& stats = m_world->GetStats();
4211   const int num_demes = deme_array.GetSize();
4212   cDataFile & df_fit = m_world->GetDataFile("deme_totalAvgEnergy.dat");
4213   df_fit.WriteComment("Average energy for demes in the population");
4214   df_fit.WriteTimeStamp();
4215   df_fit.Write(stats.GetUpdate(), "update");
4216 	cDoubleSum avg_energy;
4217 
4218   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4219     const cDeme & cur_deme = deme_array[deme_id];
4220 		avg_energy.Add(cur_deme.CalculateTotalEnergy(ctx));
4221 	}
4222 	df_fit.Write(avg_energy.Ave(), "Total Average Energy");
4223 	df_fit.Endl();
4224 }
4225 
PrintDemeGestationTime()4226 void cPopulation::PrintDemeGestationTime()
4227 {
4228   cStats& stats = m_world->GetStats();
4229   const int num_demes = deme_array.GetSize();
4230   cDataFile & df_gest = m_world->GetDataFile("deme_gest_time.dat");
4231   df_gest.WriteComment("Average gestation time for each deme in population");
4232   df_gest.WriteTimeStamp();
4233   df_gest.Write(stats.GetUpdate(), "update");
4234 
4235   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4236     cString comment;
4237     const cDeme & cur_deme = deme_array[deme_id];
4238     cDoubleSum single_deme_gest_time;
4239 
4240     for (int i = 0; i < cur_deme.GetSize(); i++) {
4241       int cur_cell = cur_deme.GetCellID(i);
4242       if (cell_array[cur_cell].IsOccupied() == false) continue;
4243       cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
4244       single_deme_gest_time.Add(phenotype.GetGestationTime());
4245     }
4246     comment.Set("Deme %d", deme_id);
4247     df_gest.Write(single_deme_gest_time.Ave(), comment);
4248   }
4249   df_gest.Endl();
4250 }
4251 
PrintDemeInstructions()4252 void cPopulation::PrintDemeInstructions()
4253 {
4254   cStats& stats = m_world->GetStats();
4255   const int num_demes = deme_array.GetSize();
4256 
4257   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4258     for (int is_id = 0; is_id < m_world->GetHardwareManager().GetNumInstSets(); is_id++) {
4259       const cString& inst_set = m_world->GetHardwareManager().GetInstSet(is_id).GetInstSetName();
4260       int num_inst = m_world->GetHardwareManager().GetInstSet(is_id).GetSize();
4261 
4262       cDataFile& df_inst = m_world->GetDataFile(cStringUtil::Stringf("deme_instruction-%d-%s.dat", deme_id, (const char*)inst_set));
4263       df_inst.WriteComment(cStringUtil::Stringf("Number of times each instruction is exectued in deme %d", deme_id));
4264       df_inst.WriteTimeStamp();
4265       df_inst.Write(stats.GetUpdate(), "update");
4266 
4267       tArray<cIntSum> single_deme_inst(num_inst);
4268 
4269       const cDeme& cur_deme = deme_array[deme_id];
4270       for (int i = 0; i < cur_deme.GetSize(); i++) {
4271         int cur_cell = cur_deme.GetCellID(i);
4272         if (!cell_array[cur_cell].IsOccupied()) continue;
4273         if (cell_array[cur_cell].GetOrganism()->GetGenome().GetInstSet() != inst_set) continue;
4274         cPhenotype& phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
4275 
4276         for (int j = 0; j < num_inst; j++) single_deme_inst[j].Add(phenotype.GetLastInstCount()[j]);
4277       }
4278 
4279       for (int j = 0; j < num_inst; j++) df_inst.Write((int)single_deme_inst[j].Sum(), cStringUtil::Stringf("Inst %d", j));
4280       df_inst.Endl();
4281     }
4282   }
4283 }
4284 
PrintDemeLifeFitness()4285 void cPopulation::PrintDemeLifeFitness()
4286 {
4287   cStats& stats = m_world->GetStats();
4288   const int num_demes = deme_array.GetSize();
4289   cDataFile & df_life_fit = m_world->GetDataFile("deme_lifetime_fitness.dat");
4290   df_life_fit.WriteComment("Average life fitnesses for each deme in the population");
4291   df_life_fit.WriteTimeStamp();
4292   df_life_fit.Write(stats.GetUpdate(), "update");
4293 
4294   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4295     cString comment;
4296     const cDeme & cur_deme = deme_array[deme_id];
4297     cDoubleSum single_deme_life_fitness;
4298 
4299     for (int i = 0; i < cur_deme.GetSize(); i++) {
4300       int cur_cell = cur_deme.GetCellID(i);
4301       if (cell_array[cur_cell].IsOccupied() == false) continue;
4302       cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
4303       single_deme_life_fitness.Add(phenotype.GetLifeFitness());
4304     }
4305     comment.Set("Deme %d", deme_id);
4306     df_life_fit.Write(single_deme_life_fitness.Ave(), comment);
4307   }
4308   df_life_fit.Endl();
4309 }
4310 
PrintDemeMerit()4311 void cPopulation::PrintDemeMerit()
4312 {
4313   cStats& stats = m_world->GetStats();
4314   const int num_demes = deme_array.GetSize();
4315   cDataFile& df_merit = m_world->GetDataFile("deme_merit.dat");
4316   df_merit.WriteComment("Average merits for each deme in population");
4317   df_merit.WriteTimeStamp();
4318   df_merit.Write(stats.GetUpdate(), "update");
4319 
4320   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4321     cString comment;
4322     const cDeme& cur_deme = deme_array[deme_id];
4323     cDoubleSum single_deme_merit;
4324 
4325     for (int i = 0; i < cur_deme.GetSize(); i++) {
4326       int cur_cell = cur_deme.GetCellID(i);
4327       if (cell_array[cur_cell].IsOccupied() == false) continue;
4328       cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
4329       single_deme_merit.Add(phenotype.GetMerit().GetDouble());
4330     }
4331     comment.Set("Deme %d", deme_id);
4332     df_merit.Write(single_deme_merit.Ave(), comment);
4333   }
4334   df_merit.Endl();
4335 }
4336 
4337 //@JJB**
PrintDemesMeritsData()4338 void cPopulation::PrintDemesMeritsData()
4339 {
4340   const int num_demes = deme_array.GetSize();
4341   cDataFile& df_merits = m_world->GetDataFile("demes_merits.dat");
4342   df_merits.WriteComment("Each deme's current calculated merit");
4343   df_merits.WriteTimeStamp();
4344   df_merits.Write(m_world->GetStats().GetUpdate(), "Update");
4345 
4346   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4347     cString comment;
4348     comment.Set("Deme %d", deme_id);
4349     df_merits.Write(deme_array[deme_id].CalcCurMerit().GetDouble(), comment);
4350   }
4351   df_merits.Endl();
4352 }
4353 
PrintDemeMutationRate()4354 void cPopulation::PrintDemeMutationRate() {
4355   cStats& stats = m_world->GetStats();
4356   const int num_demes = deme_array.GetSize();
4357   cDataFile & df_mut_rates = m_world->GetDataFile("deme_mut_rates.dat");
4358   df_mut_rates.WriteComment("Average mutation rates for organisms in each deme");
4359   df_mut_rates.WriteTimeStamp();
4360   df_mut_rates.Write(stats.GetUpdate(), "update");
4361   cDoubleSum total_mut_rate;
4362 
4363   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4364     cString comment;
4365     const cDeme & cur_deme = deme_array[deme_id];
4366     cDoubleSum single_deme_mut_rate;
4367 
4368     for (int i = 0; i < cur_deme.GetSize(); i++) {
4369       int cur_cell = cur_deme.GetCellID(i);
4370       if (cell_array[cur_cell].IsOccupied() == false) continue;
4371       single_deme_mut_rate.Add(GetCell(cur_cell).GetOrganism()->MutationRates().GetCopyMutProb());
4372     }
4373     comment.Set("Deme %d", deme_id);
4374     df_mut_rates.Write(single_deme_mut_rate.Ave(), comment);
4375     total_mut_rate.Add(single_deme_mut_rate.Ave());
4376   }
4377   df_mut_rates.Write(total_mut_rate.Ave(), "Average deme mutation rate averaged across Demes.");
4378   df_mut_rates.Endl();
4379 }
4380 
PrintDemeReceiver()4381 void cPopulation::PrintDemeReceiver() {
4382   cStats& stats = m_world->GetStats();
4383   const int num_demes = deme_array.GetSize();
4384   cDataFile & df_receiver = m_world->GetDataFile("deme_receiver.dat");
4385   df_receiver.WriteComment("Num orgs doing receiving a donate for each deme in population");
4386   df_receiver.WriteTimeStamp();
4387   df_receiver.Write(stats.GetUpdate(), "update");
4388 
4389   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4390     cString comment;
4391     const cDeme & cur_deme = deme_array[deme_id];
4392     cDoubleSum single_deme_receiver;
4393 
4394     for (int i = 0; i < cur_deme.GetSize(); i++) {
4395       int cur_cell = cur_deme.GetCellID(i);
4396       if (cell_array[cur_cell].IsOccupied() == false) continue;
4397       cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
4398       single_deme_receiver.Add(phenotype.IsReceiver());
4399     }
4400     comment.Set("Deme %d", deme_id);
4401     df_receiver.Write(single_deme_receiver.Sum(), comment);
4402   }
4403   df_receiver.Endl();
4404 }
4405 
PrintDemeResource(cAvidaContext & ctx)4406 void cPopulation::PrintDemeResource(cAvidaContext& ctx) {
4407   cStats& stats = m_world->GetStats();
4408   const int num_demes = deme_array.GetSize();
4409   cDataFile & df_resources = m_world->GetDataFile("deme_resources.dat");
4410   df_resources.WriteComment("Avida deme resource data");
4411   df_resources.WriteTimeStamp();
4412   df_resources.Write(stats.GetUpdate(), "update");
4413 
4414   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4415     cDeme & cur_deme = deme_array[deme_id];
4416 
4417     cur_deme.UpdateDemeRes(ctx);
4418     const cResourceCount& res = GetDeme(deme_id).GetDemeResourceCount();
4419     for(int j = 0; j < res.GetSize(); j++) {
4420       const char * tmp = res.GetResName(j);
4421       df_resources.Write(res.Get(ctx, j), cStringUtil::Stringf("Deme %d Resource %s", deme_id, tmp)); //comment);
4422       if ((res.GetResourcesGeometry())[j] != nGeometry::GLOBAL && (res.GetResourcesGeometry())[j] != nGeometry::PARTIAL) {
4423         PrintDemeSpatialResData(res, j, deme_id, ctx);
4424       }
4425     }
4426   }
4427   df_resources.Endl();
4428 }
4429 
4430 //Write deme global resource levels to a file that can be easily read into Matlab.
4431 //Each time this runs, a Matlab array is created that contains an array.  Each row in the array contains <deme id> <res level 0> ... <res level n>
PrintDemeGlobalResources(cAvidaContext & ctx)4432 void cPopulation::PrintDemeGlobalResources(cAvidaContext& ctx) {
4433   const int num_demes = deme_array.GetSize();
4434   cDataFile & df = m_world->GetDataFile("deme_global_resources.dat");
4435   df.WriteComment("Avida deme resource data");
4436   df.WriteTimeStamp();
4437 
4438   cString UpdateStr = cStringUtil::Stringf( "deme_global_resources_%07i = [ ...", m_world->GetStats().GetUpdate());
4439   df.WriteRaw(UpdateStr);
4440 
4441   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4442     cDeme & cur_deme = deme_array[deme_id];
4443     cur_deme.UpdateDemeRes(ctx);
4444 
4445     const cResourceCount & res = GetDeme(deme_id).GetDemeResourceCount();
4446     const int num_res = res.GetSize();
4447 
4448     df.WriteBlockElement(deme_id, 0, num_res + 1);
4449 
4450     for(int r = 0; r < num_res; r++) {
4451       if (!res.IsSpatial(r)) {
4452         df.WriteBlockElement(res.Get(ctx, r), r + 1, num_res + 1);
4453       }
4454 
4455     } //End iterating through resources
4456 
4457   } //End iterating through demes
4458 
4459   df.WriteRaw("];");
4460   df.Endl();
4461 }
4462 
4463 
4464 // Write spatial energy data to a file that can easily be read into Matlab
PrintDemeSpatialEnergyData() const4465 void cPopulation::PrintDemeSpatialEnergyData() const {
4466   int cellID = 0;
4467   int update = m_world->GetStats().GetUpdate();
4468 
4469   for(int i = 0; i < m_world->GetPopulation().GetNumDemes(); i++) {
4470     cString tmpfilename = cStringUtil::Stringf( "deme_%07i_spatial_energy.m", i);  // moved here for easy movie making
4471     cDataFile& df = m_world->GetDataFile(tmpfilename);
4472     cString UpdateStr = cStringUtil::Stringf( "deme_%07i_energy_%07i = [ ...", i, update );
4473     df.WriteRaw(UpdateStr);
4474 
4475     int gridsize = m_world->GetPopulation().GetDeme(i).GetSize();
4476     int xsize = m_world->GetConfig().WORLD_X.Get();
4477 
4478     // write grid to file
4479     for (int j = 0; j < gridsize; j++) {
4480       cPopulationCell& cell = m_world->GetPopulation().GetCell(cellID);
4481       if (cell.IsOccupied()) {
4482         df.WriteBlockElement(cell.GetOrganism()->GetPhenotype().GetStoredEnergy(), j, xsize);
4483       } else {
4484         df.WriteBlockElement(0.0, j, xsize);
4485       }
4486       cellID++;
4487     }
4488     df.WriteRaw("];");
4489     df.Endl();
4490   }
4491 }
4492 
4493 // Write spatial data to a file that can easily be read into Matlab
PrintDemeSpatialResData(const cResourceCount & res,const int i,const int deme_id,cAvidaContext & ctx) const4494 void cPopulation::PrintDemeSpatialResData(const cResourceCount& res, const int i, const int deme_id, cAvidaContext& ctx) const {
4495   const char* tmpResName = res.GetResName(i);
4496   cString tmpfilename = cStringUtil::Stringf( "deme_spatial_resource_%s.m", tmpResName );
4497   cDataFile& df = m_world->GetDataFile(tmpfilename);
4498   cString UpdateStr = cStringUtil::Stringf( "deme_%07i_%s_%07i = [ ...", deme_id, static_cast<const char*>(res.GetResName(i)), m_world->GetStats().GetUpdate() );
4499 
4500   df.WriteRaw(UpdateStr);
4501 
4502   const cSpatialResCount& sp_res = res.GetSpatialResource(i);
4503   int gridsize = sp_res.GetSize();
4504   int xsize = m_world->GetConfig().WORLD_X.Get();
4505 
4506   for (int j = 0; j < gridsize; j++) {
4507     df.WriteBlockElement(sp_res.GetAmount(j), j, xsize);
4508   }
4509   df.WriteRaw("];");
4510   df.Endl();
4511 }
4512 
4513 // Write spatial energy data to a file that can easily be read into Matlab
PrintDemeSpatialSleepData() const4514 void cPopulation::PrintDemeSpatialSleepData() const {
4515   int cellID = 0;
4516   cString tmpfilename = "deme_spatial_sleep.m";
4517   cDataFile& df = m_world->GetDataFile(tmpfilename);
4518   int update = m_world->GetStats().GetUpdate();
4519 
4520   for(int i = 0; i < m_world->GetPopulation().GetNumDemes(); i++) {
4521     cString UpdateStr = cStringUtil::Stringf( "deme_%07i_sleep_%07i = [ ...", i, update);
4522     df.WriteRaw(UpdateStr);
4523 
4524     int gridsize = m_world->GetPopulation().GetDeme(i).GetSize();
4525     int xsize = m_world->GetConfig().WORLD_X.Get();
4526 
4527     // write grid to file
4528     for (int j = 0; j < gridsize; j++) {
4529       cPopulationCell cell = m_world->GetPopulation().GetCell(cellID);
4530       if (cell.IsOccupied()) {
4531         df.WriteBlockElement(cell.GetOrganism()->IsSleeping(), j, xsize);
4532       } else {
4533         df.WriteBlockElement(0.0, j, xsize);
4534       }
4535       cellID++;
4536     }
4537     df.WriteRaw("];");
4538     df.Endl();
4539   }
4540 }
4541 
PrintDemeTasks()4542 void cPopulation::PrintDemeTasks() {
4543   cStats& stats = m_world->GetStats();
4544   const int num_demes = deme_array.GetSize();
4545   const int num_task = environment.GetNumTasks();
4546   cDataFile & df_task = m_world->GetDataFile("deme_task.dat");
4547   df_task.WriteComment("Num orgs doing each task for each deme in population");
4548   df_task.WriteTimeStamp();
4549   df_task.Write(stats.GetUpdate(), "update");
4550 
4551   for (int deme_id = 0; deme_id < num_demes; deme_id++) {
4552     cString comment;
4553     const cDeme & cur_deme = deme_array[deme_id];
4554     tArray<cIntSum> single_deme_task(num_task);
4555 
4556     for (int i = 0; i < cur_deme.GetSize(); i++) {
4557       int cur_cell = cur_deme.GetCellID(i);
4558       if (cell_array[cur_cell].IsOccupied() == false) continue;
4559       cPhenotype & phenotype = GetCell(cur_cell).GetOrganism()->GetPhenotype();
4560       for (int j = 0; j < num_task; j++) {
4561         // only interested if task is done once!
4562         if (phenotype.GetLastTaskCount()[j] > 0) {
4563           single_deme_task[j].Add(1);
4564         }
4565       }
4566     }
4567     for (int j = 0; j < num_task; j++) {
4568       comment.Set("Deme %d, Task %d", deme_id, j);
4569       df_task.Write((int) single_deme_task[j].Sum(), comment);
4570     }
4571   }
4572   df_task.Endl();
4573 }
4574 
DumpDemeFounders(ofstream & fp)4575 void cPopulation::DumpDemeFounders(ofstream& fp) {
4576   fp << "#filetype deme_founders" << endl
4577   << "#format deme_id num_founders genotype_ids" << endl
4578   << endl
4579   << "#  1: Deme ID" << endl
4580   << "#  2: Number of founders" << endl
4581   << "#  3+: founder genotype ids" << endl << endl;
4582 
4583   for(int i=0; i<deme_array.GetSize(); i++) {
4584 
4585     if (deme_array[i].IsEmpty()) continue;
4586 
4587     tArray<int>& deme_founders = deme_array[i].GetFounderGenotypeIDs();
4588 
4589     fp << i << " " << deme_founders.GetSize();
4590     for(int j=0; j<deme_founders.GetSize(); j++) {
4591       fp << " " << deme_founders[j];
4592     }
4593 
4594     fp << endl;
4595   }
4596 }
4597 
4598 
4599 
4600 
4601 /**
4602  This function will set up coalescence clade information.  If this feature is activated in the configuration,
4603  a list of coalescence genotype ids must be read in initially.  These are furnished by doing an initial run
4604  with the same seed and setup and retrieving information from the final dominant lineage and coalescence points.
4605 
4606  The value is either (by default) inherited from the parent or the organism's genotypeID if it is known
4607  to be a coalescence id.
4608 
4609  Defaulting is established in Inject or ActivateOffspring methods of this class.
4610 
4611  @MRR May 2007
4612  **/
CCladeSetupOrganism(cOrganism * organism)4613 void cPopulation::CCladeSetupOrganism(cOrganism* organism)
4614 {
4615   //  int gen_id = organism->GetBioGroup("genotype")->GetID();
4616   if (m_world->GetConfig().TRACK_CCLADES.Get() > 0) {
4617     // @TODO - support for IsCCladeFounder?
4618     //    if (m_world->GetClassificationManager().IsCCladeFounder(gen_id)) organism->SetCCladeLabel(gen_id);
4619   }
4620 }
4621 
4622 
4623 /**
4624  * This function directs which position function should be used.  It
4625  * could have also been done with a function pointer, but the dividing
4626  * of an organism takes enough time that this will be a negligible addition,
4627  * and it gives a centralized function to work with.  The parent_ok flag asks
4628  * if it is okay to replace the parent.
4629  **/
4630 //@AWC -- This could REALLY stand some functional abstraction...
PositionOffspring(cPopulationCell & parent_cell,cAvidaContext & ctx,bool parent_ok)4631 cPopulationCell& cPopulation::PositionOffspring(cPopulationCell& parent_cell, cAvidaContext& ctx, bool parent_ok)
4632 {
4633   assert(parent_cell.IsOccupied());
4634 
4635   const int birth_method = m_world->GetConfig().BIRTH_METHOD.Get();
4636 
4637   // Handle Population Cap (if enabled)
4638   int pop_cap = m_world->GetConfig().POPULATION_CAP.Get();
4639   if (pop_cap > 0 && num_organisms >= pop_cap) {
4640     int num_kills = 1;
4641     if (pop_enforce > 1 && num_organisms != pop_cap) num_kills += min(num_organisms - pop_cap, pop_enforce);
4642 
4643     while (num_kills > 0) {
4644       int target = m_world->GetRandom().GetUInt(live_org_list.GetSize());
4645       int cell_id = live_org_list[target]->GetCellID();
4646       if (cell_id == parent_cell.GetID()) {
4647         target++;
4648         if (target >= live_org_list.GetSize()) target = 0;
4649         cell_id = live_org_list[target]->GetCellID();
4650       }
4651       KillOrganism(cell_array[cell_id], ctx);
4652       num_kills--;
4653     }
4654   }
4655 
4656   // Handle Pop Cap Eldest (if enabled)
4657   int pop_eldest = m_world->GetConfig().POP_CAP_ELDEST.Get();
4658   if (pop_eldest > 0 && num_organisms >= pop_eldest) {
4659     int num_kills = 1;
4660     if (pop_enforce > 1 && num_organisms != pop_cap) num_kills += min(num_organisms - pop_cap, pop_enforce);
4661 
4662     while (num_kills > 0) {
4663       double max_age = 0.0;
4664       double max_msr = 0.0;
4665       int cell_id = 0;
4666       for (int i = 0; i < live_org_list.GetSize(); i++) {
4667         if (GetCell(live_org_list[i]->GetCellID()).IsOccupied() && live_org_list[i]->GetCellID() != parent_cell.GetID()) {
4668           double age = live_org_list[i]->GetPhenotype().GetAge();
4669           if (age > max_age) {
4670             max_age = age;
4671             cell_id = live_org_list[i]->GetCellID();
4672           }
4673           else if (age == max_age) {
4674             double msr = m_world->GetRandom().GetDouble();
4675             if (msr > max_msr) {
4676               max_msr = msr;
4677               cell_id = live_org_list[i]->GetCellID();
4678             }
4679           }
4680         }
4681       }
4682       KillOrganism(cell_array[cell_id], ctx);
4683       num_kills--;
4684     }
4685   }
4686 
4687 	// increment the number of births in the **parent deme**.  in the case of a
4688 	// migration, only the origin has its birth count incremented.
4689   if (deme_array.GetSize() > 0) {
4690     const int deme_id = parent_cell.GetDemeID();
4691     deme_array[deme_id].IncBirthCount();
4692   }
4693 
4694   // Decide if offspring will migrate to another deme -- if migrating we ignore the birth method.
4695   if (m_world->GetConfig().MIGRATION_RATE.Get() > 0.0 &&
4696       m_world->GetRandom().P(m_world->GetConfig().MIGRATION_RATE.Get())) {
4697 
4698     //cerr << "Attempting to migrate with rate " << m_world->GetConfig().MIGRATION_RATE.Get() << "!" << endl;
4699     int deme_id = parent_cell.GetDemeID();
4700 
4701     //get another -unadjusted- deme id
4702     int rnd_deme_id = m_world->GetRandom().GetInt(deme_array.GetSize()-1);
4703 
4704     //if the -unadjusted- id is above the excluded id, bump it up one
4705     //insures uniform prob of landing in any deme but the parent's
4706     if (rnd_deme_id >= deme_id) rnd_deme_id++;
4707 
4708     //set the new deme_id
4709     deme_id = rnd_deme_id;
4710 
4711     //The rest of this is essentially POSITION_OFFSPRING_DEME_RANDOM
4712     //@JEB: But note that this will not honor PREFER_EMPTY in the new deme.
4713     const int deme_size = deme_array[deme_id].GetSize();
4714 
4715     int out_pos = m_world->GetRandom().GetUInt(deme_size);
4716     int out_cell_id = deme_array[deme_id].GetCellID(out_pos);
4717     while (parent_ok == false && out_cell_id == parent_cell.GetID()) {
4718       out_pos = m_world->GetRandom().GetUInt(deme_size);
4719       out_cell_id = deme_array[deme_id].GetCellID(out_pos);
4720     }
4721 
4722     GetCell(out_cell_id).SetMigrant();
4723     return GetCell(out_cell_id);
4724   }
4725   // Fix so range can be arbitrary and we won't accidentally include ourself as a target
4726   // @AWC If not migrating try out global/full-deme birth methods first...
4727 
4728   // Similar to MIGRATION_RATE code above but allows for a bit more flexibility
4729   // in how migration between demes works. Also, respects PREFER_EMPTY in new deme.
4730   // Temporary until Deme
4731   if ((m_world->GetConfig().DEMES_MIGRATION_RATE.Get() > 0.0)
4732       && m_world->GetRandom().P(m_world->GetConfig().DEMES_MIGRATION_RATE.Get()))
4733   {
4734     return PositionDemeMigration(parent_cell, parent_ok);
4735   }
4736 
4737   // This block should be changed to a switch statment with functions handling
4738   // the cases. For now, a bunch of if's that return if they handle.
4739 
4740   if (birth_method == POSITION_OFFSPRING_FULL_SOUP_RANDOM) {
4741     // Look randomly within empty cells first, if requested
4742     if (m_world->GetConfig().PREFER_EMPTY.Get()) {
4743       int cell_id = FindRandEmptyCell();
4744       if (cell_id == -1) return GetCell(m_world->GetRandom().GetUInt(cell_array.GetSize()));
4745       else return GetCell(cell_id);
4746     }
4747 
4748     int out_pos = m_world->GetRandom().GetUInt(cell_array.GetSize());
4749     while (parent_ok == false && out_pos == parent_cell.GetID()) {
4750       out_pos = m_world->GetRandom().GetUInt(cell_array.GetSize());
4751     }
4752     return GetCell(out_pos);
4753   }
4754 
4755   if (birth_method == POSITION_OFFSPRING_FULL_SOUP_ELDEST) {
4756     cPopulationCell * out_cell = reaper_queue.PopRear();
4757     if (parent_ok == false && out_cell->GetID() == parent_cell.GetID()) {
4758       out_cell = reaper_queue.PopRear();
4759       reaper_queue.PushRear(&parent_cell);
4760     }
4761     return *out_cell;
4762   }
4763 
4764   if (birth_method == POSITION_OFFSPRING_DEME_RANDOM) {
4765     return PositionDemeRandom(parent_cell.GetDemeID(), parent_cell, parent_ok);
4766   }
4767   else if (birth_method == POSITION_OFFSPRING_PARENT_FACING) {
4768     return parent_cell.GetCellFaced();
4769   }
4770   else if (birth_method == POSITION_OFFSPRING_NEXT_CELL) {
4771     int out_cell_id = parent_cell.GetID() + 1;
4772     if (out_cell_id == cell_array.GetSize()) out_cell_id = 0;
4773     return GetCell(out_cell_id);
4774   }
4775   else if (birth_method == POSITION_OFFSPRING_FULL_SOUP_ENERGY_USED) {
4776     tList<cPopulationCell> found_list;
4777     int max_time_used = 0;
4778     for  (int i=0; i < cell_array.GetSize(); i++)
4779     {
4780       int time_used = cell_array[i].IsOccupied() ? cell_array[i].GetOrganism()->GetPhenotype().GetTimeUsed() : INT_MAX;
4781       if (time_used == max_time_used)
4782       {
4783         found_list.Push(&cell_array[i]);
4784       }
4785       else if (time_used > max_time_used)
4786       {
4787         max_time_used = time_used;
4788         found_list.Clear();
4789         found_list.Push(&cell_array[i]);
4790       }
4791     }
4792     int choice = m_world->GetRandom().GetUInt(found_list.GetSize());
4793     return *( found_list.GetPos(choice) );
4794   }
4795 
4796   // All remaining methods require us to choose among mulitple local positions.
4797 
4798   // Construct a list of equally viable locations to place the child...
4799   tList<cPopulationCell> found_list;
4800 
4801   // First, check if there is an empty organism to work with (always preferred)
4802   tList<cPopulationCell>& conn_list = parent_cell.ConnectionList();
4803 
4804   const bool prefer_empty = m_world->GetConfig().PREFER_EMPTY.Get();
4805 
4806   if (birth_method == POSITION_OFFSPRING_DISPERSAL && conn_list.GetSize() > 0) {
4807     tList<cPopulationCell>* disp_list = &conn_list;
4808 
4809     // hop through connection lists based on the dispersal rate
4810     int hops = m_world->GetRandom().GetRandPoisson(m_world->GetConfig().DISPERSAL_RATE.Get());
4811     for (int i = 0; i < hops; i++) {
4812       disp_list = &(disp_list->GetPos(m_world->GetRandom().GetUInt(disp_list->GetSize()))->ConnectionList());
4813       if (disp_list->GetSize() == 0) break;
4814     }
4815 
4816     // if prefer empty, select an empty cell from the final connection list
4817     if (prefer_empty) FindEmptyCell(*disp_list, found_list);
4818 
4819     // if prefer empty is off, or there are no empty cells, use the whole connection list as possiblities
4820     if (found_list.GetSize() == 0) {
4821       found_list = *disp_list;
4822       // if no hops were taken and ALLOW_PARENT is set, throw the parent cell into the hat for possible selection
4823       if (hops == 0 && parent_ok) found_list.Push(&parent_cell);
4824     }
4825   } else if (prefer_empty) {
4826     FindEmptyCell(conn_list, found_list);
4827   }
4828 
4829   // If we have not found an empty organism, we must use the specified function
4830   // to determine how to choose among the filled organisms.
4831   if (found_list.GetSize() == 0) {
4832     switch(birth_method) {
4833       case POSITION_OFFSPRING_AGE:
4834         PositionAge(parent_cell, found_list, parent_ok);
4835         break;
4836       case POSITION_OFFSPRING_MERIT:
4837         PositionMerit(parent_cell, found_list, parent_ok);
4838         break;
4839       case POSITION_OFFSPRING_RANDOM:
4840         found_list.Append(conn_list);
4841         if (parent_ok == true) found_list.Push(&parent_cell);
4842         break;
4843       case POSITION_OFFSPRING_NEIGHBORHOOD_ENERGY_USED:
4844         PositionEnergyUsed(parent_cell, found_list, parent_ok);
4845       case POSITION_OFFSPRING_EMPTY:
4846         // Nothing is in list if no empty cells are found...
4847         break;
4848     }
4849   }
4850 
4851   // If there are no possibilities, return parent.
4852   if (found_list.GetSize() == 0) return parent_cell;
4853 
4854   // Choose the organism randomly from those in the list, and return it.
4855   int choice = m_world->GetRandom().GetUInt(found_list.GetSize());
4856   return *( found_list.GetPos(choice) );
4857 }
4858 
PositionAge(cPopulationCell & parent_cell,tList<cPopulationCell> & found_list,bool parent_ok)4859 void cPopulation::PositionAge(cPopulationCell & parent_cell,
4860                               tList<cPopulationCell> & found_list,
4861                               bool parent_ok)
4862 {
4863   // Start with the parent organism as the replacement, and see if we can find
4864   // anything equivilent or better.
4865 
4866   found_list.Push(&parent_cell);
4867   int max_age = parent_cell.GetOrganism()->GetPhenotype().GetAge();
4868   if (parent_ok == false) max_age = -1;
4869 
4870   // Now look at all of the neighbors.
4871   tListIterator<cPopulationCell> conn_it( parent_cell.ConnectionList() );
4872 
4873   cPopulationCell * test_cell;
4874   while ( (test_cell = conn_it.Next()) != NULL) {
4875     const int cur_age = test_cell->GetOrganism()->GetPhenotype().GetAge();
4876     if (cur_age > max_age) {
4877       max_age = cur_age;
4878       found_list.Clear();
4879       found_list.Push(test_cell);
4880     }
4881     else if (cur_age == max_age) {
4882       found_list.Push(test_cell);
4883     }
4884   }
4885 }
4886 
PositionMerit(cPopulationCell & parent_cell,tList<cPopulationCell> & found_list,bool parent_ok)4887 void cPopulation::PositionMerit(cPopulationCell & parent_cell,
4888                                 tList<cPopulationCell> & found_list,
4889                                 bool parent_ok)
4890 {
4891   // Start with the parent organism as the replacement, and see if we can find
4892   // anything equivilent or better.
4893 
4894   found_list.Push(&parent_cell);
4895   double max_ratio = parent_cell.GetOrganism()->CalcMeritRatio();
4896   if (parent_ok == false) max_ratio = -1;
4897 
4898   // Now look at all of the neighbors.
4899   tListIterator<cPopulationCell> conn_it( parent_cell.ConnectionList() );
4900 
4901   cPopulationCell * test_cell;
4902   while ( (test_cell = conn_it.Next()) != NULL) {
4903     const double cur_ratio = test_cell->GetOrganism()->CalcMeritRatio();
4904     if (cur_ratio > max_ratio) {
4905       max_ratio = cur_ratio;
4906       found_list.Clear();
4907       found_list.Push(test_cell);
4908     }
4909     else if (cur_ratio == max_ratio) {
4910       found_list.Push(test_cell);
4911     }
4912   }
4913 }
4914 
PositionEnergyUsed(cPopulationCell & parent_cell,tList<cPopulationCell> & found_list,bool parent_ok)4915 void cPopulation::PositionEnergyUsed(cPopulationCell & parent_cell,
4916                                      tList<cPopulationCell> & found_list,
4917                                      bool parent_ok)
4918 {
4919   // Start with the parent organism as the replacement, and see if we can find
4920   // anything equivilent or better.
4921 
4922   found_list.Push(&parent_cell);
4923   int max_energy_used = parent_cell.GetOrganism()->GetPhenotype().GetTimeUsed();
4924   if (parent_ok == false) max_energy_used = -1;
4925 
4926   // Now look at all of the neighbors.
4927   tListIterator<cPopulationCell> conn_it( parent_cell.ConnectionList() );
4928 
4929   cPopulationCell * test_cell;
4930   while ( (test_cell = conn_it.Next()) != NULL) {
4931     const int cur_energy_used = test_cell->GetOrganism()->GetPhenotype().GetTimeUsed();
4932     if (cur_energy_used > max_energy_used) {
4933       max_energy_used = cur_energy_used;
4934       found_list.Clear();
4935       found_list.Push(test_cell);
4936     }
4937     else if (cur_energy_used == max_energy_used) {
4938       found_list.Push(test_cell);
4939     }
4940   }
4941 }
4942 
4943 // This function handles PositionOffspring() when there is migration between demes
PositionDemeMigration(cPopulationCell & parent_cell,bool parent_ok)4944 cPopulationCell& cPopulation::PositionDemeMigration(cPopulationCell& parent_cell, bool parent_ok)
4945 {
4946   int deme_id = parent_cell.GetDemeID();
4947 	int parent_id = parent_cell.GetDemeID();
4948 	GetDeme(deme_id).AddMigrationOut();
4949 
4950   // Position randomly in any other deme
4951   if (m_world->GetConfig().DEMES_MIGRATION_METHOD.Get() == 0) {
4952 
4953     //get another -unadjusted- deme id
4954     int rnd_deme_id = m_world->GetRandom().GetInt(deme_array.GetSize()-1);
4955 
4956     //if the -unadjusted- id is above the excluded id, bump it up one
4957     //insures uniform prob of landing in any deme but the parent's
4958     if (rnd_deme_id >= deme_id) rnd_deme_id++;
4959 
4960     //set the new deme_id
4961     deme_id = rnd_deme_id;
4962   }
4963 
4964   //Position randomly in an adjacent deme in neighborhood (assuming torus)
4965   //Extremely hacked DEMES_NUM_X config setting simulates grid
4966   else if (m_world->GetConfig().DEMES_MIGRATION_METHOD.Get() == 1) {
4967 
4968     //get a random eight-neighbor
4969     int dir = m_world->GetRandom().GetInt(8);
4970 
4971     // 0 = NW, 1=N, continuing clockwise....
4972 
4973     // Up one row
4974     if (m_world->GetConfig().DEMES_NUM_X.Get() == 0) {
4975       m_world->GetDriver().RaiseFatalException(1, "DEMES_NUM_X must be non-zero if DEMES_MIGRATION_METHOD 1 used.");
4976     }
4977     int x_size = m_world->GetConfig().DEMES_NUM_X.Get();
4978     int y_size = (int) (m_world->GetConfig().NUM_DEMES.Get() / x_size);
4979 
4980     assert(y_size * x_size == m_world->GetConfig().NUM_DEMES.Get());
4981 
4982     int x = deme_id % x_size;
4983     int y = (int) (deme_id / x_size);
4984 
4985     if ( (dir == 0) || (dir == 1) || (dir == 2) ) y--;
4986     if ( (dir == 5) || (dir == 6) || (dir == 7) ) y++;
4987     if ( (dir == 0) || (dir == 3) || (dir == 5) ) x--;
4988     if ( (dir == 2) || (dir == 4) || (dir == 7) ) x++;
4989 
4990     //handle boundary conditions...
4991 
4992     x = (x + x_size) % x_size;
4993     y = (y + y_size) % y_size;
4994 
4995     //set the new deme_id
4996     deme_id = x + x_size * y;
4997 
4998     assert(deme_id > 0);
4999     assert(deme_id > 0);
5000   }
5001 
5002   //Random deme adjacent in list
5003   else if (m_world->GetConfig().DEMES_MIGRATION_METHOD.Get() == 2) {
5004 
5005     //get a random direction to move in deme list
5006     int rnd_deme_id = m_world->GetRandom().GetInt(1);
5007     if (rnd_deme_id == 0) rnd_deme_id = -1;
5008 
5009     //set the new deme_id
5010     deme_id = (deme_id + rnd_deme_id + GetNumDemes()) % GetNumDemes();
5011   }
5012 
5013   //Proportional-based on a points system (hjg)
5014   // The odds of a deme being selected are inversely proportional to the
5015   // number of points it has.
5016   else if (m_world->GetConfig().DEMES_MIGRATION_METHOD.Get() == 3) {
5017 
5018     double total_points = 0;
5019     int num_demes = GetNumDemes();
5020 
5021     // Identify how many points are in the population as a whole.
5022     for (int did = 0; did < num_demes; did++) {
5023       if (did != parent_id) {
5024         total_points +=  (1/(1+GetDeme(did).GetNumberOfPoints()));
5025       }
5026     }
5027     // Select a random number from 0 to 1:
5028     double rand_point = m_world->GetRandom().GetDouble(0, total_points);
5029 
5030     // Iterate through the demes until you find the appropriate
5031     // deme to insert the organism into.
5032     double lower_point = 0;
5033     double upper_point = 0;
5034 
5035     for (int curr_deme = 0; curr_deme < num_demes; curr_deme++) {
5036       if (curr_deme != parent_id){
5037         upper_point = lower_point + (1+GetDeme(curr_deme).GetNumberOfPoints());
5038         if ((lower_point <= rand_point) && (rand_point < upper_point)) {
5039           deme_id = curr_deme;
5040         }
5041         lower_point = upper_point;
5042       }
5043     }
5044   }
5045 
5046   else if (m_world->GetConfig().DEMES_MIGRATION_METHOD.Get() == 4){
5047       // MIGRATION_MATRIX
5048       deme_id = m_world->GetMigrationMatrix().GetProbabilisticDemeID(parent_id,m_world->GetRandom(),false);
5049   }
5050 
5051   GetDeme(deme_id).AddMigrationIn();
5052 
5053   // TODO the above choice of deme does not respect PREFER_EMPTY
5054   // i.e., it does not preferentially pick a deme with empty cells if they are
5055   // it might make sense for that to happen...
5056 
5057   // Now return an empty cell from the chosen deme
5058 
5059   cPopulationCell& mig_cell = PositionDemeRandom(deme_id, parent_cell, parent_ok);
5060   mig_cell.SetMigrant();
5061   return mig_cell;
5062 }
5063 
5064 // This function handles PositionOffspring() by returning a random cell from the entire deme.
PositionDemeRandom(int deme_id,cPopulationCell & parent_cell,bool parent_ok)5065 cPopulationCell& cPopulation::PositionDemeRandom(int deme_id, cPopulationCell& parent_cell, bool parent_ok)
5066 {
5067   assert((deme_id >=0) && (deme_id < deme_array.GetSize()));
5068 
5069   const int deme_size = deme_array[deme_id].GetSize();
5070   cDeme& deme = deme_array[deme_id];
5071 
5072   // Look randomly within empty cells first, if requested
5073   if (m_world->GetConfig().PREFER_EMPTY.Get()) {
5074 
5075     int num_empty_cells = UpdateEmptyCellIDArray(deme_id);
5076     if (num_empty_cells > 0) {
5077       int out_pos = m_world->GetRandom().GetUInt(num_empty_cells);
5078       return GetCell(empty_cell_id_array[out_pos]);
5079     }
5080   }
5081 
5082   int out_pos = m_world->GetRandom().GetUInt(deme_size);
5083   int out_cell_id = deme.GetCellID(out_pos);
5084 
5085   while (parent_ok == false && out_cell_id == parent_cell.GetID()) {
5086     out_pos = m_world->GetRandom().GetUInt(deme_size);
5087     out_cell_id = deme.GetCellID(out_pos);
5088   }
5089 
5090   return GetCell(out_cell_id);
5091 }
5092 
FindRandEmptyCell()5093 int cPopulation::FindRandEmptyCell()
5094 {
5095   int world_size = cell_array.GetSize();
5096   // full world
5097   if (num_organisms >= world_size) return -1;
5098 
5099   tArray<int>& cells = GetEmptyCellIDArray();
5100   int cell_idx = m_world->GetRandom().GetUInt(world_size);
5101   int cell_id = cells[cell_idx];
5102   while (GetCell(cell_id).IsOccupied()) {
5103     // no need to pop this cell off the array, just move it and don't check that far anymore
5104     cells.Swap(cell_idx, --world_size);
5105     // if ran out of cells to check (e.g. with birth chamber weirdness)
5106     if (world_size == 1) return -1;
5107     cell_idx = m_world->GetRandom().GetUInt(world_size);
5108     cell_id = cells[cell_idx];
5109   }
5110   return cell_id;
5111 }
5112 
5113 // This function updates the list of empty cell ids in the population
5114 // and returns the number of empty cells found. Used by global PREFER_EMPTY
5115 // PositionOffspring() methods with demes (only).
UpdateEmptyCellIDArray(int deme_id)5116 int cPopulation::UpdateEmptyCellIDArray(int deme_id)
5117 {
5118   int num_empty_cells = 0;
5119   // Note: empty_cell_id_array was resized to be large enough to hold
5120   // all cells in the cPopulation when it was created. Using functions
5121   // that resize it (like Push) will slow this code down considerably.
5122   // Instead, we keep track of how much of this memory we are using.
5123 
5124   // Look at all cells
5125   if (deme_id == -1) {
5126     for (int i=0; i<cell_array.GetSize(); i++) {
5127       if (GetCell(i).IsOccupied() == false) empty_cell_id_array[num_empty_cells++] = i;
5128     }
5129   }
5130   // Look at a specific deme
5131   else {
5132     cDeme& deme = deme_array[deme_id];
5133     for (int i=0; i<deme.GetSize(); i++) {
5134       if (GetCell(deme.GetCellID(i)).IsOccupied() == false) empty_cell_id_array[num_empty_cells++] = deme.GetCellID(i);
5135     }
5136   }
5137   return num_empty_cells;
5138 }
5139 
5140 
ScheduleOrganism()5141 int cPopulation::ScheduleOrganism()
5142 {
5143   return schedule->GetNextID();
5144 }
5145 
ProcessStep(cAvidaContext & ctx,double step_size,int cell_id)5146 void cPopulation::ProcessStep(cAvidaContext& ctx, double step_size, int cell_id)
5147 {
5148   assert(step_size > 0.0);
5149   assert(cell_id < cell_array.GetSize());
5150 
5151   // If cell_id is negative, no cell could be found -- stop here.
5152   if (cell_id < 0) return;
5153 
5154 	cPopulationCell& cell = GetCell(cell_id);
5155   assert(cell.IsOccupied()); // Unoccupied cell getting processor time!
5156   cOrganism* cur_org = cell.GetOrganism();
5157 
5158   cell.GetHardware()->SingleProcess(ctx);
5159 
5160   double merit = cur_org->GetPhenotype().GetMerit().GetDouble();
5161   if (cur_org->GetPhenotype().GetToDelete() == true) {
5162     cur_org->GetHardware().DeleteMiniTrace(print_mini_trace_reacs);
5163     delete cur_org;
5164   }
5165 
5166   m_world->GetStats().IncExecuted();
5167   resource_count.Update(step_size);
5168 
5169   // These must be done even if there is only one deme.
5170   for(int i = 0; i < GetNumDemes(); i++) {
5171     GetDeme(i).Update(step_size);
5172   }
5173 
5174   cDeme & deme = GetDeme(GetCell(cell_id).GetDemeID());
5175   deme.IncTimeUsed(merit);
5176 
5177   if (GetNumDemes() >= 1) {
5178     CheckImplicitDemeRepro(deme, ctx);
5179   }
5180 }
5181 
5182 
ProcessStepSpeculative(cAvidaContext & ctx,double step_size,int cell_id)5183 void cPopulation::ProcessStepSpeculative(cAvidaContext& ctx, double step_size, int cell_id)
5184 {
5185   assert(step_size > 0.0);
5186   assert(cell_id < cell_array.GetSize());
5187 
5188   // If cell_id is negative, no cell could be found -- stop here.
5189   if (cell_id < 0) return;
5190 
5191   cPopulationCell& cell = GetCell(cell_id);
5192   assert(cell.IsOccupied()); // Unoccupied cell getting processor time!
5193 
5194   cOrganism* cur_org = cell.GetOrganism();
5195   cHardwareBase* hw = cell.GetHardware();
5196 
5197   if (cell.GetSpeculativeState()) {
5198     // We have already executed this instruction, just decrement the counter
5199     cell.DecSpeculative();
5200   } else {
5201     // Execute the actual instruction
5202     if (hw->SingleProcess(ctx)) {
5203       // Speculatively execute additional instructions
5204       int spec_count = 0;
5205       while (spec_count < 32) {
5206         if (hw->SingleProcess(ctx, true)) spec_count++;
5207         else break;
5208       }
5209       cell.SetSpeculativeState(spec_count);
5210       m_world->GetStats().AddSpeculative(spec_count);
5211     }
5212   }
5213 
5214   // Deme specific
5215   if (GetNumDemes() > 1) {
5216     for(int i = 0; i < GetNumDemes(); i++) GetDeme(i).Update(step_size);
5217 
5218     cDeme& deme = GetDeme(GetCell(cell_id).GetDemeID());
5219     deme.IncTimeUsed(cur_org->GetPhenotype().GetMerit().GetDouble());
5220     CheckImplicitDemeRepro(deme, ctx);
5221   }
5222 
5223   if (cur_org->GetPhenotype().GetToDelete() == true) {
5224     cur_org->GetHardware().DeleteMiniTrace(print_mini_trace_reacs);
5225     delete cur_org;
5226     cur_org = NULL;
5227   }
5228 
5229   m_world->GetStats().IncExecuted();
5230   resource_count.Update(step_size);
5231 }
5232 
5233 // Loop through all the demes getting stats and doing calculations
5234 // which must be done on a deme by deme basis.
UpdateDemeStats(cAvidaContext & ctx)5235 void cPopulation::UpdateDemeStats(cAvidaContext& ctx) {
5236 
5237   // These must be updated, even if there is only one deme
5238   for(int i = 0; i < GetNumDemes(); i++) {
5239     GetDeme(i).UpdateDemeRes(ctx);
5240   }
5241 
5242   // bail early to save time if there are no demes
5243   if (GetNumDemes() == 1) return ;
5244 
5245   cStats& stats = m_world->GetStats();
5246 
5247   stats.SumDemeAge().Clear();
5248   stats.SumDemeBirthCount().Clear();
5249   stats.SumDemeOrgCount().Clear();
5250   stats.SumDemeGeneration().Clear();
5251 
5252   stats.SumDemeGestationTime().Clear();
5253   stats.SumDemeNormalizedTimeUsed().Clear();
5254   stats.SumDemeMerit().Clear();
5255 
5256   stats.SumDemeGenerationsPerLifetime().Clear();
5257 
5258   stats.ClearNumOccupiedDemes();
5259 
5260   stats.SumDemeEventsKilled().Clear();
5261   stats.SumDemeAttemptsToKillEvents() .Clear();
5262 
5263   for(int i = 0; i < GetNumDemes(); i++) {
5264     cDeme& deme = GetDeme(i);
5265     if (deme.IsEmpty()) {  // ignore empty demes
5266       continue;
5267     }
5268     stats.IncNumOccupiedDemes();
5269 
5270     stats.SumDemeAge().Add(deme.GetAge());
5271     stats.SumDemeBirthCount().Add(deme.GetBirthCount());
5272     stats.SumDemeOrgCount().Add(deme.GetOrgCount());
5273     stats.SumDemeGeneration().Add(deme.GetGeneration());
5274 
5275     stats.SumDemeLastBirthCount().Add(deme.GetLastBirthCount());
5276     stats.SumDemeLastOrgCount().Add(deme.GetLastOrgCount());
5277 
5278     stats.SumDemeGestationTime().Add(deme.GetGestationTime());
5279     stats.SumDemeNormalizedTimeUsed().Add(deme.GetLastNormalizedTimeUsed());
5280     stats.SumDemeMerit().Add(deme.GetDemeMerit().GetDouble());
5281 
5282     stats.SumDemeGenerationsPerLifetime().Add(deme.GetGenerationsPerLifetime());
5283 
5284     stats.SumDemeEventsKilled().Add(deme.GetEventsKilled());
5285     stats.SumDemeAttemptsToKillEvents().Add(deme.GetEventKillAttempts());
5286   }
5287 }
5288 
5289 
UpdateOrganismStats(cAvidaContext & ctx)5290 void cPopulation::UpdateOrganismStats(cAvidaContext& ctx)
5291 {
5292   // Loop through all the cells getting stats and doing calculations
5293   // which must be done on a creature by creature basis.
5294 
5295   cStats& stats = m_world->GetStats();
5296 
5297   // Clear out organism sums...
5298   stats.SumFitness().Clear();
5299   stats.SumGestation().Clear();
5300   stats.SumMerit().Clear();
5301   stats.SumCreatureAge().Clear();
5302   stats.SumGeneration().Clear();
5303   stats.SumNeutralMetric().Clear();
5304   stats.SumLineageLabel().Clear();
5305   stats.SumCopyMutRate().Clear();
5306   stats.SumDivMutRate().Clear();
5307   stats.SumCopySize().Clear();
5308   stats.SumExeSize().Clear();
5309   stats.SumMemSize().Clear();
5310 
5311   stats.ZeroTasks();
5312   stats.ZeroReactions();
5313 
5314   stats.ZeroInst();
5315 
5316   // Counts...
5317   int num_breed_true = 0;
5318   int num_parasites = 0;
5319   int num_no_birth = 0;
5320   int num_multi_thread = 0;
5321   int num_single_thread = 0;
5322   int num_threads = 0;
5323   int num_modified = 0;
5324 
5325   // Maximums...
5326   cMerit max_merit(0);
5327   double max_fitness = 0;
5328   int max_gestation_time = 0;
5329   int max_genome_length = 0;
5330 
5331   // Minimums...
5332   cMerit min_merit(FLT_MAX);
5333   double min_fitness = FLT_MAX;
5334   int min_gestation_time = INT_MAX;
5335   int min_genome_length = INT_MAX;
5336 
5337   for (int i = 0; i < live_org_list.GetSize(); i++) {
5338     cOrganism* organism = live_org_list[i];
5339     const cPhenotype& phenotype = organism->GetPhenotype();
5340     const cMerit cur_merit = phenotype.GetMerit();
5341     const double cur_fitness = phenotype.GetFitness();
5342     const int cur_gestation_time = phenotype.GetGestationTime();
5343     const int cur_genome_length = phenotype.GetGenomeLength();
5344 
5345     stats.SumFitness().Add(cur_fitness);
5346     stats.SumMerit().Add(cur_merit.GetDouble());
5347     stats.SumGestation().Add(phenotype.GetGestationTime());
5348     stats.SumCreatureAge().Add(phenotype.GetAge());
5349     stats.SumGeneration().Add(phenotype.GetGeneration());
5350     stats.SumNeutralMetric().Add(phenotype.GetNeutralMetric());
5351     stats.SumLineageLabel().Add(organism->GetLineageLabel());
5352     stats.SumCopyMutRate().Push(organism->MutationRates().GetCopyMutProb());
5353     stats.SumLogCopyMutRate().Push(log(organism->MutationRates().GetCopyMutProb()));
5354     stats.SumDivMutRate().Push(organism->MutationRates().GetDivMutProb() / organism->GetPhenotype().GetDivType());
5355     stats.SumLogDivMutRate().Push(log(organism->MutationRates().GetDivMutProb() /organism->GetPhenotype().GetDivType()));
5356     stats.SumCopySize().Add(phenotype.GetCopiedSize());
5357     stats.SumExeSize().Add(phenotype.GetExecutedSize());
5358 
5359     tArray<cIntSum>& inst_exe_counts = stats.InstExeCountsForInstSet(organism->GetGenome().GetInstSet());
5360     for (int j = 0; j < phenotype.GetLastInstCount().GetSize(); j++) {
5361       inst_exe_counts[j].Add(organism->GetPhenotype().GetLastInstCount()[j]);
5362     }
5363 
5364     if (cur_merit > max_merit) max_merit = cur_merit;
5365     if (cur_fitness > max_fitness) max_fitness = cur_fitness;
5366     if (cur_gestation_time > max_gestation_time) max_gestation_time = cur_gestation_time;
5367     if (cur_genome_length > max_genome_length) max_genome_length = cur_genome_length;
5368 
5369     if (cur_merit < min_merit) min_merit = cur_merit;
5370     if (cur_fitness < min_fitness) min_fitness = cur_fitness;
5371     if (cur_gestation_time < min_gestation_time) min_gestation_time = cur_gestation_time;
5372     if (cur_genome_length < min_genome_length) min_genome_length = cur_genome_length;
5373 
5374     // Test what tasks this creatures has completed.
5375     for (int j = 0; j < m_world->GetEnvironment().GetNumTasks(); j++) {
5376       if (phenotype.GetCurTaskCount()[j] > 0) {
5377         stats.AddCurTask(j);
5378         stats.AddCurTaskQuality(j, phenotype.GetCurTaskQuality()[j]);
5379       }
5380 
5381       if (phenotype.GetLastTaskCount()[j] > 0) {
5382         stats.AddLastTask(j);
5383         stats.AddLastTaskQuality(j, phenotype.GetLastTaskQuality()[j]);
5384         stats.IncTaskExeCount(j, phenotype.GetLastTaskCount()[j]);
5385       }
5386 
5387       if (phenotype.GetCurHostTaskCount()[j] > 0) {
5388         stats.AddCurHostTask(j);
5389       }
5390 
5391       if (phenotype.GetLastHostTaskCount()[j] > 0) {
5392         stats.AddLastHostTask(j);
5393       }
5394 
5395       if (phenotype.GetCurParasiteTaskCount()[j] > 0) {
5396         stats.AddCurParasiteTask(j);
5397       }
5398 
5399       if (phenotype.GetLastParasiteTaskCount()[j] > 0) {
5400         stats.AddLastParasiteTask(j);
5401       }
5402 
5403       if (phenotype.GetCurInternalTaskCount()[j] > 0) {
5404         stats.AddCurInternalTask(j);
5405         stats.AddCurInternalTaskQuality(j, phenotype.GetCurInternalTaskQuality()[j]);
5406       }
5407 
5408       if (phenotype.GetLastInternalTaskCount()[j] > 0) {
5409         stats.AddLastInternalTask(j);
5410         stats.AddLastInternalTaskQuality(j, phenotype.GetLastInternalTaskQuality()[j]);
5411       }
5412     }
5413 
5414     // Record what add bonuses this organism garnered for different reactions
5415     for (int j = 0; j < m_world->GetEnvironment().GetNumReactions(); j++) {
5416       if (phenotype.GetCurReactionCount()[j] > 0) {
5417         stats.AddCurReaction(j);
5418         stats.AddCurReactionAddReward(j, phenotype.GetCurReactionAddReward()[j]);
5419       }
5420 
5421       if (phenotype.GetLastReactionCount()[j] > 0) {
5422         stats.AddLastReaction(j);
5423         stats.IncReactionExeCount(j, phenotype.GetLastReactionCount()[j]);
5424         stats.AddLastReactionAddReward(j, phenotype.GetLastReactionAddReward()[j]);
5425       }
5426     }
5427 
5428     // Test what resource combinations this creature has sensed
5429     for (int j = 0; j < stats.GetSenseSize(); j++) {
5430       if (phenotype.GetLastSenseCount()[j] > 0) {
5431         stats.AddLastSense(j);
5432         stats.IncLastSenseExeCount(j, phenotype.GetLastSenseCount()[j]);
5433       }
5434     }
5435 
5436     // Increment the counts for all qualities the organism has...
5437     num_parasites += organism->GetNumParasites();
5438     if (phenotype.ParentTrue()) num_breed_true++;
5439     if (phenotype.GetNumDivides() == 0) num_no_birth++;
5440     if (phenotype.IsMultiThread()) num_multi_thread++;
5441     else num_single_thread++;
5442 
5443     if (phenotype.IsModified()) num_modified++;
5444 
5445     cHardwareBase& hardware = organism->GetHardware();
5446     stats.SumMemSize().Add(hardware.GetMemory().GetSize());
5447     num_threads += hardware.GetNumThreads();
5448 
5449     // Increment the age of this organism.
5450     organism->GetPhenotype().IncAge();
5451   }
5452 
5453   stats.SetBreedTrueCreatures(num_breed_true);
5454   stats.SetNumNoBirthCreatures(num_no_birth);
5455   stats.SetNumParasites(num_parasites);
5456   stats.SetNumSingleThreadCreatures(num_single_thread);
5457   stats.SetNumMultiThreadCreatures(num_multi_thread);
5458   stats.SetNumThreads(num_threads);
5459   stats.SetNumModified(num_modified);
5460 
5461   stats.SetMaxMerit(max_merit.GetDouble());
5462   stats.SetMaxFitness(max_fitness);
5463   stats.SetMaxGestationTime(max_gestation_time);
5464   stats.SetMaxGenomeLength(max_genome_length);
5465 
5466   stats.SetMinMerit(min_merit.GetDouble());
5467   stats.SetMinFitness(min_fitness);
5468   stats.SetMinGestationTime(min_gestation_time);
5469   stats.SetMinGenomeLength(min_genome_length);
5470 
5471   resource_count.UpdateGlobalResources(ctx);
5472 }
5473 
UpdateFTOrgStats(cAvidaContext & ctx)5474 void cPopulation::UpdateFTOrgStats(cAvidaContext& ctx)
5475 {
5476   // Get per-org stats seperately for pred and prey
5477   cStats& stats = m_world->GetStats();
5478 
5479   // Clear out organism sums...
5480   stats.SumPreyFitness().Clear();
5481   stats.SumPreyGestation().Clear();
5482   stats.SumPreyMerit().Clear();
5483   stats.SumPreyCreatureAge().Clear();
5484   stats.SumPreyGeneration().Clear();
5485 
5486   stats.SumPredFitness().Clear();
5487   stats.SumPredGestation().Clear();
5488   stats.SumPredMerit().Clear();
5489   stats.SumPredCreatureAge().Clear();
5490   stats.SumPredGeneration().Clear();
5491 
5492   //  stats.ZeroFTReactions();   ****
5493 
5494   stats.ZeroFTInst();
5495 
5496   for (int i = 0; i < live_org_list.GetSize(); i++) {
5497     cOrganism* organism = live_org_list[i];
5498     const cPhenotype& phenotype = organism->GetPhenotype();
5499     const cMerit cur_merit = phenotype.GetMerit();
5500     const double cur_fitness = phenotype.GetFitness();
5501 
5502     if(organism->GetForageTarget() > -2) {
5503       stats.SumPreyFitness().Add(cur_fitness);
5504       stats.SumPreyGestation().Add(phenotype.GetGestationTime());
5505       stats.SumPreyMerit().Add(cur_merit.GetDouble());
5506       stats.SumPreyCreatureAge().Add(phenotype.GetAge());
5507       stats.SumPreyGeneration().Add(phenotype.GetGeneration());
5508 
5509       tArray<cIntSum>& prey_inst_exe_counts = stats.InstPreyExeCountsForInstSet(organism->GetGenome().GetInstSet());
5510       for (int j = 0; j < phenotype.GetLastInstCount().GetSize(); j++) {
5511         prey_inst_exe_counts[j].Add(organism->GetPhenotype().GetLastInstCount()[j]);
5512       }
5513     }
5514     else {
5515       stats.SumPredFitness().Add(cur_fitness);
5516       stats.SumPredGestation().Add(phenotype.GetGestationTime());
5517       stats.SumPredMerit().Add(cur_merit.GetDouble());
5518       stats.SumPredCreatureAge().Add(phenotype.GetAge());
5519       stats.SumPredGeneration().Add(phenotype.GetGeneration());
5520 
5521       tArray<cIntSum>& pred_inst_exe_counts = stats.InstPredExeCountsForInstSet(organism->GetGenome().GetInstSet());
5522       for (int j = 0; j < phenotype.GetLastInstCount().GetSize(); j++) {
5523         pred_inst_exe_counts[j].Add(organism->GetPhenotype().GetLastInstCount()[j]);
5524       }
5525     }
5526 
5527     // Record what add bonuses this organism garnered for different reactions
5528     /*    for (int j = 0; j < m_world->GetEnvironment().GetNumReactions(); j++) {
5529      if (phenotype.GetCurReactionCount()[j] > 0) {
5530      stats.AddCurReaction(j);
5531      stats.AddCurReactionAddReward(j, phenotype.GetCurReactionAddReward()[j]);
5532      }
5533 
5534      if (phenotype.GetLastReactionCount()[j] > 0) {
5535      stats.AddLastReaction(j);
5536      stats.IncReactionExeCount(j, phenotype.GetLastReactionCount()[j]);
5537      stats.AddLastReactionAddReward(j, phenotype.GetLastReactionAddReward()[j]);
5538      }
5539      }*/
5540 
5541   }
5542 }
5543 
UpdateMaleFemaleOrgStats(cAvidaContext & ctx)5544 void cPopulation::UpdateMaleFemaleOrgStats(cAvidaContext& ctx)
5545 {
5546   // Get per-org stats seperately for males and females
5547   cStats& stats = m_world->GetStats();
5548 
5549   // Clear out organism sums...
5550   stats.SumMaleFitness().Clear();
5551   stats.SumMaleGestation().Clear();
5552   stats.SumMaleMerit().Clear();
5553   stats.SumMaleCreatureAge().Clear();
5554   stats.SumMaleGeneration().Clear();
5555 
5556   stats.SumFemaleFitness().Clear();
5557   stats.SumFemaleGestation().Clear();
5558   stats.SumFemaleMerit().Clear();
5559   stats.SumFemaleCreatureAge().Clear();
5560   stats.SumFemaleGeneration().Clear();
5561 
5562   stats.ZeroMTInst();
5563 
5564   for (int i = 0; i < live_org_list.GetSize(); i++) {
5565     cOrganism* organism = live_org_list[i];
5566     const cPhenotype& phenotype = organism->GetPhenotype();
5567     const cMerit cur_merit = phenotype.GetMerit();
5568     const double cur_fitness = phenotype.GetFitness();
5569 
5570     if(organism->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) {
5571       stats.SumMaleFitness().Add(cur_fitness);
5572       stats.SumMaleGestation().Add(phenotype.GetGestationTime());
5573       stats.SumMaleMerit().Add(cur_merit.GetDouble());
5574       stats.SumMaleCreatureAge().Add(phenotype.GetAge());
5575       stats.SumMaleGeneration().Add(phenotype.GetGeneration());
5576 
5577       tArray<cIntSum>& male_inst_exe_counts = stats.InstMaleExeCountsForInstSet(organism->GetGenome().GetInstSet());
5578       for (int j = 0; j < phenotype.GetLastInstCount().GetSize(); j++) {
5579         male_inst_exe_counts[j].Add(organism->GetPhenotype().GetLastInstCount()[j]);
5580       }
5581     }
5582     else if (organism->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) {
5583       stats.SumFemaleFitness().Add(cur_fitness);
5584       stats.SumFemaleGestation().Add(phenotype.GetGestationTime());
5585       stats.SumFemaleMerit().Add(cur_merit.GetDouble());
5586       stats.SumFemaleCreatureAge().Add(phenotype.GetAge());
5587       stats.SumFemaleGeneration().Add(phenotype.GetGeneration());
5588 
5589       tArray<cIntSum>& female_inst_exe_counts = stats.InstFemaleExeCountsForInstSet(organism->GetGenome().GetInstSet());
5590       for (int j = 0; j < phenotype.GetLastInstCount().GetSize(); j++) {
5591         female_inst_exe_counts[j].Add(organism->GetPhenotype().GetLastInstCount()[j]);
5592       }
5593     }
5594   }
5595 }
5596 
UpdateResStats(cAvidaContext & ctx)5597 void cPopulation::UpdateResStats(cAvidaContext& ctx)
5598 {
5599   cStats& stats = m_world->GetStats();
5600   stats.SetResources(resource_count.GetResources(ctx));
5601   stats.SetSpatialRes(resource_count.GetSpatialRes(ctx));
5602   stats.SetResourcesGeometry(resource_count.GetResourcesGeometry());
5603 }
5604 
ProcessPreUpdate()5605 void cPopulation::ProcessPreUpdate()
5606 {
5607   resource_count.SetSpatialUpdate(m_world->GetStats().GetUpdate());
5608   for (int i = 0; i < deme_array.GetSize(); i++) deme_array[i].ProcessPreUpdate();
5609 }
5610 
ProcessPostUpdate(cAvidaContext & ctx)5611 void cPopulation::ProcessPostUpdate(cAvidaContext& ctx)
5612 {
5613   ProcessUpdateCellActions(ctx);
5614 
5615   cStats& stats = m_world->GetStats();
5616 
5617   // Reset the Genebank to prepare it for stat collection.
5618   m_world->GetClassificationManager().UpdateReset();
5619 
5620   stats.SetNumCreatures(GetNumOrganisms());
5621 
5622   UpdateDemeStats(ctx);
5623   UpdateOrganismStats(ctx);
5624   m_world->GetClassificationManager().UpdateStats(stats);
5625   if (m_world->GetConfig().PRED_PREY_SWITCH.Get() == -2 || m_world->GetConfig().PRED_PREY_SWITCH.Get() > -1) {
5626     UpdateFTOrgStats(ctx);
5627   }
5628   if (m_world->GetConfig().MATING_TYPES.Get()) {
5629     UpdateMaleFemaleOrgStats(ctx);
5630   }
5631 
5632   // Have stats calculate anything it now can...
5633   stats.CalcEnergy();
5634   stats.CalcFidelity();
5635 
5636   for (int i = 0; i < deme_array.GetSize(); i++) deme_array[i].ProcessUpdate(ctx);
5637 }
5638 
ProcessUpdateCellActions(cAvidaContext & ctx)5639 void cPopulation::ProcessUpdateCellActions(cAvidaContext& ctx)
5640 {
5641   for (int i = 0; i < cell_array.GetSize(); i++) {
5642     if (cell_array[i].MutationRates().TestDeath(ctx)) KillOrganism(cell_array[i], ctx);
5643   }
5644 }
5645 
5646 
5647 struct sOrgInfo {
5648   int cell_id;
5649   int offset;
5650   int lineage_label;
5651   int curr_group;
5652   int curr_forage;
5653   int birth_cell;
5654   int avatar_cell;
5655   int av_bcell;
5656   // rebirth data
5657   int parent_ft;
5658   int parent_is_teacher;
5659   double parent_merit;
5660 
sOrgInfosOrgInfo5661   sOrgInfo() { ; }
sOrgInfosOrgInfo5662   sOrgInfo(int c, int o, int l, int in_group, int in_forage, int in_bcell, int in_avcell, int in_av_bcell, int in_parent_ft,
5663           int in_parent_is_teacher, double in_parent_merit) :
5664           cell_id(c), offset(o), lineage_label(l), curr_group(in_group), curr_forage(in_forage), birth_cell(in_bcell),
5665           avatar_cell(in_avcell), av_bcell(in_av_bcell), parent_ft(in_parent_ft), parent_is_teacher(in_parent_is_teacher),
5666           parent_merit(in_parent_merit) { ; }
5667 };
5668 
5669 struct sGroupInfo {
5670   cBioGroup* bg;
5671   tArray<sOrgInfo> orgs;
5672   bool parasite;
5673 
sGroupInfosGroupInfo5674   sGroupInfo(cBioGroup* in_bg, bool is_para = false) : bg(in_bg), parasite(is_para) { ; }
5675 };
5676 
SavePopulation(const cString & filename,bool save_historic,bool save_groupings,bool save_avatars,bool save_rebirth)5677 bool cPopulation::SavePopulation(const cString& filename, bool save_historic, bool save_groupings, bool save_avatars, bool save_rebirth)
5678 {
5679   cDataFile& df = m_world->GetDataFile(filename);
5680   df.SetFileType("genotype_data");
5681   df.WriteComment("Structured Population Save");
5682   df.WriteTimeStamp();
5683 
5684   // Build up hash table of all current genotypes and the cells in which the organisms reside
5685   tHashMap<int, sGroupInfo*> genotype_map;
5686 
5687   for (int cell = 0; cell < cell_array.GetSize(); cell++) {
5688     if (cell_array[cell].IsOccupied()) {
5689       cOrganism* org = cell_array[cell].GetOrganism();
5690 
5691       // Handle any parasites
5692       const tArray<cBioUnit*>& parasites = org->GetParasites();
5693       for (int p = 0; p < parasites.GetSize(); p++) {
5694         cBioGroup* pg = parasites[p]->GetBioGroup("genotype");
5695         if (pg == NULL) continue;
5696 
5697         sGroupInfo* map_entry = NULL;
5698         if (genotype_map.Find(pg->GetID(), map_entry)) {
5699           map_entry->orgs.Push(sOrgInfo(cell, 0, -1, -1, -1, 0, -1, -1, -1, 0, 1));
5700         } else {
5701           map_entry = new sGroupInfo(pg, true);
5702           map_entry->orgs.Push(sOrgInfo(cell, 0, -1, -1, -1, 0, -1, -1, -1, 0, 1));
5703           genotype_map.Set(pg->GetID(), map_entry);
5704         }
5705       }
5706 
5707 
5708       // Handle the organism itself
5709       cBioGroup* genotype = org->GetBioGroup("genotype");
5710       if (genotype == NULL) continue;
5711 
5712       int offset = org->GetPhenotype().GetCPUCyclesUsed();
5713       sGroupInfo* map_entry = NULL;
5714       if (genotype_map.Find(genotype->GetID(), map_entry)) {
5715         int curr_group = -1;
5716         if (org->HasOpinion()) curr_group = org->GetOpinion().first;
5717         const int curr_forage = org->GetForageTarget();
5718         const int birth_cell = org->GetPhenotype().GetBirthCell();
5719         int avatar_cell = -1;
5720         int av_bcell = -1;
5721         if (m_world->GetConfig().USE_AVATARS.Get()) {
5722           avatar_cell = org->GetOrgInterface().GetAVCellID();
5723           av_bcell = org->GetPhenotype().GetAVBirthCell();
5724         }
5725         if (!save_rebirth) {
5726           if (!save_groupings && !save_avatars) {
5727             map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), -1, -1, 0, -1, -1, -1, 0, 1));
5728           }
5729           else if (save_groupings && !save_avatars) {
5730             map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), curr_group, curr_forage, birth_cell, -1, -1, -1, 0, 1));
5731           }
5732           else if (save_groupings && save_avatars) {
5733             map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), curr_group, curr_forage, birth_cell, avatar_cell, av_bcell, -1, 0, 1));
5734           }
5735           else if (!save_groupings && save_avatars) {
5736             map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), -1, -1, 0, avatar_cell, av_bcell, -1, 0, 1));
5737           }
5738         }
5739         else if (save_rebirth) {
5740           const int p_ft = org->GetParentFT();
5741           const int p_teach = (bool) (org->HadParentTeacher());
5742           const double p_merit = org->GetParentMerit();
5743           map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), curr_group, curr_forage, birth_cell, avatar_cell, av_bcell, p_ft, p_teach, p_merit));
5744         }
5745       } else {
5746         map_entry = new sGroupInfo(genotype);
5747         int curr_group = -1;
5748         if (org->HasOpinion()) curr_group = org->GetOpinion().first;
5749         const int curr_forage = org->GetForageTarget();
5750         const int birth_cell = org->GetPhenotype().GetBirthCell();
5751         const int avatar_cell = org->GetOrgInterface().GetAVCellID();
5752         const int av_bcell = org->GetPhenotype().GetAVBirthCell();
5753         if (!save_rebirth) {
5754           if (!save_groupings && !save_avatars) {
5755             map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), -1, -1, 0, -1, -1, -1, 0, 1));
5756           }
5757           else if (save_groupings && !save_avatars) {
5758             map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), curr_group, curr_forage, birth_cell, -1, -1, -1, 0, 1));
5759           }
5760           else if (save_groupings && save_avatars) {
5761             map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), curr_group, curr_forage, birth_cell, avatar_cell, av_bcell, -1, 0, 1));
5762           }
5763           else if (!save_groupings && save_avatars) {
5764             map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), -1, -1, 0, avatar_cell, av_bcell, -1, 0, 1));
5765           }
5766         }
5767         else if (save_rebirth) {
5768           const int p_ft = org->GetParentFT();
5769           const int p_teach = (bool) (org->HadParentTeacher());
5770           const double p_merit = org->GetParentMerit();
5771           map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), curr_group, curr_forage, birth_cell, avatar_cell, av_bcell, p_ft, p_teach, p_merit));
5772         }
5773         genotype_map.Set(genotype->GetID(), map_entry);
5774       }
5775     }
5776   }
5777 
5778   // Output all current genotypes
5779   tArray<sGroupInfo*> genotype_entries;
5780   genotype_map.GetValues(genotype_entries);
5781   for (int i = 0; i < genotype_entries.GetSize(); i++) {
5782     cBioGroup* genotype = genotype_entries[i]->bg;
5783 
5784     genotype->Save(df);
5785 
5786     tArray<sOrgInfo>& cells = genotype_entries[i]->orgs;
5787     cString cellstr;
5788     cString offsetstr;
5789     cString lineagestr;
5790     cString groupstr;
5791     cString foragestr;
5792     cString birthstr;
5793     cString avatarstr;
5794     cString avatarbstr;
5795 
5796     cString pforagestr;
5797     cString pteachstr;
5798     cString pmeritstr;
5799 
5800     cellstr.Set("%d", cells[0].cell_id);
5801     offsetstr.Set("%d", cells[0].offset);
5802     lineagestr.Set("%d", cells[0].lineage_label);
5803     groupstr.Set("%d", cells[0].curr_group);
5804     foragestr.Set("%d", cells[0].curr_forage);
5805     birthstr.Set("%d", cells[0].birth_cell);
5806     avatarstr.Set("%d", cells[0].avatar_cell);
5807     avatarbstr.Set("%d", cells[0].av_bcell);
5808 
5809     pforagestr.Set("%d", cells[0].parent_ft);
5810     pteachstr.Set("%d", cells[0].parent_is_teacher);
5811     pmeritstr.Set("%.4d", cells[0].parent_merit);
5812 
5813     for (int cell_i = 1; cell_i < cells.GetSize(); cell_i++) {
5814       cellstr += cStringUtil::Stringf(",%d", cells[cell_i].cell_id);
5815       offsetstr += cStringUtil::Stringf(",%d", cells[cell_i].offset);
5816       lineagestr += cStringUtil::Stringf(",%d", cells[cell_i].lineage_label);
5817       if (!save_rebirth) {
5818         if (save_groupings) {
5819           groupstr += cStringUtil::Stringf(",%d", cells[cell_i].curr_group);
5820           foragestr += cStringUtil::Stringf(",%d", cells[cell_i].curr_forage);
5821           birthstr += cStringUtil::Stringf(",%d", cells[cell_i].birth_cell);
5822         }
5823         if (save_avatars) {
5824           avatarstr += cStringUtil::Stringf(",%d",cells[cell_i].avatar_cell);
5825           avatarbstr += cStringUtil::Stringf(",%d",cells[cell_i].av_bcell);
5826         }
5827       }
5828       else if (save_rebirth) {
5829         groupstr += cStringUtil::Stringf(",%d", cells[cell_i].curr_group);
5830         foragestr += cStringUtil::Stringf(",%d", cells[cell_i].curr_forage);
5831         birthstr += cStringUtil::Stringf(",%d", cells[cell_i].birth_cell);
5832         avatarstr += cStringUtil::Stringf(",%d",cells[cell_i].avatar_cell);
5833         avatarbstr += cStringUtil::Stringf(",%d",cells[cell_i].av_bcell);
5834 
5835         pforagestr += cStringUtil::Stringf(",%d",cells[cell_i].parent_ft);
5836         pteachstr += cStringUtil::Stringf(",%d",cells[cell_i].parent_is_teacher);
5837         pmeritstr += cStringUtil::Stringf(",%.4d",cells[cell_i].parent_merit);
5838       }
5839     }
5840 
5841     df.Write(cellstr, "Occupied Cell IDs", "cells");
5842     if (genotype_entries[i]->parasite) df.Write("", "Gestation (CPU) Cycle Offsets", "gest_offset");
5843     else df.Write(offsetstr, "Gestation (CPU) Cycle Offsets", "gest_offset");
5844     df.Write(lineagestr, "Lineage Label", "lineage");
5845       if (!save_rebirth) {
5846         if (save_groupings) {
5847           df.Write(groupstr, "Current Group IDs", "group_id");
5848           df.Write(foragestr, "Current Forager Types", "forager_type");
5849           df.Write(birthstr, "Birth Cells", "birth_cell");
5850         }
5851         if (save_avatars) {
5852           df.Write(avatarstr, "Current Avatar Cell Locations", "avatar_cell");
5853           df.Write(avatarbstr, "Avatar Birth Cell", "av_bcell");
5854         }
5855       }
5856       else if (save_rebirth) {
5857         df.Write(groupstr, "Current Group IDs", "group_id");
5858         df.Write(foragestr, "Current Forager Types", "forager_type");
5859         df.Write(birthstr, "Birth Cells", "birth_cell");
5860         df.Write(avatarstr, "Current Avatar Cell Locations", "avatar_cell");
5861         df.Write(avatarbstr, "Avatar Birth Cell", "av_bcell");
5862         df.Write(pforagestr, "Parent forager type", "parent_ft");
5863         df.Write(pteachstr, "Was Parent a Teacher", "parent_is_teach");
5864         df.Write(pmeritstr, "Parent Merit", "parent_merit");
5865       }
5866     df.Endl();
5867 
5868     delete genotype_entries[i];
5869   }
5870 
5871   // Output historic genotypes
5872   if (save_historic) m_world->GetClassificationManager().SaveBioGroups("genotype", df);
5873 
5874   m_world->GetDataFileManager().Remove(filename);
5875   return true;
5876 }
5877 
SaveFlameData(const cString & filename)5878 bool cPopulation::SaveFlameData(const cString& filename)
5879 {
5880   cDataFile& df = m_world->GetDataFile(filename);
5881   df.WriteComment("Flame Data Save");
5882   df.WriteTimeStamp();
5883 
5884   // Build up hash table of all current genotypes
5885   tHashMap<int, sGroupInfo*> genotype_map;
5886 
5887   for (int cell = 0; cell < cell_array.GetSize(); cell++) {
5888     if (cell_array[cell].IsOccupied()) {
5889       cOrganism* org = cell_array[cell].GetOrganism();
5890 
5891       // Handle any parasites
5892       const tArray<cBioUnit*>& parasites = org->GetParasites();
5893       for (int p = 0; p < parasites.GetSize(); p++) {
5894         cBioGroup* pg = parasites[p]->GetBioGroup("genotype");
5895         if (pg == NULL) continue;
5896 
5897         sGroupInfo* map_entry = NULL;
5898         if (genotype_map.Find(pg->GetID(), map_entry)) {
5899           map_entry->orgs.Push(sOrgInfo(cell, 0, -1, -1, -1, 0, -1, -1, -1, 0, 1));
5900         } else {
5901           map_entry = new sGroupInfo(pg, true);
5902           map_entry->orgs.Push(sOrgInfo(cell, 0, -1, -1, -1, 0, -1, -1, -1, 0, 1));
5903           genotype_map.Set(pg->GetID(), map_entry);
5904         }
5905       }
5906 
5907 
5908       // Handle the organism itself
5909       cBioGroup* genotype = org->GetBioGroup("genotype");
5910       if (genotype == NULL) continue;
5911 
5912       int offset = org->GetPhenotype().GetCPUCyclesUsed();
5913       sGroupInfo* map_entry = NULL;
5914       if (genotype_map.Find(genotype->GetID(), map_entry)) {
5915         map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), -1, -1, 0, -1, -1, -1, 0, 1));
5916       } else {
5917         map_entry = new sGroupInfo(genotype);
5918         map_entry->orgs.Push(sOrgInfo(cell, offset, org->GetLineageLabel(), -1, -1, 0, -1, -1, -1, 0, 1));
5919         genotype_map.Set(genotype->GetID(), map_entry);
5920       }
5921     }
5922   }
5923 
5924   // Output all current genotypes
5925   tArray<sGroupInfo*> genotype_entries;
5926   genotype_map.GetValues(genotype_entries);
5927   for (int i = 0; i < genotype_entries.GetSize(); i++) {
5928     cBioGroup* genotype = genotype_entries[i]->bg;
5929 
5930     genotype->DepthSave(df);
5931 
5932     df.Endl();
5933 
5934     delete genotype_entries[i];
5935   }
5936   m_world->GetDataFileManager().Remove(filename);
5937   return true;
5938 }
5939 
5940 struct sTmpGenotype
5941 {
5942 public:
5943   int id_num;
5944   tDictionary<cString>* props;
5945 
5946   int num_cpus;
5947   tArray<int> cells;
5948   tArray<int> offsets;
5949   tArray<int> lineage_labels;
5950   tArray<int> group_ids;
5951   tArray<int> forager_types;
5952   tArray<int> birth_cells;
5953   tArray<int> avatar_cells;
5954   tArray<double> parent_merit;
5955   tArray<bool> parent_teacher;
5956   tArray<int> parent_ft;
5957 
5958   cBioGroup* bg;
5959 
5960 
sTmpGenotypesTmpGenotype5961   inline sTmpGenotype() : id_num(-1), props(NULL) { ; }
operator <sTmpGenotype5962   inline bool operator<(const sTmpGenotype& rhs) const { return id_num > rhs.id_num; }
operator >sTmpGenotype5963   inline bool operator>(const sTmpGenotype& rhs) const { return id_num < rhs.id_num; }
operator <=sTmpGenotype5964   inline bool operator<=(const sTmpGenotype& rhs) const { return id_num >= rhs.id_num; }
operator >=sTmpGenotype5965   inline bool operator>=(const sTmpGenotype& rhs) const { return id_num <= rhs.id_num; }
5966 };
5967 
LoadPopulation(const cString & filename,cAvidaContext & ctx,int cellid_offset,int lineage_offset,bool load_groups,bool load_birth_cells,bool load_avatars,bool load_rebirth)5968 bool cPopulation::LoadPopulation(const cString& filename, cAvidaContext& ctx, int cellid_offset, int lineage_offset, bool load_groups,
5969                                  bool load_birth_cells, bool load_avatars, bool load_rebirth)
5970 {
5971   // @TODO - build in support for verifying population dimensions
5972 
5973   cInitFile input_file(filename, m_world->GetWorkingDir());
5974   if (!input_file.WasOpened()) {
5975     const cUserFeedback& feedback = input_file.GetFeedback();
5976     for (int i = 0; i < feedback.GetNumMessages(); i++) {
5977       switch (feedback.GetMessageType(i)) {
5978         case cUserFeedback::UF_ERROR:    m_world->GetDriver().RaiseException(feedback.GetMessage(i)); break;
5979         case cUserFeedback::UF_WARNING:  m_world->GetDriver().NotifyWarning(feedback.GetMessage(i)); break;
5980         default:                      m_world->GetDriver().NotifyComment(feedback.GetMessage(i)); break;
5981       };
5982     }
5983     return false;
5984   }
5985 
5986   // Clear out the population, unless an offset is being used
5987   if (cellid_offset == 0) {
5988     for (int i = 0; i < cell_array.GetSize(); i++) KillOrganism(cell_array[i], ctx);
5989   }
5990 
5991   // First, we read in all the genotypes and store them in an array
5992   tManagedPointerArray<sTmpGenotype> genotypes(input_file.GetNumLines());
5993 
5994   bool structured = false;
5995   for (int line_id = 0; line_id < input_file.GetNumLines(); line_id++) {
5996     cString cur_line = input_file.GetLine(line_id);
5997 
5998     // Setup the genotype for this line...
5999     sTmpGenotype& tmp = genotypes[line_id];
6000     tmp.props = input_file.GetLineAsDict(line_id);
6001     tmp.id_num = tmp.props->Get("id").AsInt();
6002 
6003     // Loads "num_units" preferrentially, but will fall back to "num_cpus" if present
6004     assert(tmp.props->HasEntry("num_cpus") || tmp.props->HasEntry("num_units"));
6005     tmp.num_cpus = (tmp.props->HasEntry("num_units")) ? tmp.props->Get("num_units").AsInt() : tmp.props->Get("num_cpus").AsInt();
6006 
6007     // Process resident cell ids
6008     cString cellstr(tmp.props->Get("cells"));
6009     if (structured || cellstr.GetSize()) {
6010       structured = true;
6011       while (cellstr.GetSize()) tmp.cells.Push(cellstr.Pop(',').AsInt());
6012       assert(tmp.cells.GetSize() == tmp.num_cpus);
6013     }
6014 
6015     // Process gestation time offsets
6016     if (!load_rebirth) {
6017       cString offsetstr(tmp.props->Get("gest_offset"));
6018       if (offsetstr.GetSize()) {
6019         while (offsetstr.GetSize()) tmp.offsets.Push(offsetstr.Pop(',').AsInt());
6020         assert(tmp.offsets.GetSize() == tmp.num_cpus);
6021       }
6022     }
6023     // Lineage label (only set if given in file)
6024     cString lineagestr(tmp.props->Get("lineage"));
6025     while (lineagestr.GetSize()) tmp.lineage_labels.Push(lineagestr.Pop(',').AsInt());
6026     // @blw preserve compatability with older .spop files that don't have lineage labels
6027     assert(tmp.lineage_labels.GetSize() == 0 || tmp.lineage_labels.GetSize() == tmp.num_cpus);
6028 
6029     // Other org specs (if given in file)
6030     if (load_rebirth) {
6031       if (tmp.props->HasEntry("birth_cell")) {
6032         cString birthstr(tmp.props->Get("birth_cell"));
6033         while (birthstr.GetSize()) tmp.birth_cells.Push(birthstr.Pop(',').AsInt());
6034         assert(tmp.birth_cells.GetSize() == 0 || tmp.birth_cells.GetSize() == tmp.num_cpus);
6035       }
6036       if (tmp.props->HasEntry("av_bcell") && m_world->GetConfig().USE_AVATARS.Get()) {
6037         cString avatarstr(tmp.props->Get("av_bcell"));
6038         while (avatarstr.GetSize()) tmp.avatar_cells.Push(avatarstr.Pop(',').AsInt());
6039         assert(tmp.avatar_cells.GetSize() == 0 || tmp.avatar_cells.GetSize() == tmp.num_cpus);
6040       }
6041       if (tmp.props->HasEntry("parent_is_teach")) {
6042         cString teachstr(tmp.props->Get("parent_is_teach"));
6043         while (teachstr.GetSize()) tmp.parent_teacher.Push((bool)(teachstr.Pop(',').AsInt()));
6044         assert(tmp.parent_teacher.GetSize() == 0 || tmp.parent_teacher.GetSize() == tmp.num_cpus);
6045       }
6046       if (tmp.props->HasEntry("parent_ft")) {
6047         cString parentftstr(tmp.props->Get("parent_ft"));
6048         while (parentftstr.GetSize()) tmp.parent_ft.Push(parentftstr.Pop(',').AsInt());
6049         assert(tmp.parent_ft.GetSize() == 0 || tmp.parent_ft.GetSize() == tmp.num_cpus);
6050       }
6051       if (tmp.props->HasEntry("parent_merit")) {
6052         cString meritstr(tmp.props->Get("parent_merit"));
6053         while (meritstr.GetSize()) tmp.parent_merit.Push(meritstr.Pop(',').AsDouble());
6054         assert(tmp.parent_merit.GetSize() == 0 || tmp.parent_merit.GetSize() == tmp.num_cpus);
6055       }
6056     }
6057     else {
6058       if (load_groups) {
6059         if (tmp.props->HasEntry("group_id")) {
6060           cString groupstr(tmp.props->Get("group_id"));
6061           while (groupstr.GetSize()) tmp.group_ids.Push(groupstr.Pop(',').AsInt());
6062           assert(tmp.group_ids.GetSize() == 0 || tmp.group_ids.GetSize() == tmp.num_cpus);
6063         }
6064         if (tmp.props->HasEntry("forager_type")) {
6065           cString foragestr(tmp.props->Get("forager_type"));
6066           while (foragestr.GetSize()) tmp.forager_types.Push(foragestr.Pop(',').AsInt());
6067           assert(tmp.forager_types.GetSize() == 0 || tmp.forager_types.GetSize() == tmp.num_cpus);
6068         }
6069       }
6070       if (load_birth_cells) {
6071         if (tmp.props->HasEntry("birth_cell")) {
6072           cString birthstr(tmp.props->Get("birth_cell"));
6073           while (birthstr.GetSize()) tmp.birth_cells.Push(birthstr.Pop(',').AsInt());
6074           assert(tmp.birth_cells.GetSize() == 0 || tmp.birth_cells.GetSize() == tmp.num_cpus);
6075         }
6076         if (tmp.props->HasEntry("av_bcell") && m_world->GetConfig().USE_AVATARS.Get()) {
6077           cString avatarstr(tmp.props->Get("av_bcell"));
6078           while (avatarstr.GetSize()) tmp.avatar_cells.Push(avatarstr.Pop(',').AsInt());
6079           assert(tmp.avatar_cells.GetSize() == 0 || tmp.avatar_cells.GetSize() == tmp.num_cpus);
6080         }
6081       }
6082       else if (!load_birth_cells && load_avatars && tmp.props->HasEntry("avatar_cell")) {
6083         cString avatarstr(tmp.props->Get("avatar_cell"));
6084         while (avatarstr.GetSize()) tmp.avatar_cells.Push(avatarstr.Pop(',').AsInt());
6085         assert(tmp.avatar_cells.GetSize() == 0 || tmp.avatar_cells.GetSize() == tmp.num_cpus);
6086       }
6087     }
6088   }
6089 
6090   // Sort genotypes in ascending order according to their id_num
6091   tArrayUtils::QSort(genotypes);
6092 
6093   cBioGroupManager* bgm = m_world->GetClassificationManager().GetBioGroupManager("genotype");
6094   for (int i = 0; i < genotypes.GetSize(); i++) {
6095     // Fix Parent IDs
6096     cString nparentstr;
6097     int pcount = 0;
6098     cString lparentstr = genotypes[i].props->Get("parents");
6099     if (lparentstr == "(none)") lparentstr = "";
6100     cStringList opidlist(lparentstr, ',');
6101     while (opidlist.GetSize()) {
6102       int opid = opidlist.Pop().AsInt();
6103       int npid = -1;
6104       for (int j = i; j >= 0; j--) {
6105         if (genotypes[j].id_num == opid) {
6106           npid = genotypes[j].bg->GetID();
6107           break;
6108         }
6109       }
6110       assert(npid != -1);
6111       if (pcount) nparentstr += ",";
6112       nparentstr += cStringUtil::Convert(npid);
6113       pcount++;
6114     }
6115     genotypes[i].props->Set("parents", nparentstr);
6116 
6117     genotypes[i].bg = bgm->LoadBioGroup(*genotypes[i].props);
6118   }
6119 
6120 
6121   // Process genotypes, inject into organisms as necessary
6122   int u_cell_id = 0;
6123   for (int gen_i = genotypes.GetSize() - 1; gen_i >= 0; gen_i--) {
6124     sTmpGenotype& tmp = genotypes[gen_i];
6125     // otherwise, we insert as many organisms as we need
6126     for (int cell_i = 0; cell_i < tmp.num_cpus; cell_i++) {
6127       int cell_id = 0;
6128       if (!load_birth_cells) cell_id = (structured) ? (tmp.cells[cell_i] + cellid_offset) : (u_cell_id++ + cellid_offset);
6129       else cell_id = (structured) ? (tmp.birth_cells[cell_i] + cellid_offset) : (u_cell_id++ + cellid_offset);
6130 
6131       // Set up lineage, including lineage label (0 if not loaded)
6132       int lineage_label = 0;
6133       if (tmp.lineage_labels.GetSize() != 0) {
6134         lineage_label = tmp.lineage_labels[cell_i] + lineage_offset;
6135       }
6136 
6137       cAvidaContext& ctx = m_world->GetDefaultContext();
6138 
6139       assert(tmp.bg->HasProperty("genome"));
6140       Genome mg(tmp.bg->GetProperty("genome").AsString());
6141       cOrganism* new_organism = new cOrganism(m_world, ctx, mg, -1, SRC_ORGANISM_FILE_LOAD);
6142 
6143       // Setup the phenotype...
6144       cPhenotype& phenotype = new_organism->GetPhenotype();
6145 
6146       phenotype.SetupInject(mg.GetSequence());
6147 
6148       // Classify this new organism
6149       tArrayMap<cString, tArrayMap<cString, cString> > hints;
6150       hints["genotype"]["id"] = cStringUtil::Stringf("%d", tmp.bg->GetID());
6151       m_world->GetClassificationManager().ClassifyNewBioUnit(new_organism, &hints);
6152 
6153       // Coalescense Clade Setup
6154       new_organism->SetCCladeLabel(-1);
6155 
6156       if (m_world->GetConfig().ENERGY_ENABLED.Get() == 1) {
6157         phenotype.SetMerit(cMerit(phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy())));
6158       } else {
6159         // Set the phenotype merit from the save file
6160         assert(tmp.props->HasEntry("merit"));
6161         double merit = tmp.props->Get("merit").AsDouble();
6162         if (load_rebirth && m_world->GetConfig().INHERIT_MERIT.Get() && tmp.props->HasEntry("parent_merit")) {
6163           merit = tmp.parent_merit[cell_i];
6164         }
6165 
6166         if (merit > 0) {
6167           phenotype.SetMerit(cMerit(merit));
6168         } else {
6169           phenotype.SetMerit(cMerit(new_organism->GetTestMerit(ctx)));
6170         }
6171 
6172         if (tmp.offsets.GetSize() > cell_i) {
6173           // Adjust initial merit to account for organism execution at the time the population was saved
6174           // - this factors the merit by the fraction of the gestation time remaining
6175           // - this will be approximate, since gestation time may vary for each organism, but it should work for many cases
6176           double gest_time = tmp.props->Get("gest_time").AsDouble();
6177           double gest_remain = gest_time - (double)tmp.offsets[cell_i];
6178           if (gest_remain > 0.0 && gest_time > 0.0) {
6179             double new_merit = phenotype.GetMerit().GetDouble() * (gest_time / gest_remain);
6180             phenotype.SetMerit(cMerit(new_merit));
6181           }
6182         }
6183       }
6184 
6185       new_organism->SetLineageLabel(lineage_label);
6186 
6187       // Prep the cell..
6188       if (m_world->GetConfig().BIRTH_METHOD.Get() == POSITION_OFFSPRING_FULL_SOUP_ELDEST &&
6189           cell_array[cell_id].IsOccupied() == true) {
6190         // Have to manually take this cell out of the reaper Queue.
6191         reaper_queue.Remove( &(cell_array[cell_id]) );
6192       }
6193 
6194       // Setup the child's mutation rates.  Since this organism is being injected
6195       // and has no parent, we should always take the rate from the environment.
6196       new_organism->MutationRates().Copy(cell_array[cell_id].MutationRates());
6197 
6198       // Activate the organism in the population...
6199       bool org_survived = false;
6200       if (!load_rebirth) {
6201         if (load_groups) {
6202           // Set up group id and forager type (if loaded)
6203           int group_id = -1;
6204           int forager_type = -1;
6205           if (tmp.group_ids.GetSize() != 0) group_id = tmp.group_ids[cell_i];
6206           if (tmp.forager_types.GetSize() != 0) forager_type = tmp.forager_types[cell_i];
6207           new_organism->SetOpinion(group_id);
6208           JoinGroup(new_organism, group_id);
6209           new_organism->SetForageTarget(forager_type);
6210           new_organism->GetPhenotype().SetBirthCellID(cell_id);
6211           new_organism->GetPhenotype().SetBirthGroupID(group_id);
6212           new_organism->GetPhenotype().SetBirthForagerType(forager_type);
6213           new_organism->SetParentGroup(group_id);
6214           new_organism->SetParentFT(forager_type);
6215           org_survived = ActivateOrganism(ctx, new_organism, cell_array[cell_id], false, true);
6216         }
6217         else org_survived = ActivateOrganism(ctx, new_organism, cell_array[cell_id], true, true);
6218 
6219         if ((load_avatars || load_birth_cells) && org_survived && m_world->GetConfig().USE_AVATARS.Get() && !m_world->GetConfig().NEURAL_NETWORKING.Get()) { //**
6220           int avatar_cell = -1;
6221           if (tmp.avatar_cells.GetSize() != 0) avatar_cell = tmp.avatar_cells[cell_i];
6222           if (avatar_cell != -1) new_organism->GetOrgInterface().AddPredPreyAV(avatar_cell);
6223         }
6224       }
6225       else if (load_rebirth) {
6226         new_organism->SetParentFT(tmp.parent_ft[cell_i]);
6227         new_organism->SetParentTeacher(tmp.parent_teacher[cell_i]);
6228 
6229         new_organism->GetPhenotype().SetBirthCellID(cell_id);
6230         org_survived = ActivateOrganism(ctx, new_organism, cell_array[cell_id], false, true);
6231       }
6232 
6233       if (org_survived && m_world->GetConfig().USE_AVATARS.Get() && !m_world->GetConfig().NEURAL_NETWORKING.Get()) { //**
6234         int avatar_cell = -1;
6235         if (tmp.avatar_cells.GetSize() != 0) avatar_cell = tmp.avatar_cells[cell_i];
6236         if (avatar_cell != -1) new_organism->GetOrgInterface().AddPredPreyAV(avatar_cell);
6237       }
6238     }
6239   }
6240   sync_events = true;
6241 
6242   return true;
6243 }
6244 
DumpMemorySummary(ofstream & fp)6245 bool cPopulation::DumpMemorySummary(ofstream& fp)
6246 {
6247   if (fp.good() == false) return false;
6248 
6249   // Dump the memory...
6250 
6251   for (int i = 0; i < cell_array.GetSize(); i++) {
6252     fp << i << " ";
6253     if (cell_array[i].IsOccupied() == false) {
6254       fp << "EMPTY" << endl;
6255     }
6256     else {
6257       Sequence & mem = cell_array[i].GetOrganism()->GetHardware().GetMemory();
6258       fp << mem.GetSize() << " "
6259       << mem.AsString() << endl;
6260     }
6261   }
6262   return true;
6263 }
6264 
6265 
6266 
6267 /**
6268  * This function loads a genome from a given file, and initializes
6269  * a cpu with it.
6270  *
6271  * @param filename The name of the file to load.
6272  * @param in_cpu The grid-position into which the genome should be loaded.
6273  * @param merit An initial merit value.
6274  * @param lineage_label A value that allows to track the daughters of
6275  * this organism.
6276  **/
6277 
Inject(const Genome & genome,eBioUnitSource src,cAvidaContext & ctx,int cell_id,double merit,int lineage_label,double neutral,bool inject_group,int group_id,int forager_type,int trace)6278 void cPopulation::Inject(const Genome& genome, eBioUnitSource src, cAvidaContext& ctx, int cell_id, double merit, int lineage_label, double neutral, bool inject_group, int group_id, int forager_type, int trace)
6279 {
6280   // If an invalid cell was given, choose a new ID for it.
6281   if (cell_id < 0) {
6282     switch (m_world->GetConfig().BIRTH_METHOD.Get()) {
6283       case POSITION_OFFSPRING_FULL_SOUP_ELDEST:
6284         cell_id = reaper_queue.PopRear()->GetID();
6285       default:
6286         cell_id = 0;
6287     }
6288   }
6289 
6290   // We can't inject into the boundary of the world:
6291   if(m_world->IsWorldBoundary(GetCell(cell_id))) {
6292     cell_id += m_world->GetConfig().WORLD_X.Get()+1;
6293   }
6294   // Can't inject onto deadly world edges either
6295   if (m_world->GetConfig().DEADLY_BOUNDARIES.Get() == 1) {
6296     const int dest_x = cell_id % m_world->GetConfig().WORLD_X.Get();
6297     if (dest_x == 0) cell_id += 1;
6298     else if (dest_x == m_world->GetConfig().WORLD_X.Get() - 1) cell_id -= 1;
6299     const int dest_y = cell_id / m_world->GetConfig().WORLD_X.Get();
6300     if (dest_y == 0) cell_id += m_world->GetConfig().WORLD_X.Get();
6301     else if (dest_y == m_world->GetConfig().WORLD_Y.Get() - 1) cell_id -= m_world->GetConfig().WORLD_X.Get();
6302   }
6303 
6304   // if the injected org already has a group we will assign it to, do not assign group id in activate organism
6305   if (!inject_group) InjectGenome(cell_id, src, genome, ctx, lineage_label, true);
6306   else InjectGenome(cell_id, src, genome, ctx, lineage_label, false);
6307 
6308   cPhenotype& phenotype = GetCell(cell_id).GetOrganism()->GetPhenotype();
6309   phenotype.SetNeutralMetric(neutral);
6310 
6311   if (merit > 0) phenotype.SetMerit(cMerit(merit));
6312   AdjustSchedule(GetCell(cell_id), phenotype.GetMerit());
6313 
6314   cell_array[cell_id].GetOrganism()->SetLineageLabel(lineage_label);
6315 
6316   // the following bit of code is required for proper germline support.
6317   // even if there's only one deme!!
6318   if (m_world->GetConfig().DEMES_USE_GERMLINE.Get()) {
6319     cDeme& deme = deme_array[GetCell(cell_id).GetDemeID()];
6320 
6321     // If we're using germlines, then we have to be a little careful here.
6322     // This should probably not be within Inject() since we mainly want it to
6323     // apply to the START_ORGANISM? -- @JEB
6324 
6325     //@JEB This section is very messy to maintain consistency with other deme ways.
6326 
6327     if (m_world->GetConfig().DEMES_SEED_METHOD.Get() == 0) {
6328       if (m_world->GetConfig().DEMES_USE_GERMLINE.Get() == 1) {
6329         if (deme.GetGermline().Size()==0) {
6330           deme.GetGermline().Add(GetCell(cell_id).GetOrganism()->GetGenome());
6331         }
6332       }
6333     } else if (m_world->GetConfig().DEMES_SEED_METHOD.Get() == 1) {
6334       if (m_world->GetConfig().DEMES_USE_GERMLINE.Get() == 2) {
6335         //find the genotype we just created from the genome, and save it
6336         deme.ReplaceGermline(GetCell(cell_id).GetOrganism()->GetBioGroup("genotype"));
6337       } else { // not germlines, save org as founder
6338         deme.AddFounder(GetCell(cell_id).GetOrganism()->GetBioGroup("genotype"), &phenotype);
6339       }
6340 
6341       GetCell(cell_id).GetOrganism()->GetPhenotype().SetPermanentGermlinePropensity
6342         (m_world->GetConfig().DEMES_FOUNDER_GERMLINE_PROPENSITY.Get());
6343 
6344 
6345       if (m_world->GetConfig().DEMES_FOUNDER_GERMLINE_PROPENSITY.Get() >= 0.0) {
6346         GetCell(cell_id).GetOrganism()->GetPhenotype().SetPermanentGermlinePropensity
6347           ( m_world->GetConfig().DEMES_FOUNDER_GERMLINE_PROPENSITY.Get() );
6348       }
6349 
6350     }
6351   } else if (m_world->GetConfig().DEMES_USE_GERMLINE.Get() == 2) {
6352     //find the genotype we just created from the genome, and save it
6353     cDeme& deme = deme_array[GetCell(cell_id).GetDemeID()];
6354     cDemePlaceholderUnit unit(src, genome);
6355     cBioGroup* genotype = m_world->GetClassificationManager().GetBioGroupManager("genotype")->ClassifyNewBioUnit(&unit);
6356     deme.ReplaceGermline(genotype);
6357     genotype->RemoveBioUnit(&unit);
6358   }
6359 
6360   if (inject_group) {
6361     cell_array[cell_id].GetOrganism()->SetOpinion(group_id);
6362     cell_array[cell_id].GetOrganism()->JoinGroup(group_id);
6363     cell_array[cell_id].GetOrganism()->SetForageTarget(forager_type);
6364 
6365     cell_array[cell_id].GetOrganism()->GetPhenotype().SetBirthCellID(cell_id);
6366     cell_array[cell_id].GetOrganism()->GetPhenotype().SetBirthGroupID(group_id);
6367     cell_array[cell_id].GetOrganism()->GetPhenotype().SetBirthForagerType(forager_type);
6368   }
6369   if (m_world->GetConfig().USE_AVATARS.Get() && !m_world->GetConfig().NEURAL_NETWORKING.Get()) {
6370     cell_array[cell_id].GetOrganism()->GetOrgInterface().AddPredPreyAV(cell_id);
6371   }
6372   if (trace) SetupMiniTrace(cell_array[cell_id].GetOrganism());
6373 }
6374 
InjectGroup(const Genome & genome,eBioUnitSource src,cAvidaContext & ctx,int cell_id,double merit,int lineage_label,double neutral,int group_id,int forager_type,int trace)6375 void cPopulation::InjectGroup(const Genome& genome, eBioUnitSource src, cAvidaContext& ctx, int cell_id, double merit, int lineage_label, double neutral, int group_id, int forager_type, int trace)
6376 {
6377   Inject(genome, src, ctx, cell_id, merit, lineage_label, neutral, true, group_id, forager_type, trace);
6378 }
6379 
InjectParasite(const cString & label,const Sequence & injected_code,int cell_id)6380 void cPopulation::InjectParasite(const cString& label, const Sequence& injected_code, int cell_id)
6381 {
6382   cOrganism* target_organism = cell_array[cell_id].GetOrganism();
6383   // target_organism-> target_organism->GetHardware().GetCurThread()
6384   if (target_organism == NULL) return;
6385 
6386   Genome mg(target_organism->GetHardware().GetType(), target_organism->GetHardware().GetInstSet().GetInstSetName(), injected_code);
6387   cParasite* parasite = new cParasite(m_world, mg, 0, SRC_PARASITE_FILE_LOAD, label);
6388 
6389   //default to configured parasite virulence
6390   parasite->SetVirulence(m_world->GetConfig().PARASITE_VIRULENCE.Get());
6391 
6392   if (target_organism->ParasiteInfectHost(parasite)) {
6393     m_world->GetClassificationManager().ClassifyNewBioUnit(parasite);
6394   } else {
6395     delete parasite;
6396   }
6397 }
6398 
6399 
UpdateResources(cAvidaContext & ctx,const tArray<double> & res_change)6400 void cPopulation::UpdateResources(cAvidaContext& ctx, const tArray<double> & res_change)
6401 {
6402   resource_count.Modify(ctx, res_change);
6403 }
6404 
UpdateResource(cAvidaContext & ctx,int res_index,double change)6405 void cPopulation::UpdateResource(cAvidaContext& ctx, int res_index, double change)
6406 {
6407   resource_count.Modify(ctx, res_index, change);
6408 }
6409 
UpdateCellResources(cAvidaContext & ctx,const tArray<double> & res_change,const int cell_id)6410 void cPopulation::UpdateCellResources(cAvidaContext& ctx, const tArray<double>& res_change, const int cell_id)
6411 {
6412   resource_count.ModifyCell(ctx, res_change, cell_id);
6413 }
6414 
UpdateDemeCellResources(cAvidaContext & ctx,const tArray<double> & res_change,const int cell_id)6415 void cPopulation::UpdateDemeCellResources(cAvidaContext& ctx, const tArray<double>& res_change, const int cell_id)
6416 {
6417   GetDeme(GetCell(cell_id).GetDemeID()).ModifyDemeResCount(ctx, res_change, cell_id);
6418 }
6419 
SetResource(cAvidaContext & ctx,int res_index,double new_level)6420 void cPopulation::SetResource(cAvidaContext& ctx, int res_index, double new_level)
6421 {
6422   resource_count.Set(ctx, res_index, new_level);
6423 }
6424 
6425 /* This version of SetResource takes the name of the resource.
6426  * If a resource by this name does not exist, it does nothing.
6427  * Otherwise, it sets the resource to the new level,
6428  * calling the index version of SetResource().
6429  */
SetResource(cAvidaContext & ctx,const cString res_name,double new_level)6430 void cPopulation::SetResource(cAvidaContext& ctx, const cString res_name, double new_level)
6431 {
6432   cResource* res = environment.GetResourceLib().GetResource(res_name);
6433   if (res != NULL) SetResource(ctx, res->GetIndex(), new_level);
6434 }
6435 
6436 /* This method sets the inflow of the named resource.
6437  * It changes this value in the environment, then updates it in the
6438  * actual population's resource count.
6439  */
SetResourceInflow(const cString res_name,double new_level)6440 void cPopulation::SetResourceInflow(const cString res_name, double new_level)
6441 {
6442   environment.SetResourceInflow(res_name, new_level);
6443   resource_count.SetInflow(res_name, new_level);
6444 }
6445 
6446 /* This method sets the outflow of the named resource.
6447  * It changes this value in the enviroment, then updates the
6448  * decay rate in the resource count (to 1 - the given outflow, as
6449  * outflow is different than decay).
6450  */
SetResourceOutflow(const cString res_name,double new_level)6451 void cPopulation::SetResourceOutflow(const cString res_name, double new_level)
6452 {
6453   environment.SetResourceOutflow(res_name, new_level);
6454   resource_count.SetDecay(res_name, 1 - new_level);
6455 }
6456 
6457 /* This method sets a deme resource to the same level across
6458  * all demes.  If a resource by the given name does not exist,
6459  * it does nothing.
6460  */
SetDemeResource(cAvidaContext & ctx,const cString res_name,double new_level)6461 void cPopulation::SetDemeResource(cAvidaContext& ctx, const cString res_name, double new_level)
6462 {
6463   cResource* res = environment.GetResourceLib().GetResource(res_name);
6464   if (res != NULL) {
6465     int num_demes = GetNumDemes();
6466     for (int deme_id = 0; deme_id < num_demes; ++deme_id) {
6467       cDeme& deme = GetDeme(deme_id);
6468       deme.SetResource(ctx, res->GetIndex(), new_level);
6469     }
6470   }
6471 }
6472 
6473 /* This method sets the inflow for the named deme resource in a specific deme.
6474  * It changes the value in the environment, then updates it in the specified deme's
6475  * resource count.
6476  *
6477  * ATTENTION: This leads to the rather bizzare consequence that the inflow rate
6478  * in the environment may not match the inflow rate in each deme's resource count.
6479  * This is not my own decision, simply a reflection of how the SetDemeResourceInflow
6480  * action (for which I am writing this as a helper) works.  Unless you have a specific
6481  * reason NOT to change the inflow for all demes, it is probably best to use
6482  * cPopulation::SetDemeResourceInflow() -- blw
6483  */
SetSingleDemeResourceInflow(int deme_id,const cString res_name,double new_level)6484 void cPopulation::SetSingleDemeResourceInflow(int deme_id, const cString res_name, double new_level)
6485 {
6486   environment.SetResourceInflow(res_name, new_level);
6487   GetDeme(deme_id).GetDemeResources().SetInflow(res_name, new_level);
6488 }
6489 
6490 /* This method sets the inflow for the named deme resource across ALL demes.
6491  * It changes the value in the environment, then updates it in the deme resource
6492  * counts.
6493  *
6494  * This maintains the connection between the enviroment value and the resource
6495  * count values, unlike cPopulation::SetSingleDemeResourceInflow()
6496  */
SetDemeResourceInflow(const cString res_name,double new_level)6497 void cPopulation::SetDemeResourceInflow(const cString res_name, double new_level)
6498 {
6499   environment.SetResourceInflow(res_name, new_level);
6500   int num_demes = GetNumDemes();
6501   for (int deme_id = 0; deme_id < num_demes; ++deme_id) {
6502     GetDeme(deme_id).GetDemeResources().SetInflow(res_name, new_level);
6503   }
6504 }
6505 
6506 /* This method sets the outflow for the named deme resource in a specific deme.
6507  * It changes the value in the environment, then updates the decay rate in the
6508  * specified deme's resource count.
6509  *
6510  * ATTENTION: This leads to the rather bizzare consequence that the outflow rate
6511  * in the environment may not match the decay (1-outflow) rate in each deme's resource count.
6512  * This is not my own decision, simply a reflection of how the SetDemeResourceOutflow
6513  * action (for which I am writing this as a helper) works.  Unless you have a specific
6514  * reason NOT to change the outflow for all demes, it is probably best to use
6515  * cPopulation::SetDemeResourceOutflow() -- blw
6516  */
SetSingleDemeResourceOutflow(int deme_id,const cString res_name,double new_level)6517 void cPopulation::SetSingleDemeResourceOutflow(int deme_id, const cString res_name, double new_level)
6518 {
6519   environment.SetResourceOutflow(res_name, new_level);
6520   GetDeme(deme_id).GetDemeResources().SetDecay(res_name, 1 - new_level);
6521 }
6522 
6523 /* This method sets the outflow for the named deme resource across ALL demes.
6524  * It changes the value in the environment, then updates the decay rate in the
6525  * deme resource counts.
6526  *
6527  * This maintains the connection between the enviroment value and the resource
6528  * count values, unlike cPopulation::SetSingleDemeResourceOutflow()
6529  */
SetDemeResourceOutflow(const cString res_name,double new_level)6530 void cPopulation::SetDemeResourceOutflow(const cString res_name, double new_level)
6531 {
6532   environment.SetResourceOutflow(res_name, new_level);
6533   int num_demes = GetNumDemes();
6534   for (int deme_id = 0; deme_id < num_demes; ++deme_id) {
6535     GetDeme(deme_id).GetDemeResources().SetDecay(res_name, 1 - new_level);
6536   }
6537 }
6538 
ResetInputs(cAvidaContext & ctx)6539 void cPopulation::ResetInputs(cAvidaContext& ctx)
6540 {
6541   for (int i=0; i<GetSize(); i++) {
6542     cPopulationCell& cell = GetCell(i);
6543     cell.ResetInputs(ctx);
6544     if (cell.IsOccupied()) {
6545       cell.GetOrganism()->ResetInput();
6546     }
6547   }
6548   //@JJB**
6549   for (int i = 0; i < GetNumDemes(); i++) {
6550     GetDeme(i).ResetInputs(ctx);
6551     GetDeme(i).ResetInput();
6552   }
6553 }
6554 
BuildTimeSlicer()6555 void cPopulation::BuildTimeSlicer()
6556 {
6557   switch (m_world->GetConfig().SLICING_METHOD.Get()) {
6558     case SLICE_CONSTANT:
6559       schedule = new cConstSchedule(cell_array.GetSize());
6560       break;
6561     case SLICE_PROB_MERIT:
6562       schedule = new cProbSchedule(cell_array.GetSize(), m_world->GetRandom().GetInt(0x7FFFFFFF));
6563       break;
6564     case SLICE_DEME_PROB_MERIT:
6565       schedule = new cDemeProbSchedule(cell_array.GetSize(), m_world->GetRandom().GetInt(0x7FFFFFFF), deme_array.GetSize());
6566       break;
6567     case SLICE_PROB_DEMESIZE_PROB_MERIT:
6568       schedule = new cProbDemeProbSchedule(cell_array.GetSize(), m_world->GetRandom().GetInt(0x7FFFFFFF), deme_array.GetSize());
6569       break;
6570     case SLICE_INTEGRATED_MERIT:
6571       schedule = new cIntegratedSchedule(cell_array.GetSize());
6572       break;
6573     case SLICE_CONSTANT_BURST:
6574       schedule = new cConstBurstSchedule(cell_array.GetSize(), m_world->GetConfig().SLICING_BURST_SIZE.Get());
6575     default:
6576       cout << "Warning: Requested Time Slicer not found, defaulting to Integrated." << endl;
6577       schedule = new cIntegratedSchedule(cell_array.GetSize());
6578       break;
6579   }
6580 }
6581 
6582 
FindEmptyCell(tList<cPopulationCell> & cell_list,tList<cPopulationCell> & found_list)6583 void cPopulation::FindEmptyCell(tList<cPopulationCell> & cell_list,
6584                                 tList<cPopulationCell> & found_list)
6585 {
6586   tListIterator<cPopulationCell> cell_it(cell_list);
6587   cPopulationCell * test_cell;
6588 
6589   while ( (test_cell = cell_it.Next()) != NULL) {
6590     // If this cell is empty, add it to the list...
6591     if (test_cell->IsOccupied() == false) found_list.Push(test_cell);
6592   }
6593 }
6594 
6595 
6596 // This function injects a new organism into the population at cell_id that
6597 // is an exact clone of the organism passed in.
6598 
InjectClone(int cell_id,cOrganism & orig_org,eBioUnitSource src)6599 void cPopulation::InjectClone(int cell_id, cOrganism& orig_org, eBioUnitSource src)
6600 {
6601   assert(cell_id >= 0 && cell_id < cell_array.GetSize());
6602 
6603   cAvidaContext& ctx = m_world->GetDefaultContext();
6604 
6605   cOrganism* new_organism = new cOrganism(m_world, ctx, orig_org.GetGenome(), orig_org.GetPhenotype().GetGeneration(), src);
6606 
6607   // Classify the new organism
6608   m_world->GetClassificationManager().ClassifyNewBioUnit(new_organism);
6609 
6610   // Setup the phenotype...
6611   new_organism->GetPhenotype().SetupClone(orig_org.GetPhenotype());
6612 
6613   // Prep the cell..
6614   if (m_world->GetConfig().BIRTH_METHOD.Get() == POSITION_OFFSPRING_FULL_SOUP_ELDEST &&
6615       cell_array[cell_id].IsOccupied() == true) {
6616     // Have to manually take this cell out of the reaper Queue.
6617     reaper_queue.Remove( &(cell_array[cell_id]) );
6618   }
6619 
6620   // Setup the mutation rate based on the population cell...
6621   const int mut_source = m_world->GetConfig().MUT_RATE_SOURCE.Get();
6622   if (mut_source == 1) {
6623     // Update the mutation rates of each child from the environment....
6624     new_organism->MutationRates().Copy(cell_array[cell_id].MutationRates());
6625   } else {
6626     // Update the mutation rates of each child from its parent.
6627     new_organism->MutationRates().Copy(orig_org.MutationRates());
6628   }
6629 
6630   // Activate the organism in the population...
6631   ActivateOrganism(ctx, new_organism, cell_array[cell_id], true, true);
6632 }
6633 
6634 // This function injects the offspring genome of an organism into the population at cell_id.
6635 // Takes care of divide mutations.
CompeteOrganisms_ConstructOffspring(int cell_id,cOrganism & parent)6636 void cPopulation::CompeteOrganisms_ConstructOffspring(int cell_id, cOrganism& parent)
6637 {
6638   assert(cell_id >= 0 && cell_id < cell_array.GetSize());
6639 
6640   cAvidaContext& ctx = m_world->GetDefaultContext();
6641 
6642   // Do mutations on the child genome, but restore it to its current state afterward.
6643   Genome save_child = parent.OffspringGenome();
6644   parent.GetHardware().Divide_DoMutations(ctx);
6645   Genome child_genome = parent.OffspringGenome();
6646   parent.GetHardware().Divide_TestFitnessMeasures(ctx);
6647   parent.OffspringGenome() = save_child;
6648   cOrganism* new_organism = new cOrganism(m_world, ctx, child_genome, parent.GetPhenotype().GetGeneration(), SRC_ORGANISM_COMPETE);
6649 
6650   // Classify the offspring
6651   tArray<const tArray<cBioGroup*>*> pgrps(1);
6652   pgrps[0] = &parent.GetBioGroups();
6653   new_organism->SelfClassify(pgrps);
6654 
6655   // Setup the phenotype...
6656   new_organism->GetPhenotype().SetupOffspring(parent.GetPhenotype(),child_genome.GetSequence());
6657 
6658   // Prep the cell..
6659   if (m_world->GetConfig().BIRTH_METHOD.Get() == POSITION_OFFSPRING_FULL_SOUP_ELDEST &&
6660       cell_array[cell_id].IsOccupied() == true) {
6661     // Have to manually take this cell out of the reaper Queue.
6662     reaper_queue.Remove( &(cell_array[cell_id]) );
6663   }
6664 
6665   // Setup the mutation rate based on the population cell...
6666   const int mut_source = m_world->GetConfig().MUT_RATE_SOURCE.Get();
6667   if (mut_source == 1) {
6668     // Update the mutation rates of each child from the environment....
6669     new_organism->MutationRates().Copy(cell_array[cell_id].MutationRates());
6670   } else {
6671     // Update the mutation rates of each child from its parent.
6672     new_organism->MutationRates().Copy(parent.MutationRates());
6673   }
6674 
6675   // Activate the organism in the population...
6676   ActivateOrganism(ctx, new_organism, cell_array[cell_id], true, true);
6677 }
6678 
6679 
InjectGenome(int cell_id,eBioUnitSource src,const Genome & genome,cAvidaContext & ctx2,int lineage_label,bool assign_group)6680 void cPopulation::InjectGenome(int cell_id, eBioUnitSource src, const Genome& genome, cAvidaContext& ctx2, int lineage_label, bool assign_group)
6681 {
6682   assert(cell_id >= 0 && cell_id < cell_array.GetSize());
6683   if (cell_id < 0 || cell_id >= cell_array.GetSize()) {
6684     m_world->GetDriver().RaiseFatalException(1, "InjectGenotype into nonexistent cell");
6685   }
6686 
6687   cAvidaContext& ctx = m_world->GetDefaultContext();
6688 
6689   cOrganism* new_organism = new cOrganism(m_world, ctx, genome, -1, src);
6690 
6691   // Setup the phenotype...
6692   cPhenotype& phenotype = new_organism->GetPhenotype();
6693 
6694   phenotype.SetupInject(genome.GetSequence());
6695 
6696   // Classify this new organism
6697   m_world->GetClassificationManager().ClassifyNewBioUnit(new_organism);
6698 
6699   //Coalescense Clade Setup
6700   new_organism->SetCCladeLabel(-1);
6701 
6702   cGenomeTestMetrics* metrics = cGenomeTestMetrics::GetMetrics(ctx, new_organism->GetBioGroup("genotype"));
6703 
6704   if (m_world->GetConfig().ENERGY_ENABLED.Get() == 1) {
6705     phenotype.SetMerit(cMerit(phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy())));
6706   } else {
6707     phenotype.SetMerit(cMerit(metrics->GetMerit()));
6708   }
6709 
6710   phenotype.SetLinesCopied(metrics->GetLinesCopied());
6711   phenotype.SetLinesExecuted(metrics->GetLinesExecuted());
6712   phenotype.SetGestationTime(metrics->GetGestationTime());
6713 
6714 
6715   // Prep the cell..
6716   if (m_world->GetConfig().BIRTH_METHOD.Get() == POSITION_OFFSPRING_FULL_SOUP_ELDEST &&
6717       cell_array[cell_id].IsOccupied() == true) {
6718     // Have to manually take this cell out of the reaper Queue.
6719     reaper_queue.Remove( &(cell_array[cell_id]) );
6720   }
6721 
6722   // Setup the child's mutation rates.  Since this organism is being injected
6723   // and has no parent, we should always take the rate from the environment.
6724   new_organism->MutationRates().Copy(cell_array[cell_id].MutationRates());
6725   new_organism->SetLineageLabel(lineage_label);
6726 
6727   // Activate the organism in the population...
6728   if (assign_group) ActivateOrganism(ctx, new_organism, cell_array[cell_id], true, true);
6729   else ActivateOrganism(ctx, new_organism, cell_array[cell_id], false, true);
6730 
6731   // Log the injection of this organism if LOG_INJECT is set to 1 and
6732   // the current update number is >= INJECT_LOG_START
6733   if ( (m_world->GetConfig().LOG_INJECT.Get() == 1) &&
6734       (m_world->GetStats().GetUpdate() >= m_world->GetConfig().INJECT_LOG_START.Get()) ){
6735 
6736     cString tmpfilename = cStringUtil::Stringf("injectlog.dat");
6737     cDataFile& df = m_world->GetDataFile(tmpfilename);
6738 
6739     df.Write(m_world->GetStats().GetUpdate(), "Update");
6740     df.Write(new_organism->GetID(), "Organism ID");
6741     df.Write(m_world->GetPopulation().GetCell(cell_id).GetDemeID(), "Deme ID");
6742     df.Write(new_organism->GetFacing(), "Facing");
6743     df.Endl();
6744   }
6745 }
6746 
6747 // Note: cPopulation::SerialTransfer does not respect deme boundaries and only acts on a single population.
SerialTransfer(int transfer_size,bool ignore_deads,cAvidaContext & ctx)6748 void cPopulation::SerialTransfer(int transfer_size, bool ignore_deads, cAvidaContext& ctx)
6749 {
6750   assert(transfer_size > 0);
6751 
6752   // If we are ignoring all dead organisms, remove them from the population.
6753   if (ignore_deads == true) {
6754     for (int i = 0; i < GetSize(); i++) {
6755       cPopulationCell & cell = cell_array[i];
6756       if (cell.IsOccupied() && cell.GetOrganism()->GetTestFitness(m_world->GetDefaultContext()) == 0.0) {
6757         KillOrganism(cell, ctx);
6758       }
6759     }
6760   }
6761 
6762   // If removing the dead was enough, stop here.
6763   if (num_organisms <= transfer_size) return;
6764 
6765   // Collect a vector of the occupied cells...
6766   vector<int> transfer_pool;
6767   transfer_pool.reserve(num_organisms);
6768   for (int i = 0; i < GetSize(); i++) {
6769     if (cell_array[i].IsOccupied()) transfer_pool.push_back(i);
6770   }
6771 
6772   // Remove the proper number of cells.
6773   const int removal_size = num_organisms - transfer_size;
6774   for (int i = 0; i < removal_size; i++) {
6775     int j = (int) m_world->GetRandom().GetUInt(transfer_pool.size());
6776     KillOrganism(cell_array[transfer_pool[j]], ctx);
6777     transfer_pool[j] = transfer_pool.back();
6778     transfer_pool.pop_back();
6779   }
6780 }
6781 
RemovePredators(cAvidaContext & ctx)6782 void cPopulation::RemovePredators(cAvidaContext& ctx)
6783 {
6784   for (int i = 0; i < live_org_list.GetSize(); i++) {
6785     if (live_org_list[i]->GetForageTarget() <= -2) live_org_list[i]->Die(ctx);
6786   }
6787 }
6788 
PrintPhenotypeData(const cString & filename)6789 void cPopulation::PrintPhenotypeData(const cString& filename)
6790 {
6791   set<int> ids;
6792   set<cString> complete;
6793   double average_shannon_diversity = 0.0;
6794   int num_orgs = 0; //could get from elsewhere, but more self-contained this way
6795   double average_num_tasks = 0.0;
6796 
6797   //implementing a very poor man's hash...
6798   tArray<int> phenotypes;
6799   tArray<int> phenotype_counts;
6800 
6801   for (int i = 0; i < cell_array.GetSize(); i++) {
6802     // Only look at cells with organisms in them.
6803     if (cell_array[i].IsOccupied() == false) continue;
6804 
6805     num_orgs++;
6806     const cPhenotype& phenotype = cell_array[i].GetOrganism()->GetPhenotype();
6807 
6808     int total_tasks = 0;
6809     int id = 0;
6810     cString key;
6811     for (int j = 0; j < phenotype.GetLastTaskCount().GetSize(); j++) {
6812       if (phenotype.GetLastTaskCount()[j] > 0) id += (1 << j);
6813       if (phenotype.GetLastTaskCount()[j] > 0) average_num_tasks += 1.0;
6814       key += cStringUtil::Stringf("%i-", phenotype.GetLastTaskCount()[j]);
6815       total_tasks += phenotype.GetLastTaskCount()[j];
6816     }
6817     ids.insert(id);
6818     complete.insert(key);
6819 
6820     // add one to our count for this key
6821     int k;
6822     for(k=0; k<phenotypes.GetSize(); k++)
6823     {
6824       if (phenotypes[k] == id) {
6825         phenotype_counts[k] = phenotype_counts[k] + 1;
6826         break;
6827       }
6828     }
6829     // this is a new key
6830     if (k == phenotypes.GetSize()) {
6831       phenotypes.Push(id);
6832       phenotype_counts.Push(1);
6833     }
6834 
6835     // go through again to calculate Shannon Diversity of task counts
6836     // now that we know the total number of tasks done
6837     double shannon_diversity = 0;
6838     for (int j = 0; j < phenotype.GetLastTaskCount().GetSize(); j++) {
6839       if (phenotype.GetLastTaskCount()[j] == 0) continue;
6840       double fraction = static_cast<double>(phenotype.GetLastTaskCount()[j]) / static_cast<double>(total_tasks);
6841       shannon_diversity -= fraction * log(fraction) / log(2.0);
6842     }
6843 
6844     average_shannon_diversity += static_cast<double>(shannon_diversity);
6845   }
6846 
6847   double shannon_diversity_of_phenotypes = 0.0;
6848   for (int j = 0; j < phenotype_counts.GetSize(); j++) {
6849     double fraction = static_cast<double>(phenotype_counts[j]) / static_cast<double>(num_orgs);
6850     shannon_diversity_of_phenotypes -= fraction * log(fraction) / log(2.0);
6851   }
6852 
6853   average_shannon_diversity /= static_cast<double>(num_orgs);
6854   average_num_tasks /= num_orgs;
6855 
6856   cDataFile& df = m_world->GetDataFile(filename);
6857   df.WriteTimeStamp();
6858   df.Write(m_world->GetStats().GetUpdate(), "Update");
6859   df.Write(static_cast<int>(ids.size()), "Unique Phenotypes (by task done)");
6860   df.Write(shannon_diversity_of_phenotypes, "Shannon Diversity of Phenotypes (by task done)");
6861   df.Write(static_cast<int>(complete.size()), "Unique Phenotypes (by task count)");
6862   df.Write(average_shannon_diversity, "Average Phenotype Shannon Diversity (by task count)");
6863   df.Write(average_num_tasks, "Average Task Diversity (number of different tasks)");
6864   df.Endl();
6865 }
6866 
PrintPhenotypeStatus(const cString & filename)6867 void cPopulation::PrintPhenotypeStatus(const cString& filename)
6868 {
6869   cDataFile& df_phen = m_world->GetDataFile(filename);
6870 
6871   df_phen.WriteComment("Num orgs doing each task for each deme in population");
6872   df_phen.WriteTimeStamp();
6873   df_phen.Write(m_world->GetStats().GetUpdate(), "Update");
6874 
6875   cString comment;
6876 
6877   for (int i = 0; i < cell_array.GetSize(); i++)
6878   {
6879     // Only look at cells with organisms in them.
6880     if (cell_array[i].IsOccupied() == false) continue;
6881 
6882     const cPhenotype& phenotype = cell_array[i].GetOrganism()->GetPhenotype();
6883 
6884     comment.Set("cur_merit %d;", i);
6885     df_phen.Write(phenotype.GetMerit().GetDouble(), comment);
6886 
6887     comment.Set("cur_merit_base %d;", i);
6888     df_phen.Write(phenotype.GetCurMeritBase(), comment);
6889 
6890     comment.Set("cur_merit_bonus %d;", i);
6891     df_phen.Write(phenotype.GetCurBonus(), comment);
6892 
6893     //    comment.Set("last_merit %d", i);
6894     //    df_phen.Write(phenotype.GetLastMerit(), comment);
6895 
6896     comment.Set("last_merit_base %d", i);
6897     df_phen.Write(phenotype.GetLastMeritBase(), comment);
6898 
6899     comment.Set("last_merit_bonus %d", i);
6900     df_phen.Write(phenotype.GetLastBonus(), comment);
6901 
6902     comment.Set("life_fitness %d", i);
6903     df_phen.Write(phenotype.GetLifeFitness(), comment);
6904 
6905     comment.Set("*");
6906     df_phen.Write("*", comment);
6907 
6908   }
6909   df_phen.Endl();
6910 
6911 }
6912 
PrintHostPhenotypeData(const cString & filename)6913 void cPopulation::PrintHostPhenotypeData(const cString& filename)
6914 {
6915   set<int> ids;
6916   set<cString> complete;
6917   double average_shannon_diversity = 0.0;
6918   int num_orgs = 0; //could get from elsewhere, but more self-contained this way
6919   double average_num_tasks = 0.0;
6920 
6921   //implementing a very poor man's hash...
6922   tArray<int> phenotypes;
6923   tArray<int> phenotype_counts;
6924 
6925   for (int i = 0; i < cell_array.GetSize(); i++) {
6926     // Only look at cells with organisms in them.
6927     if (cell_array[i].IsOccupied() == false) continue;
6928 
6929     num_orgs++;
6930     const cPhenotype& phenotype = cell_array[i].GetOrganism()->GetPhenotype();
6931 
6932     int total_tasks = 0;
6933     int id = 0;
6934     cString key;
6935     for (int j = 0; j < phenotype.GetLastHostTaskCount().GetSize(); j++) {
6936       if (phenotype.GetLastHostTaskCount()[j] > 0) id += (1 << j);
6937       if (phenotype.GetLastHostTaskCount()[j] > 0) average_num_tasks += 1.0;
6938       key += cStringUtil::Stringf("%i-", phenotype.GetLastHostTaskCount()[j]);
6939       total_tasks += phenotype.GetLastHostTaskCount()[j];
6940     }
6941     ids.insert(id);
6942     complete.insert(key);
6943 
6944     // add one to our count for this key
6945     int k;
6946     for(k=0; k<phenotypes.GetSize(); k++)
6947     {
6948       if (phenotypes[k] == id) {
6949         phenotype_counts[k] = phenotype_counts[k] + 1;
6950         break;
6951       }
6952     }
6953     // this is a new key
6954     if (k == phenotypes.GetSize()) {
6955       phenotypes.Push(id);
6956       phenotype_counts.Push(1);
6957     }
6958 
6959     // go through again to calculate Shannon Diversity of task counts
6960     // now that we know the total number of tasks done
6961     double shannon_diversity = 0;
6962     for (int j = 0; j < phenotype.GetLastHostTaskCount().GetSize(); j++) {
6963       if (phenotype.GetLastHostTaskCount()[j] == 0) continue;
6964       double fraction = static_cast<double>(phenotype.GetLastHostTaskCount()[j]) / static_cast<double>(total_tasks);
6965       shannon_diversity -= fraction * log(fraction) / log(2.0);
6966     }
6967 
6968     average_shannon_diversity += static_cast<double>(shannon_diversity);
6969   }
6970 
6971   double shannon_diversity_of_phenotypes = 0.0;
6972   for (int j = 0; j < phenotype_counts.GetSize(); j++) {
6973     double fraction = static_cast<double>(phenotype_counts[j]) / static_cast<double>(num_orgs);
6974     shannon_diversity_of_phenotypes -= fraction * log(fraction) / log(2.0);
6975   }
6976 
6977   average_shannon_diversity /= static_cast<double>(num_orgs);
6978   average_num_tasks /= num_orgs;
6979 
6980   cDataFile& df = m_world->GetDataFile(filename);
6981   df.WriteTimeStamp();
6982   df.Write(m_world->GetStats().GetUpdate(), "Update");
6983   df.Write(static_cast<int>(ids.size()), "Unique Phenotypes (by task done)");
6984   df.Write(shannon_diversity_of_phenotypes, "Shannon Diversity of Phenotypes (by task done)");
6985   df.Write(static_cast<int>(complete.size()), "Unique Phenotypes (by task count)");
6986   df.Write(average_shannon_diversity, "Average Phenotype Shannon Diversity (by task count)");
6987   df.Write(average_num_tasks, "Average Task Diversity (number of different tasks)");
6988   df.Endl();
6989 }
6990 
PrintParasitePhenotypeData(const cString & filename)6991 void cPopulation::PrintParasitePhenotypeData(const cString& filename)
6992 {
6993   set<int> ids;
6994   set<cString> complete;
6995   double average_shannon_diversity = 0.0;
6996   int num_orgs = 0; //could get from elsewhere, but more self-contained this way
6997   double average_num_tasks = 0.0;
6998 
6999   //implementing a very poor man's hash...
7000   tArray<int> phenotypes;
7001   tArray<int> phenotype_counts;
7002 
7003   for (int i = 0; i < cell_array.GetSize(); i++) {
7004     // Only look at cells with organisms in them.
7005     if (cell_array[i].IsOccupied() == false) continue;
7006 
7007     num_orgs++;
7008     const cPhenotype& phenotype = cell_array[i].GetOrganism()->GetPhenotype();
7009 
7010     int total_tasks = 0;
7011     int id = 0;
7012     cString key;
7013     for (int j = 0; j < phenotype.GetLastParasiteTaskCount().GetSize(); j++) {
7014       if (phenotype.GetLastParasiteTaskCount()[j] > 0) id += (1 << j);
7015       if (phenotype.GetLastParasiteTaskCount()[j] > 0) average_num_tasks += 1.0;
7016       key += cStringUtil::Stringf("%i-", phenotype.GetLastParasiteTaskCount()[j]);
7017       total_tasks += phenotype.GetLastParasiteTaskCount()[j];
7018     }
7019     ids.insert(id);
7020     complete.insert(key);
7021 
7022     // add one to our count for this key
7023     int k;
7024     for(k=0; k<phenotypes.GetSize(); k++)
7025     {
7026       if (phenotypes[k] == id) {
7027         phenotype_counts[k] = phenotype_counts[k] + 1;
7028         break;
7029       }
7030     }
7031     // this is a new key
7032     if (k == phenotypes.GetSize()) {
7033       phenotypes.Push(id);
7034       phenotype_counts.Push(1);
7035     }
7036 
7037     // go through again to calculate Shannon Diversity of task counts
7038     // now that we know the total number of tasks done
7039     double shannon_diversity = 0;
7040     for (int j = 0; j < phenotype.GetLastParasiteTaskCount().GetSize(); j++) {
7041       if (phenotype.GetLastParasiteTaskCount()[j] == 0) continue;
7042       double fraction = static_cast<double>(phenotype.GetLastParasiteTaskCount()[j]) / static_cast<double>(total_tasks);
7043       shannon_diversity -= fraction * log(fraction) / log(2.0);
7044     }
7045 
7046     average_shannon_diversity += static_cast<double>(shannon_diversity);
7047   }
7048 
7049   double shannon_diversity_of_phenotypes = 0.0;
7050   for (int j = 0; j < phenotype_counts.GetSize(); j++) {
7051     double fraction = static_cast<double>(phenotype_counts[j]) / static_cast<double>(num_orgs);
7052     shannon_diversity_of_phenotypes -= fraction * log(fraction) / log(2.0);
7053   }
7054 
7055   average_shannon_diversity /= static_cast<double>(num_orgs);
7056   average_num_tasks /= num_orgs;
7057 
7058   cDataFile& df = m_world->GetDataFile(filename);
7059   df.WriteTimeStamp();
7060   df.Write(m_world->GetStats().GetUpdate(), "Update");
7061   df.Write(static_cast<int>(ids.size()), "Unique Phenotypes (by task done)");
7062   df.Write(shannon_diversity_of_phenotypes, "Shannon Diversity of Phenotypes (by task done)");
7063   df.Write(static_cast<int>(complete.size()), "Unique Phenotypes (by task count)");
7064   df.Write(average_shannon_diversity, "Average Phenotype Shannon Diversity (by task count)");
7065   df.Write(average_num_tasks, "Average Task Diversity (number of different tasks)");
7066   df.Endl();
7067 }
7068 
UpdateMerit(int cell_id,double new_merit)7069 bool cPopulation::UpdateMerit(int cell_id, double new_merit)
7070 {
7071   assert( GetCell(cell_id).IsOccupied() == true);
7072   assert( new_merit >= 0.0 );
7073 
7074   cPhenotype & phenotype = GetCell(cell_id).GetOrganism()->GetPhenotype();
7075   double old_merit = phenotype.GetMerit().GetDouble();
7076 
7077   phenotype.SetMerit( cMerit(new_merit) );
7078   phenotype.SetLifeFitness(new_merit/phenotype.GetGestationTime());
7079   if (new_merit <= old_merit) {
7080     phenotype.SetIsDonorCur(); }
7081   else  { phenotype.SetIsReceiver(); }
7082   AdjustSchedule(GetCell(cell_id), phenotype.GetMerit());
7083 
7084   return true;
7085 }
7086 
7087 
AddBeginSleep(int cellID,int start_time)7088 void cPopulation::AddBeginSleep(int cellID, int start_time) {
7089   sleep_log[cellID].Add(make_pair(start_time,-1));
7090 }
7091 
AddEndSleep(int cellID,int end_time)7092 void cPopulation::AddEndSleep(int cellID, int end_time) {
7093   pair<int,int> p = sleep_log[cellID][sleep_log[cellID].Size()-1];
7094   sleep_log[cellID].RemoveAt(sleep_log[cellID].Size()-1);
7095   sleep_log[cellID].Add(make_pair(p.first, end_time));
7096 }
7097 
7098 // Starts a new trial for each organism in the population
NewTrial(cAvidaContext & ctx)7099 void cPopulation::NewTrial(cAvidaContext& ctx)
7100 {
7101   for (int i=0; i< GetSize(); i++) {
7102     cPopulationCell& cell = GetCell(i);
7103     if (cell.IsOccupied()) {
7104       cPhenotype & p =  cell.GetOrganism()->GetPhenotype();
7105 
7106       // Don't continue if the time used was zero
7107       if (p.GetTrialTimeUsed() != 0) {
7108         // Correct gestation time for speculative execution
7109         p.SetTrialTimeUsed(p.GetTrialTimeUsed() - cell.GetSpeculativeState());
7110         p.SetTimeUsed(p.GetTimeUsed() - cell.GetSpeculativeState());
7111 
7112         cell.GetOrganism()->NewTrial();
7113         cell.GetOrganism()->GetHardware().Reset(ctx);
7114 
7115         cell.SetSpeculativeState(0);
7116       }
7117     }
7118   }
7119 
7120   //Recalculate the stats immediately, so that if they are printed before a new update
7121   //is processed, they accurately reflect this trial only...
7122   cStats& stats = m_world->GetStats();
7123   stats.ProcessUpdate();
7124   ProcessPostUpdate(ctx);
7125 }
7126 
7127 /*
7128  CompeteOrganisms
7129 
7130  parents_survive => for any organism represented by >=1 child, the first created is the parent (has no mutations)
7131  dynamic_scaling => rescale the time interval such that the geometric mean of the highest fitness versus lower fitnesses
7132  equals a time of 1 unit
7133  */
7134 
CompeteOrganisms(cAvidaContext & ctx,int competition_type,int parents_survive)7135 void cPopulation::CompeteOrganisms(cAvidaContext& ctx, int competition_type, int parents_survive)
7136 {
7137   NewTrial(ctx);
7138 
7139   double total_fitness = 0;
7140   int num_cells = GetSize();
7141   tArray<double> org_fitness(num_cells);
7142 
7143   double lowest_fitness = -1.0;
7144   double average_fitness = 0;
7145   double highest_fitness = -1.0;
7146   double lowest_fitness_copied = -1.0;
7147   double average_fitness_copied = 0;
7148   double highest_fitness_copied = -1.0;
7149   int different_orgs_copied = 0;
7150   int num_competed_orgs = 0;
7151 
7152   int num_trials = -1;
7153 
7154   int dynamic_scaling = 0;
7155 
7156   if (competition_type==3) dynamic_scaling = 1;
7157   else if  (competition_type==4) dynamic_scaling = 2;
7158 
7159   // How many trials were there? -- same for every organism
7160   // we just need to find one...
7161   for (int i = 0; i < num_cells; i++) {
7162     if (GetCell(i).IsOccupied()) {
7163       cPhenotype& p = GetCell(i).GetOrganism()->GetPhenotype();
7164       // We trigger a lot of asserts if the copied size is zero...
7165       p.SetLinesCopied(p.GetGenomeLength());
7166 
7167       if ( (num_trials != -1) && (num_trials != p.GetTrialFitnesses().GetSize()) ) {
7168         cout << "The number of trials is not the same for every organism in the population.\n";
7169         cout << "You need to remove all normal ways of replicating for CompeteOrganisms to work correctly.\n";
7170         exit(1);
7171       }
7172 
7173       num_trials = p.GetTrialFitnesses().GetSize();
7174     }
7175   }
7176 
7177   // If there weren't any trials then end here (but call new trial so things are set up for the next iteration)
7178   if (num_trials == 0) return;
7179 
7180   if (m_world->GetVerbosity() > VERBOSE_SILENT) cout << "==Compete Organisms==" << endl;
7181 
7182   tArray<double> min_trial_fitnesses(num_trials);
7183   tArray<double> max_trial_fitnesses(num_trials);
7184   tArray<double> avg_trial_fitnesses(num_trials);
7185   avg_trial_fitnesses.SetAll(0);
7186 
7187   bool init = false;
7188   // What is the min and max fitness in each trial
7189   for (int i = 0; i < num_cells; i++) {
7190     if (GetCell(i).IsOccupied()) {
7191       num_competed_orgs++;
7192       cPhenotype& p = GetCell(i).GetOrganism()->GetPhenotype();
7193       tArray<double> trial_fitnesses = p.GetTrialFitnesses();
7194       for (int t=0; t < num_trials; t++) {
7195         if ((!init) || (min_trial_fitnesses[t] > trial_fitnesses[t])) {
7196           min_trial_fitnesses[t] = trial_fitnesses[t];
7197         }
7198         if ((!init) || (max_trial_fitnesses[t] < trial_fitnesses[t])) {
7199           max_trial_fitnesses[t] = trial_fitnesses[t];
7200         }
7201         avg_trial_fitnesses[t] += trial_fitnesses[t];
7202       }
7203       init = true;
7204     }
7205   }
7206 
7207   //divide averages for each trial
7208   for (int t=0; t < num_trials; t++) {
7209     avg_trial_fitnesses[t] /= num_competed_orgs;
7210   }
7211 
7212   if (m_world->GetVerbosity() > VERBOSE_SILENT) {
7213     if (min_trial_fitnesses.GetSize() > 1) {
7214       for (int t=0; t < min_trial_fitnesses.GetSize(); t++) {
7215         cout << "Trial #" << t << " Min Fitness = " << min_trial_fitnesses[t] << ", Avg fitness = " << avg_trial_fitnesses[t] << " Max Fitness = " << max_trial_fitnesses[t] << endl;
7216       }
7217     }
7218   }
7219 
7220   bool using_trials = true;
7221   for (int i = 0; i < num_cells; i++) {
7222     if (GetCell(i).IsOccupied()) {
7223       double fitness = 0.0;
7224       cPhenotype& p = GetCell(i).GetOrganism()->GetPhenotype();
7225       //Don't need to reset trial_fitnesses because we will call cPhenotype::OffspringReset on the entire pop
7226       tArray<double> trial_fitnesses = p.GetTrialFitnesses();
7227 
7228       //If there are no trial fitnesses...use the actual fitness.
7229       if (trial_fitnesses.GetSize() == 0) {
7230         using_trials = false;
7231         trial_fitnesses.Push(p.GetFitness());
7232       }
7233       switch (competition_type) {
7234           //Geometric Mean
7235         case 0:
7236         case 3:
7237         case 4:
7238           //Treat as logs to avoid overflow when multiplying very large fitnesses
7239           fitness = 0;
7240           for (int t=0; t < trial_fitnesses.GetSize(); t++) {
7241             fitness += log(trial_fitnesses[t]);
7242           }
7243           fitness /= (double)trial_fitnesses.GetSize();
7244           fitness = exp( fitness );
7245           break;
7246 
7247           //Product
7248         case 5:
7249           //Treat as logs to avoid overflow when multiplying very large fitnesses
7250           fitness = 0;
7251           for (int t=0; t < trial_fitnesses.GetSize(); t++) {
7252             fitness += log(trial_fitnesses[t]);
7253           }
7254           fitness = exp( fitness );
7255           break;
7256 
7257           //Geometric Mean of normalized values
7258         case 1:
7259           fitness = 1.0;
7260           for (int t=0; t < trial_fitnesses.GetSize(); t++) {
7261             fitness*=trial_fitnesses[t] / max_trial_fitnesses[t];
7262           }
7263           fitness = exp( (1.0/((double)trial_fitnesses.GetSize())) * log(fitness) );
7264           break;
7265 
7266           //Arithmetic Mean
7267         case 2:
7268           fitness = 0;
7269           for (int t=0; t < trial_fitnesses.GetSize(); t++) {
7270             fitness+=trial_fitnesses[t];
7271           }
7272           fitness /= (double)trial_fitnesses.GetSize();
7273           break;
7274 
7275         default:
7276           m_world->GetDriver().RaiseFatalException(1, "Unknown CompeteOrganisms method");
7277       }
7278       if (m_world->GetVerbosity() >= VERBOSE_DETAILS) {
7279         cout << "Trial fitness in cell " << i << " = " << fitness << endl;
7280       }
7281       org_fitness[i] = fitness;
7282       total_fitness += fitness;
7283 
7284       if ((highest_fitness == -1.0) || (fitness > highest_fitness)) highest_fitness = fitness;
7285       if ((lowest_fitness == -1.0) || (fitness < lowest_fitness)) lowest_fitness = fitness;
7286     } // end if occupied
7287   }
7288   average_fitness = total_fitness / num_competed_orgs;
7289 
7290   //Rescale by the geometric mean of the difference from the top score and the average
7291   if ( dynamic_scaling == 1 ) {
7292     double dynamic_factor = 1.0;
7293     if (highest_fitness > 0) {
7294       dynamic_factor = 2 / highest_fitness;
7295     }
7296 
7297     total_fitness = 0;
7298     for (int i = 0; i < num_cells; i++) {
7299       if ( GetCell(i).IsOccupied() ) {
7300         org_fitness[i] *= dynamic_factor;
7301         total_fitness += org_fitness[i];
7302       }
7303     }
7304   }
7305 
7306   // Rescale geometric mean to 1
7307   else if ( dynamic_scaling == 2 ) {
7308     int num_org = 0;
7309     double dynamic_factor = 1.0;
7310     for (int i = 0; i < num_cells; i++) {
7311       if ( GetCell(i).IsOccupied() && (org_fitness[i] > 0.0)) {
7312         num_org++;
7313         dynamic_factor += log(org_fitness[i]);
7314       }
7315     }
7316 
7317     cout << "Scaling factor = " << dynamic_factor << endl;
7318     if (num_org > 0) dynamic_factor = exp(dynamic_factor / (double)num_org);
7319     cout << "Scaling factor = " << dynamic_factor << endl;
7320 
7321     total_fitness = 0;
7322 
7323     for (int i = 0; i < num_cells; i++) {
7324       if ( GetCell(i).IsOccupied() ) {
7325         org_fitness[i] /= dynamic_factor;
7326         total_fitness += org_fitness[i];
7327       }
7328     }
7329   }
7330 
7331   // Pick which orgs should be in the next generation. (Filling all cells)
7332   tArray<int> new_orgs(num_cells);
7333   for (int i = 0; i < num_cells; i++) {
7334     double birth_choice = (double) m_world->GetRandom().GetDouble(total_fitness);
7335     double test_total = 0;
7336     for (int test_org = 0; test_org < num_cells; test_org++) {
7337       test_total += org_fitness[test_org];
7338       if (birth_choice < test_total) {
7339         new_orgs[i] = test_org;
7340         if (m_world->GetVerbosity() >= VERBOSE_DETAILS) cout << "Propagating from cell " << test_org << " to " << i << endl;
7341         if ((highest_fitness_copied == -1.0) || (org_fitness[test_org] > highest_fitness_copied)) highest_fitness_copied = org_fitness[test_org];
7342         if ((lowest_fitness_copied == -1.0) || (org_fitness[test_org] < lowest_fitness_copied)) lowest_fitness_copied = org_fitness[test_org];
7343         average_fitness_copied += org_fitness[test_org];
7344         break;
7345       }
7346     }
7347   }
7348   // average assumes we fill all cells.
7349   average_fitness_copied /= num_cells;
7350 
7351   // Track how many of each org we should have.
7352   tArray<int> org_count(num_cells);
7353   org_count.SetAll(0);
7354   for (int i = 0; i < num_cells; i++) {
7355     org_count[new_orgs[i]]++;
7356   }
7357 
7358   // Reset organism phenotypes that have successfully divided! Must do before injecting children.
7359   // -- but not the full reset if we are using trials, the trial reset should already cover things like task counts, etc.
7360   // calling that twice would erase this information before it could potentially be output between NewTrial and CompeteOrganisms events.
7361   for (int i = 0; i < num_cells; i++) {
7362     if (m_world->GetVerbosity() >= VERBOSE_DETAILS) cout << "Cell " << i << " has " << org_count[i] << " copies in the next generation" << endl;
7363 
7364     if (org_count[i] > 0) {
7365       different_orgs_copied++;
7366       cPhenotype& p = GetCell(i).GetOrganism()->GetPhenotype();
7367       if (using_trials)
7368       {
7369         p.TrialDivideReset( GetCell(i).GetOrganism()->GetGenome().GetSequence() );
7370       }
7371       else //trials not used
7372       {
7373         //TrialReset has never been called so we need the entire routine to make "last" of "cur" stats.
7374         p.DivideReset( GetCell(i).GetOrganism()->GetGenome().GetSequence() );
7375       }
7376     }
7377   }
7378 
7379   tArray<bool> is_init(num_cells);
7380   is_init.SetAll(false);
7381 
7382   // Copy orgs until all org counts are 1.
7383   int last_from_cell_id = 0;
7384   int last_to_cell_id = 0;
7385   while (true) {
7386     // Find the next org to copy...
7387     int from_cell_id, to_cell_id;
7388     for (from_cell_id = last_from_cell_id; from_cell_id < num_cells; from_cell_id++) {
7389       if (org_count[from_cell_id] > 1) break;
7390     }
7391     last_from_cell_id = from_cell_id;
7392 
7393     // Stop if we didn't find another org to copy
7394     if (from_cell_id == num_cells) break;
7395 
7396     for (to_cell_id = last_to_cell_id; to_cell_id < num_cells; to_cell_id++) {
7397       if (org_count[to_cell_id] == 0) break;
7398     }
7399     last_to_cell_id = to_cell_id;
7400 
7401     // We now have both a "from" and a "to" org....
7402     org_count[from_cell_id]--;
7403     org_count[to_cell_id]++;
7404 
7405     cOrganism* organism = GetCell(from_cell_id).GetOrganism();
7406     organism->OffspringGenome() = organism->GetGenome();
7407     if (m_world->GetVerbosity() >= VERBOSE_DETAILS) cout << "Injecting Offspring " << from_cell_id << " to " << to_cell_id << endl;
7408     CompeteOrganisms_ConstructOffspring(to_cell_id, *organism);
7409 
7410     is_init[to_cell_id] = true;
7411   }
7412 
7413   if (!parents_survive)
7414   {
7415     // Now create children from remaining cells into themselves
7416     for (int cell_id = 0; cell_id < num_cells; cell_id++) {
7417       if (!is_init[cell_id])
7418       {
7419         cOrganism* organism = GetCell(cell_id).GetOrganism();
7420         organism->OffspringGenome() = organism->GetGenome();
7421         if (m_world->GetVerbosity() >= VERBOSE_DETAILS) cout << "Re-injecting Self " << cell_id << " to " << cell_id << endl;
7422         CompeteOrganisms_ConstructOffspring(cell_id, *organism);
7423       }
7424     }
7425   }
7426 
7427 
7428   if (m_world->GetVerbosity() > VERBOSE_SILENT)
7429   {
7430     cout << "Competed: Min fitness = " << lowest_fitness << ", Avg fitness = " << average_fitness << " Max fitness = " << highest_fitness << endl;
7431     cout << "Copied  : Min fitness = " << lowest_fitness_copied << ", Avg fitness = " << average_fitness_copied << ", Max fitness = " << highest_fitness_copied << endl;
7432     cout << "Copied  : Different organisms = " << different_orgs_copied << endl;
7433   }
7434 
7435   // copy stats to cStats, so that these can be remembered and printed
7436   m_world->GetStats().SetCompetitionTrialFitnesses(avg_trial_fitnesses);
7437   m_world->GetStats().SetCompetitionFitnesses(average_fitness, lowest_fitness, highest_fitness, average_fitness_copied, lowest_fitness_copied, highest_fitness_copied);
7438   m_world->GetStats().SetCompetitionOrgsReplicated(different_orgs_copied);
7439 
7440   NewTrial(ctx);
7441 }
7442 
7443 
7444 /* This routine is designed to change values in the resource count in the
7445  middle of a run.  This is designed to work with cActionSetGradient Count */
7446 //JW
7447 
UpdateGradientCount(cAvidaContext & ctx,const int Verbosity,cWorld * world,const cString res_name)7448 void cPopulation::UpdateGradientCount(cAvidaContext& ctx, const int Verbosity, cWorld* world, const cString res_name)
7449 {
7450   const cResourceLib & resource_lib = environment.GetResourceLib();
7451   int global_res_index = -1;
7452 
7453   for (int i = 0; i < resource_lib.GetSize(); i++) {
7454     cResource * res = resource_lib.GetResource(i);
7455 
7456     if (!res->GetDemeResource()) global_res_index++;
7457 
7458     if (res->GetName() == res_name) {
7459       resource_count.SetGradientCount(ctx, world, global_res_index, res->GetPeakX(), res->GetPeakY(),
7460                            res->GetHeight(), res->GetSpread(), res->GetPlateau(), res->GetDecay(),
7461                            res->GetMaxX(), res->GetMinX(), res->GetMaxY(), res->GetMinY(), res->GetAscaler(), res->GetUpdateStep(),
7462                            res->GetHalo(), res->GetHaloInnerRadius(), res->GetHaloWidth(),
7463                            res->GetHaloAnchorX(), res->GetHaloAnchorY(), res->GetMoveSpeed(),
7464                            res->GetPlateauInflow(), res->GetPlateauOutflow(), res->GetConeInflow(), res->GetConeOutflow(),
7465                            res->GetGradientInflow(), res->GetIsPlateauCommon(), res->GetFloor(), res->GetHabitat(),
7466                            res->GetMinSize(), res->GetMaxSize(), res->GetConfig(), res->GetCount(), res->GetResistance(),
7467                            res->GetInitialPlatVal(), res->GetThreshold(), res->GetRefuge());
7468     }
7469   }
7470 }
7471 
UpdateGradientPlatInflow(const cString res_name,const double inflow)7472 void cPopulation::UpdateGradientPlatInflow(const cString res_name, const double inflow)
7473 {
7474   const cResourceLib & resource_lib = environment.GetResourceLib();
7475   int global_res_index = -1;
7476 
7477   for (int i = 0; i < resource_lib.GetSize(); i++) {
7478     cResource * res = resource_lib.GetResource(i);
7479     if (!res->GetDemeResource()) global_res_index++;
7480     if (res->GetName() == res_name) {
7481       res->SetPlateauInflow(inflow);
7482       resource_count.SetGradientPlatInflow(global_res_index, inflow);
7483     }
7484   }
7485 }
7486 
UpdateGradientPlatOutflow(const cString res_name,const double outflow)7487 void cPopulation::UpdateGradientPlatOutflow(const cString res_name, const double outflow)
7488 {
7489   const cResourceLib & resource_lib = environment.GetResourceLib();
7490   int global_res_index = -1;
7491 
7492   for (int i = 0; i < resource_lib.GetSize(); i++) {
7493     cResource * res = resource_lib.GetResource(i);
7494     if (!res->GetDemeResource()) global_res_index++;
7495     if (res->GetName() == res_name) {
7496       res->SetPlateauOutflow(outflow);
7497       resource_count.SetGradientPlatOutflow(global_res_index, outflow);
7498     }
7499   }
7500 }
7501 
UpdateGradientConeInflow(const cString res_name,const double inflow)7502 void cPopulation::UpdateGradientConeInflow(const cString res_name, const double inflow)
7503 {
7504   const cResourceLib & resource_lib = environment.GetResourceLib();
7505   int global_res_index = -1;
7506 
7507   for (int i = 0; i < resource_lib.GetSize(); i++) {
7508     cResource * res = resource_lib.GetResource(i);
7509     if (!res->GetDemeResource()) global_res_index++;
7510     if (res->GetName() == res_name) {
7511       res->SetConeInflow(inflow);
7512       resource_count.SetGradientConeInflow(global_res_index, inflow);
7513     }
7514   }
7515 }
7516 
UpdateGradientConeOutflow(const cString res_name,const double outflow)7517 void cPopulation::UpdateGradientConeOutflow(const cString res_name, const double outflow)
7518 {
7519   const cResourceLib & resource_lib = environment.GetResourceLib();
7520   int global_res_index = -1;
7521 
7522   for (int i = 0; i < resource_lib.GetSize(); i++) {
7523     cResource * res = resource_lib.GetResource(i);
7524     if (!res->GetDemeResource()) global_res_index++;
7525     if (res->GetName() == res_name) {
7526       res->SetConeOutflow(outflow);
7527       resource_count.SetGradientConeOutflow(global_res_index, outflow);
7528     }
7529   }
7530 }
7531 
UpdateGradientInflow(const cString res_name,const double inflow)7532 void cPopulation::UpdateGradientInflow(const cString res_name, const double inflow)
7533 {
7534   const cResourceLib & resource_lib = environment.GetResourceLib();
7535   int global_res_index = -1;
7536 
7537   for (int i = 0; i < resource_lib.GetSize(); i++) {
7538     cResource * res = resource_lib.GetResource(i);
7539     if (!res->GetDemeResource()) global_res_index++;
7540     if (res->GetName() == res_name) {
7541       res->SetGradientInflow(inflow);
7542       resource_count.SetGradientInflow(global_res_index, inflow);
7543     }
7544   }
7545 }
7546 
SetGradPlatVarInflow(const cString res_name,const double mean,const double variance,const int type)7547 void cPopulation::SetGradPlatVarInflow(const cString res_name, const double mean, const double variance, const int type)
7548 {
7549   const cResourceLib & resource_lib = environment.GetResourceLib();
7550   int global_res_index = -1;
7551 
7552   for (int i = 0; i < resource_lib.GetSize(); i++) {
7553     cResource * res = resource_lib.GetResource(i);
7554     if (!res->GetDemeResource()) global_res_index++;
7555     if (res->GetName() == res_name) {
7556       resource_count.SetGradPlatVarInflow(global_res_index, mean, variance, type);
7557     }
7558   }
7559 }
7560 
SetPredatoryResource(const cString res_name,const double odds,const int juvsper,const double detection_prob)7561 void cPopulation::SetPredatoryResource(const cString res_name, const double odds, const int juvsper, const double detection_prob)
7562 {
7563   const cResourceLib & resource_lib = environment.GetResourceLib();
7564   int global_res_index = -1;
7565 
7566   for (int i = 0; i < resource_lib.GetSize(); i++) {
7567     cResource* res = resource_lib.GetResource(i);
7568     if (!res->GetDemeResource()) global_res_index++;
7569     if (res->GetName() == res_name) {
7570       res->SetPredatoryResource(odds, juvsper, detection_prob);
7571       res->SetHabitat(5);
7572       environment.AddHabitat(5);
7573       resource_count.SetPredatoryResource(global_res_index, odds, juvsper);
7574     }
7575   }
7576   m_has_predatory_res = true;
7577 }
7578 
SetProbabilisticResource(cAvidaContext & ctx,const cString res_name,const double initial,const double inflow,const double outflow,const double lambda,const double theta,const int x,const int y,const int count)7579 void cPopulation::SetProbabilisticResource(cAvidaContext& ctx, const cString res_name, const double initial, const double inflow,
7580   const double outflow, const double lambda, const double theta, const int x, const int y, const int count)
7581 {
7582   const cResourceLib & resource_lib = environment.GetResourceLib();
7583   int global_res_index = -1;
7584 
7585   for (int i = 0; i < resource_lib.GetSize(); i++) {
7586     cResource* res = resource_lib.GetResource(i);
7587     if (!res->GetDemeResource()) global_res_index++;
7588     if (res->GetName() == res_name) {
7589       resource_count.SetProbabilisticResource(ctx, global_res_index, initial, inflow, outflow, lambda, theta, x, y, count);
7590       break;
7591     }
7592   }
7593 }
7594 
ExecutePredatoryResource(cAvidaContext & ctx,const int cell_id,const double pred_odds,const int juvs_per)7595 void cPopulation::ExecutePredatoryResource(cAvidaContext& ctx, const int cell_id, const double pred_odds, const int juvs_per)
7596 {
7597   cPopulationCell& cell = m_world->GetPopulation().GetCell(cell_id);
7598   const int juv_age = m_world->GetConfig().JUV_PERIOD.Get();
7599 
7600   const cResourceLib& resource_lib = m_world->GetEnvironment().GetResourceLib();
7601 
7602   tArray<double> cell_res;
7603   cell_res = GetCellResources(cell_id, ctx);
7604 
7605   bool cell_has_den = false;
7606   for (int j = 0; j < cell_res.GetSize(); j++) {
7607     if ((resource_lib.GetResource(j)->GetHabitat() == 4 || resource_lib.GetResource(j)->GetHabitat() == 3) && cell_res[j] > 0) {
7608       cell_has_den = true;
7609       break;
7610     }
7611   }
7612 
7613   if (m_world->GetConfig().USE_AVATARS.Get() && cell.HasAV()) {
7614     tArray<cOrganism*> cell_avs = cell.GetCellAVs();
7615 
7616     // on den, kill juvs only
7617     if (cell_has_den) {
7618       tArray<cOrganism*> juvs;
7619       juvs.Resize(0);
7620       int num_juvs = 0;
7621       int num_guards = 0;
7622       for (int k = 0; k < cell_avs.GetSize(); k++) {
7623         if (cell_avs[k]->GetPhenotype().GetTimeUsed() < juv_age) {
7624           num_juvs++;
7625           juvs.Push(cell_avs[k]);
7626         }
7627         else if (cell_avs[k]->IsGuard()) num_guards++;
7628       }
7629       if (num_juvs > 0) {
7630         int guarded_juvs = num_guards * juvs_per;
7631         int unguarded_juvs = num_juvs - guarded_juvs;
7632         for (int k = 0; k < unguarded_juvs; k++) {
7633           if (ctx.GetRandom().P(pred_odds) && !juvs[k]->IsDead()) {
7634             if (!juvs[k]->IsRunning()) KillOrganism(GetCell(juvs[k]->GetCellID()), ctx);
7635             else {
7636                 juvs[k]->GetPhenotype().SetToDie();
7637                 m_world->GetStats().IncJuvKilled();
7638             }
7639           }
7640         }
7641       }
7642     }
7643     // away from den, kill anyone
7644     else {
7645       if (ctx.GetRandom().P(pred_odds)) {
7646         cOrganism* target_org = cell_avs[m_world->GetRandom().GetUInt(cell_avs.GetSize())];
7647         if (!target_org->IsDead()) {
7648           if (!target_org->IsRunning()) KillOrganism(GetCell(target_org->GetCellID()), ctx);
7649           else target_org->GetPhenotype().SetToDie();
7650         }
7651       }
7652     }
7653   }
7654   else if (!m_world->GetConfig().USE_AVATARS.Get() && cell.IsOccupied()) {
7655     cOrganism* target_org = cell.GetOrganism();
7656     // if not avatars, a juv will be killed regardless of whether it is on a den
7657     // an adult would only be targeted off of a den
7658     if (target_org->GetPhenotype().GetTimeUsed() < juv_age || !cell_has_den) {
7659       if (ctx.GetRandom().P(pred_odds) && !target_org->IsDead()) {
7660           if (!target_org->IsRunning()) KillOrganism(GetCell(target_org->GetCellID()), ctx);
7661           else target_org->GetPhenotype().SetToDie();
7662       }
7663     }
7664   }
7665 }
7666 
UpdateResourceCount(const int Verbosity,cWorld * world)7667 void cPopulation::UpdateResourceCount(const int Verbosity, cWorld* world) {
7668   const cResourceLib & resource_lib = environment.GetResourceLib();
7669   int global_res_index = -1;
7670   int deme_res_index = -1;
7671   int num_deme_res = 0;
7672 
7673   //setting size of global and deme-level resources
7674   for(int i = 0; i < resource_lib.GetSize(); i++) {
7675     cResource * res = resource_lib.GetResource(i);
7676     if (res->GetDemeResource())
7677       num_deme_res++;
7678   }
7679 
7680   for(int i = 0; i < GetNumDemes(); i++) {
7681     cResourceCount tmp_deme_res_count(num_deme_res);
7682     GetDeme(i).SetDemeResourceCount(tmp_deme_res_count);
7683   }
7684 
7685   for (int i = 0; i < resource_lib.GetSize(); i++) {
7686     cResource * res = resource_lib.GetResource(i);
7687     if (!res->GetDemeResource()) {
7688       global_res_index++;
7689       const double decay = 1.0 - res->GetOutflow();
7690       resource_count.Setup(world, global_res_index, res->GetName(), res->GetInitial(),
7691                            res->GetInflow(), decay,
7692                            res->GetGeometry(), res->GetXDiffuse(),
7693                            res->GetXGravity(), res->GetYDiffuse(),
7694                            res->GetYGravity(), res->GetInflowX1(),
7695                            res->GetInflowX2(), res->GetInflowY1(),
7696                            res->GetInflowY2(), res->GetOutflowX1(),
7697                            res->GetOutflowX2(), res->GetOutflowY1(),
7698                            res->GetOutflowY2(), res->GetCellListPtr(),
7699                            res->GetCellIdListPtr(), Verbosity,
7700                            res->GetDynamicResource(), res->GetPeaks(),
7701                            res->GetMinHeight(), res->GetMinRadius(), res->GetRadiusRange(),
7702                            res->GetAh(), res->GetAr(),
7703                            res->GetAcx(), res->GetAcy(),
7704                            res->GetHStepscale(), res->GetRStepscale(),
7705                            res->GetCStepscaleX(), res->GetCStepscaleY(),
7706                            res->GetHStep(), res->GetRStep(),
7707                            res->GetCStepX(), res->GetCStepY(),
7708                            res->GetUpdateDynamic(), res->GetPeakX(), res->GetPeakY(),
7709                            res->GetHeight(), res->GetSpread(), res->GetPlateau(), res->GetDecay(),
7710                            res->GetMaxX(), res->GetMinX(), res->GetMaxY(), res->GetMinY(), res->GetAscaler(), res->GetUpdateStep(),
7711                            res->GetHalo(), res->GetHaloInnerRadius(), res->GetHaloWidth(),
7712                            res->GetHaloAnchorX(), res->GetHaloAnchorY(), res->GetMoveSpeed(),
7713                            res->GetPlateauInflow(), res->GetPlateauOutflow(), res->GetConeInflow(), res->GetConeOutflow(),
7714                            res->GetGradientInflow(), res->GetIsPlateauCommon(), res->GetFloor(), res->GetHabitat(),
7715                            res->GetMinSize(), res->GetMaxSize(), res->GetConfig(), res->GetCount(), res->GetResistance(),
7716                            res->GetInitialPlatVal(), res->GetThreshold(), res->GetRefuge(), res->GetGradient()
7717                            );
7718 
7719     } else if (res->GetDemeResource()) {
7720       deme_res_index++;
7721       for(int j = 0; j < GetNumDemes(); j++) {
7722         GetDeme(j).SetupDemeRes(deme_res_index, res, Verbosity, world);
7723         // could add deme resources to global resource stats here
7724       }
7725     } else {
7726       cerr<< "ERROR: Resource \"" << res->GetName() <<"\"is not a global or deme resource.  Exit";
7727       exit(1);
7728     }
7729   }
7730 
7731 }
7732 
7733 
7734 // Adds an organism to live org list
AddLiveOrg(cOrganism * org)7735 void  cPopulation::AddLiveOrg(cOrganism* org)
7736 {
7737   live_org_list.Push(org);
7738   org->SetOrgIndex(live_org_list.GetSize()-1);
7739 }
7740 
7741 // Remove an organism from live org list
RemoveLiveOrg(cOrganism * org)7742 void  cPopulation::RemoveLiveOrg(cOrganism* org)
7743 {
7744   unsigned int last = live_org_list.GetSize() - 1;
7745   cOrganism* exist_org = live_org_list[last];
7746   exist_org->SetOrgIndex(org->GetOrgIndex());
7747   live_org_list.Swap(org->GetOrgIndex(), last);
7748   live_org_list.Pop();
7749 }
7750 
7751 
7752 // Adds an organism to a group
JoinGroup(cOrganism * org,int group_id)7753 void  cPopulation::JoinGroup(cOrganism* org, int group_id)
7754 {
7755   map<int,int>::iterator it;
7756   it=m_groups.find(group_id);
7757   if (it == m_groups.end()) {
7758     // new group
7759     m_groups[group_id] = 0;
7760     tSmartArray<cOrganism*> temp;
7761     group_list.Set(group_id, temp);
7762     // If tolerance is on, create the new group's tolerance cache
7763     if (m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
7764       tArray<pair<int,int> > temp_array(2);
7765       temp_array[0] = make_pair(-1, -1);
7766       temp_array[1] = make_pair(-1, -1);
7767       m_group_intolerances.Set(group_id, temp_array);
7768       if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
7769         m_group_intolerances_females.Set(group_id, temp_array);
7770         m_group_intolerances_males.Set(group_id, temp_array);
7771         m_group_intolerances_juvs.Set(group_id, temp_array);
7772       }
7773     }
7774   }
7775   // add to group
7776   m_groups[group_id]++;
7777   if (org->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) m_group_females[group_id]++;
7778   else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) m_group_males[group_id]++;
7779 
7780   group_list[group_id].Push(org);
7781   // If tolerance is on, must add the organism's intolerance to the group cache
7782   if (m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
7783     int tol_max = m_world->GetConfig().MAX_TOLERANCE.Get();
7784     int immigrant_tol = org->GetPhenotype().CalcToleranceImmigrants();
7785     m_group_intolerances[group_id][0].second += tol_max - immigrant_tol;
7786     if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
7787       if (org->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) {
7788         m_group_intolerances_females[group_id][0].second += tol_max - immigrant_tol;
7789       } else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) {
7790         m_group_intolerances_males[group_id][0].second += tol_max - immigrant_tol;
7791       } else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) {
7792         m_group_intolerances_juvs[group_id][0].second += tol_max - immigrant_tol;
7793       }
7794     }
7795     m_group_intolerances[group_id][1].second += tol_max - org->GetPhenotype().CalcToleranceOffspringOthers();
7796   }
7797 }
7798 
7799 // Makes a new group (highest current group number +1)
MakeGroup(cOrganism * org)7800 void cPopulation::MakeGroup(cOrganism* org)
7801 {
7802   if (m_world->GetConfig().USE_FORM_GROUPS.Get() != 1) return;
7803 
7804   int highest_group;
7805   if (m_groups.size() > 0) {
7806     highest_group = m_groups.rbegin()->first;
7807   } else {
7808     highest_group = -1;
7809   }
7810 
7811   org->SetOpinion(highest_group + 1);
7812   JoinGroup(org, highest_group + 1);
7813 }
7814 
7815 // Removes an organism from a group
LeaveGroup(cOrganism * org,int group_id)7816 void  cPopulation::LeaveGroup(cOrganism* org, int group_id)
7817 {
7818   map<int,int>::iterator it = m_groups.find(group_id);
7819   if (it != m_groups.end()) {
7820     m_groups[group_id]--;
7821     if (org->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) m_group_females[group_id]--;
7822     else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) m_group_males[group_id]--;
7823 
7824     // If no restrictions on group ids,
7825     // removes empty groups so the number of total groups being tracked doesn't become excessive
7826     // (Removes the highest group even if empty, causes misstep in marching groups).
7827     if (m_world->GetConfig().USE_FORM_GROUPS.Get() == 1) {
7828       if (m_groups[group_id] <= 0) {
7829         m_groups.erase(group_id);
7830       }
7831     }
7832   }
7833 
7834   // If tolerance is on, remove the organim's intolerance from the group's cache
7835   if (m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
7836     int tol_max = m_world->GetConfig().MAX_TOLERANCE.Get();
7837     int immigrant_tol = org->GetPhenotype().CalcToleranceImmigrants();
7838     m_group_intolerances[group_id][0].second -= tol_max - immigrant_tol;
7839     if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
7840       if (org->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) {
7841         m_group_intolerances_females[group_id][0].second -= tol_max - immigrant_tol;
7842       } else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) {
7843         m_group_intolerances_males[group_id][0].second -= tol_max - immigrant_tol;
7844       } else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) {
7845         m_group_intolerances_juvs[group_id][0].second -= tol_max - immigrant_tol;
7846       }
7847     }
7848     m_group_intolerances[group_id][1].second -= tol_max - org->GetPhenotype().CalcToleranceOffspringOthers();
7849   }
7850 
7851   for (int i = 0; i < group_list[group_id].GetSize(); i++) {
7852     if (group_list[group_id][i] == org) {
7853       unsigned int last = group_list[group_id].GetSize() - 1;
7854       group_list[group_id].Swap(i,last);
7855       group_list[group_id].Pop();
7856       // If no restrictions, removes empty groups.
7857       if (m_world->GetConfig().USE_FORM_GROUPS.Get() == 1) {
7858         if (group_list[group_id].GetSize() <= 0) {
7859           group_list.Remove(group_id);
7860         }
7861       }
7862       break;
7863     }
7864   }
7865 }
7866 
7867 // Identifies the number of organisms in a group
NumberOfOrganismsInGroup(int group_id)7868 int  cPopulation::NumberOfOrganismsInGroup(int group_id)
7869 {
7870   map<int,int>::iterator it;
7871   it=m_groups.find(group_id);
7872   int num_orgs = 0;
7873   if (it != m_groups.end()) {
7874     num_orgs = m_groups[group_id];
7875   }
7876   return num_orgs;
7877 }
7878 
NumberGroupFemales(int group_id)7879 int  cPopulation::NumberGroupFemales(int group_id)
7880 {
7881   map<int,int>::iterator it;
7882   it=m_groups.find(group_id);
7883   int num_orgs = 0;
7884   if (it != m_groups.end()) {
7885     num_orgs = m_group_females[group_id];
7886   }
7887   return num_orgs;
7888 }
7889 
NumberGroupMales(int group_id)7890 int  cPopulation::NumberGroupMales(int group_id)
7891 {
7892   map<int,int>::iterator it;
7893   it=m_groups.find(group_id);
7894   int num_orgs = 0;
7895   if (it != m_groups.end()) {
7896     num_orgs = m_group_males[group_id];
7897   }
7898   return num_orgs;
7899 }
7900 
NumberGroupJuvs(int group_id)7901 int  cPopulation::NumberGroupJuvs(int group_id)
7902 {
7903   map<int,int>::iterator it;
7904   it=m_groups.find(group_id);
7905   int num_males = 0;
7906   int num_females = 0;
7907   int tot_orgs = 0;
7908   if (it != m_groups.end()) {
7909     num_males = m_group_males[group_id];
7910     num_females = m_group_females[group_id];
7911     tot_orgs = m_groups[group_id];
7912   }
7913   return tot_orgs - (num_males + num_females);
7914 }
7915 
ChangeGroupMatingTypes(cOrganism * org,int group_id,int old_type,int new_type)7916 void  cPopulation::ChangeGroupMatingTypes(cOrganism* org, int group_id, int old_type, int new_type)
7917 {
7918   if (old_type == new_type) return;
7919 
7920   if (old_type == 0) m_group_females[group_id]--;
7921   else if (old_type == 1) m_group_males[group_id]--;
7922 
7923   if (new_type == 0) m_group_females[group_id]++;
7924   else if (new_type == 1) m_group_males[group_id]++;
7925 
7926   if (m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
7927     if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
7928       int tol_max = m_world->GetConfig().MAX_TOLERANCE.Get();
7929       int immigrant_tol = org->GetPhenotype().CalcToleranceImmigrants();
7930       // remove from old
7931       if (old_type == 0) {
7932         m_group_intolerances_females[group_id][0].second -= tol_max - immigrant_tol;
7933       } else if (old_type == 1) {
7934         m_group_intolerances_males[group_id][0].second -= tol_max - immigrant_tol;
7935       } else if (old_type == 2) {
7936         m_group_intolerances_juvs[group_id][0].second -= tol_max - immigrant_tol;
7937       }
7938       // add to new
7939       if (new_type == 0) {
7940         m_group_intolerances_females[group_id][0].second += tol_max - immigrant_tol;
7941       } else if (new_type == 1) {
7942         m_group_intolerances_males[group_id][0].second += tol_max - immigrant_tol;
7943       } else if (new_type == 2) {
7944         m_group_intolerances_juvs[group_id][0].second += tol_max - immigrant_tol;
7945       }
7946     }
7947   }
7948 }
7949 
7950 // Calculates group tolerance towards immigrants
CalcGroupToleranceImmigrants(int group_id,int mating_type)7951 int cPopulation::CalcGroupToleranceImmigrants(int group_id, int mating_type)
7952 {
7953   const int tolerance_max = m_world->GetConfig().MAX_TOLERANCE.Get();
7954 
7955   if (group_id < 0) return tolerance_max;
7956   if (group_list[group_id].GetSize() <= 0) return tolerance_max;
7957 
7958   // use cache, if up to date
7959   int tol_update = m_group_intolerances[group_id][0].first;
7960   int group_intol = m_group_intolerances[group_id][0].second;
7961   if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
7962     if (mating_type == 0) {
7963       tol_update = m_group_intolerances_females[group_id][0].first;
7964       group_intol = m_group_intolerances_females[group_id][0].second;
7965     } else if (mating_type == 1) {
7966       tol_update = m_group_intolerances_males[group_id][0].first;
7967       group_intol = m_group_intolerances_males[group_id][0].second;
7968     } else if (mating_type == 2) {
7969       tol_update = m_group_intolerances_juvs[group_id][0].first;
7970       group_intol = m_group_intolerances_juvs[group_id][0].second;
7971     }
7972   }
7973   int cur_update = m_world->GetStats().GetUpdate();
7974   if (tol_update == cur_update) return max(0, tolerance_max - group_intol);
7975 
7976   // If can't use cache, sum the total group intolerance
7977   int group_intolerance = 0;
7978   int single_member_intolerance = 0;
7979   for (int index = 0; index < group_list[group_id].GetSize(); index++) {
7980     bool use_org = true;
7981     // if using immigrant only tolerance + sex, only update the cache for this current mating type
7982     if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
7983       if (mating_type == 0 && group_list[group_id][index]->GetPhenotype().GetMatingType() != MATING_TYPE_FEMALE)  use_org = false;
7984       else if (mating_type == 1 && group_list[group_id][index]->GetPhenotype().GetMatingType() != MATING_TYPE_MALE)  use_org = false;
7985       else if (mating_type == 2 && group_list[group_id][index]->GetPhenotype().GetMatingType() != MATING_TYPE_JUVENILE)  use_org = false;
7986     }
7987     if (use_org) single_member_intolerance = tolerance_max - group_list[group_id][index]->GetPhenotype().CalcToleranceImmigrants();
7988     group_intolerance += single_member_intolerance;
7989   }
7990 
7991   // Save current update and current intolerance to group cache
7992   // this is the only time we can do this since this is the only
7993   // time we ever look at the entire group (updated every individual) or sub-group (by sex)
7994   if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() != 2) {
7995     m_group_intolerances[group_id][0].first = cur_update;
7996     m_group_intolerances[group_id][0].second = group_intolerance;
7997   } else {
7998     if (mating_type == 0) {
7999       m_group_intolerances_females[group_id][0].first = cur_update;
8000       m_group_intolerances_females[group_id][0].second = group_intolerance;
8001     } else if (mating_type == 1) {
8002       m_group_intolerances_males[group_id][0].first = cur_update;
8003       m_group_intolerances_males[group_id][0].second = group_intolerance;
8004     } else if (mating_type == 2) {
8005       m_group_intolerances_juvs[group_id][0].first = cur_update;
8006       m_group_intolerances_juvs[group_id][0].second = group_intolerance;
8007     }
8008   }
8009 
8010   int group_tolerance = tolerance_max - group_intolerance;
8011   // return zero if totally intolerant (no negative numbers)
8012   return max(0, group_tolerance);
8013 }
8014 
8015 // Calculates group tolerance towards offspring (not including parent)
CalcGroupToleranceOffspring(cOrganism * parent_organism)8016 int cPopulation::CalcGroupToleranceOffspring(cOrganism* parent_organism)
8017 {
8018   const int tolerance_max = m_world->GetConfig().MAX_TOLERANCE.Get();
8019   int group_id = parent_organism->GetOpinion().first;
8020 
8021   if ((group_id < 0) || (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() > 0)) return tolerance_max;
8022   if (group_list[group_id].GetSize() <= 0) return tolerance_max;
8023 
8024   int cur_update = m_world->GetStats().GetUpdate();
8025   int parent_intolerance = tolerance_max - parent_organism->GetPhenotype().CalcToleranceOffspringOthers();
8026 
8027   int group_intolerance = 0;
8028   if (m_group_intolerances[group_id][1].first == cur_update) {
8029     group_intolerance = m_group_intolerances[group_id][1].second;
8030   } else {
8031     int single_member_intolerance = 0;
8032     // Sum the total group intolerance
8033     for (int index = 0; index < group_list[group_id].GetSize(); index++) {
8034       single_member_intolerance = tolerance_max - group_list[group_id][index]->GetPhenotype().CalcToleranceOffspringOthers();
8035       group_intolerance += single_member_intolerance;
8036     }
8037     // Save current update and current intolerance to cache
8038     m_group_intolerances[group_id][1].first = cur_update;
8039     m_group_intolerances[group_id][1].second = group_intolerance;
8040   }
8041 
8042   // Remove the parent intolerance
8043   group_intolerance -= parent_intolerance;
8044   int group_tolerance = tolerance_max - group_intolerance;
8045   return max(0, group_tolerance);
8046 }
8047 
8048 // Calculates the odds (out of 1) for successful immigration based on group's tolerance
CalcGroupOddsImmigrants(int group_id,int mating_type)8049 double cPopulation::CalcGroupOddsImmigrants(int group_id, int mating_type)
8050 {
8051   if (group_id < 0) return 1.0;
8052 
8053   const int tolerance_max = m_world->GetConfig().MAX_TOLERANCE.Get();
8054   int group_tolerance = CalcGroupToleranceImmigrants(group_id, mating_type);
8055   double immigrant_odds = (double) group_tolerance / (double) tolerance_max;
8056   return immigrant_odds;
8057 }
8058 
8059 // Returns true if the org successfully passes immigration tolerance and joins the group
AttemptImmigrateGroup(int group_id,cOrganism * org)8060 bool cPopulation::AttemptImmigrateGroup(int group_id, cOrganism* org)
8061 {
8062   bool immigrate = false;
8063   // If non-standard group, automatic success
8064   if (group_id < 0) return true;
8065 
8066   // If there are no members of the target group, automatic successful immigration
8067   if (m_world->GetPopulation().NumberOfOrganismsInGroup(group_id) == 0) immigrate = true;
8068   else if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
8069     if (org->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE && NumberGroupFemales(group_id) == 0) immigrate = true;
8070     else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_MALE && NumberGroupMales(group_id) == 0) immigrate = true;
8071     else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE && NumberGroupJuvs(group_id) == 0) immigrate = true;
8072   // Calculate chances based on target group tolerance of another org successfully immigrating
8073   } else {
8074     int mating_type = -1;
8075     if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
8076       if (org->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) mating_type = 0;
8077       else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) mating_type = 1;
8078       else if (org->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) mating_type = 2;
8079     }
8080     double probability_immigration = CalcGroupOddsImmigrants(group_id, mating_type);
8081 
8082     double rand = m_world->GetRandom().GetDouble();
8083     if (rand <= probability_immigration) immigrate = true;
8084   }
8085 
8086   if (immigrate) {
8087     int opinion = m_world->GetConfig().DEFAULT_GROUP.Get();
8088     if (org->HasOpinion()) {
8089       opinion = org->GetOpinion().first;
8090       LeaveGroup(org, opinion);
8091     }
8092     org->SetOpinion(group_id);
8093     JoinGroup(org, group_id);
8094   }
8095   return immigrate;
8096 }
8097 
8098 // Calculates the odds (out of 1) for the organism's offspring to be born into its parent's group
CalcGroupOddsOffspring(cOrganism * parent)8099 double cPopulation::CalcGroupOddsOffspring(cOrganism* parent)
8100 {
8101   assert(parent->HasOpinion());
8102 
8103   // If non-standard group, automatic success
8104   if ((parent->GetOpinion().first < 0) || (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() > 0)) return 1.0;
8105 
8106   const double tolerance_max = (double) m_world->GetConfig().MAX_TOLERANCE.Get();
8107 
8108   double parent_tolerance = (double) parent->GetPhenotype().CalcToleranceOffspringOwn();
8109   double parent_group_tolerance = (double) CalcGroupToleranceOffspring(parent);
8110 
8111   const double prob_parent_allows =  parent_tolerance / tolerance_max;
8112   const double prob_group_allows = parent_group_tolerance / tolerance_max;
8113 
8114   double prob = prob_parent_allows * prob_group_allows;
8115 
8116   return prob;
8117 }
8118 
8119 // Calculates the odds (out of 1) for offspring to be born into the group
CalcGroupOddsOffspring(int group_id)8120 double cPopulation::CalcGroupOddsOffspring(int group_id)
8121 {
8122   // If non-standard group, automatic success
8123   if ((group_id < 0) || (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() > 0)) return 1.0;
8124 
8125   const int tolerance_max = m_world->GetConfig().MAX_TOLERANCE.Get();
8126 
8127   int group_intolerance = 0;
8128   int single_member_intolerance = 0;
8129   for (int index = 0; index < group_list[group_id].GetSize(); index++) {
8130     single_member_intolerance = tolerance_max - group_list[group_id][index]->GetPhenotype().CalcToleranceOffspringOthers();
8131     group_intolerance += single_member_intolerance;
8132     if (group_intolerance >= tolerance_max) {
8133       group_intolerance = tolerance_max;
8134       break;
8135     }
8136   }
8137 
8138   int group_tolerance = tolerance_max - group_intolerance;
8139   double offspring_odds = (double) group_tolerance / (double) tolerance_max;
8140   return offspring_odds;
8141 }
8142 
AttemptOffspringParentGroup(cAvidaContext & ctx,cOrganism * parent,cOrganism * offspring)8143 bool cPopulation::AttemptOffspringParentGroup(cAvidaContext& ctx, cOrganism* parent, cOrganism* offspring)
8144 {
8145   // If joining a non-standard group, only immigrant tolerance, or only immigrant + sex tolerance, automatic success
8146   if ((parent->GetOpinion().first < 0) || (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() > 0)) {
8147     int parent_group = parent->GetOpinion().first;
8148     offspring->SetOpinion(parent_group);
8149     JoinGroup(offspring, parent_group);
8150     return true;
8151   }
8152 
8153   // If using % chance of random migration
8154   if (m_world->GetConfig().TOLERANCE_WINDOW.Get() < 0) {
8155     const int parent_group = parent->GetOpinion().first;
8156     const double prob_immigrate = ((double) m_world->GetConfig().TOLERANCE_WINDOW.Get() * -1.0) / 100.0;
8157     double rand = m_world->GetRandom().GetDouble();
8158     if (rand <= prob_immigrate) {
8159       const int num_groups = m_world->GetPopulation().GetResources(ctx).GetSize();
8160       int target_group;
8161       do {
8162         target_group = m_world->GetRandom().GetUInt(num_groups);
8163       } while (target_group == parent_group);
8164       offspring->SetOpinion(target_group);
8165       JoinGroup(offspring, target_group);
8166       return true;
8167     } else {
8168       // Put the offspring in the parent's group.
8169       assert(parent->HasOpinion());
8170       offspring->SetOpinion(parent_group);
8171       JoinGroup(offspring, parent_group);
8172       return true;
8173     }
8174   // If using standard tolerances
8175   } else if (m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
8176     assert(parent->HasOpinion());
8177     const double tolerance_max = (double) m_world->GetConfig().MAX_TOLERANCE.Get();
8178     const int parent_group = parent->GetOpinion().first;
8179 
8180     // Retrieve the parent's tolerance for its offspring
8181     double parent_tolerance = (double) parent->GetPhenotype().CalcToleranceOffspringOwn();
8182     // Retrieve the parent group's tolerance for offspring
8183     double parent_group_tolerance = (double) CalcGroupToleranceOffspring(parent);
8184 
8185     // Offspring first passes parent vote, then must also pass group vote
8186     // offspring first attempt to join the parent group and if unsuccessful attempt to immigrate
8187     const double prob_parent_allows = parent_tolerance / tolerance_max;
8188     const double prob_group_allows = parent_group_tolerance / tolerance_max;
8189     double rand2 = m_world->GetRandom().GetDouble();
8190     double rand = m_world->GetRandom().GetDouble();
8191 
8192     bool join_parent_group = false;
8193 
8194     if (rand <= prob_parent_allows) {
8195       // If there is nobody else in the group, the offspring gets in
8196       join_parent_group = true;
8197       // If there are others in the group, it's their turn
8198       if (group_list[parent_group].GetSize() > 1) {
8199         if (rand2 <= prob_group_allows) {
8200           // Offspring successfully joins parent's group
8201           join_parent_group = true;
8202         } else join_parent_group = false;
8203       }
8204     }
8205 
8206     if (join_parent_group) {
8207       offspring->SetOpinion(parent_group);
8208       JoinGroup(offspring, parent_group);
8209       // Let the parent know that its offspring was born into its group
8210       parent->GetPhenotype().SetBornParentGroup() = true;
8211       return true;
8212     } else {
8213       // Let the parent know its offspring was not born into its group
8214       parent->GetPhenotype().SetBornParentGroup() = false;
8215     }
8216 
8217     // If the offspring is rejected by the parent group, and there are no other groups, the offspring is doomed
8218     const int num_groups = m_world->GetPopulation().GetResources(ctx).GetSize();
8219     if (!join_parent_group && num_groups == 1) {
8220       return false;
8221     }
8222 
8223     // If the offspring is rejected by the parent group, and there are other groups, the offspring attempts to immigrate
8224     if (!join_parent_group && num_groups > 1) {
8225       // Find another group at random, which is not the parent's
8226       int target_group;
8227       do {
8228         target_group = m_world->GetRandom().GetUInt(num_groups);
8229       } while (target_group == parent_group);
8230 
8231       // If there are no members currently of the target group, offspring has 100% chance of immigrating
8232       if (group_list[target_group].GetSize() == 0) {
8233         offspring->SetOpinion(target_group);
8234         JoinGroup(offspring, target_group);
8235         return true;
8236       } else {
8237         double probability_born_target_group = CalcGroupOddsImmigrants(target_group, -1);
8238 
8239         rand = m_world->GetRandom().GetDouble();
8240         // Calculate if the offspring successfully immigrates
8241         if (rand <= probability_born_target_group) {
8242           // Offspring joins target group
8243           offspring->SetOpinion(target_group);
8244           JoinGroup(offspring, target_group);
8245           return true;
8246         } else {
8247           // Offspring fails to immigrate and is doomed
8248           return false;
8249         }
8250       }
8251     }
8252   }
8253   return false;
8254 }
8255 
8256 // Calculates the average for intra-group tolerance to immigrants
CalcGroupAveImmigrants(int group_id,int mating_type)8257 double cPopulation::CalcGroupAveImmigrants(int group_id, int mating_type)
8258 {
8259   cDoubleSum immigrant_tolerance;
8260   int single_member_tolerance = 0;
8261   for (int index = 0; index < group_list[group_id].GetSize(); index++) {
8262     bool count_org = false;
8263     if (mating_type == -1) count_org = true;
8264     else if (mating_type == 0 && group_list[group_id][index]->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) {
8265       count_org = true;
8266     } else if (mating_type == 1 && group_list[group_id][index]->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) {
8267       count_org = true;
8268     } else if (mating_type == 2 && group_list[group_id][index]->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) {
8269       count_org = true;
8270     }
8271     if (count_org) {
8272       single_member_tolerance = group_list[group_id][index]->GetPhenotype().CalcToleranceImmigrants();
8273       immigrant_tolerance.Add(single_member_tolerance);
8274     }
8275   }
8276   double aveimmigrants = immigrant_tolerance.Average();
8277   return aveimmigrants;
8278 }
8279 
8280 // Calculates the standard deviation for group tolerance to immigrants
CalcGroupSDevImmigrants(int group_id,int mating_type)8281 double cPopulation::CalcGroupSDevImmigrants(int group_id, int mating_type)
8282 {
8283   cDoubleSum immigrant_tolerance;
8284   int single_member_tolerance = 0;
8285   for (int index = 0; index < group_list[group_id].GetSize(); index++) {
8286     bool count_org = false;
8287     if (mating_type == -1) count_org = true;
8288     else if (mating_type == 0 && group_list[group_id][index]->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) {
8289       count_org = true;
8290     } else if (mating_type == 1 && group_list[group_id][index]->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) {
8291       count_org = true;
8292     } else if (mating_type == 2 && group_list[group_id][index]->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) {
8293       count_org = true;
8294     }
8295     if (count_org) {
8296       single_member_tolerance = group_list[group_id][index]->GetPhenotype().CalcToleranceImmigrants();
8297       immigrant_tolerance.Add(single_member_tolerance);
8298     }
8299   }
8300   double sdevimmigrants = immigrant_tolerance.StdDeviation();
8301   return sdevimmigrants;
8302 }
8303 
8304 // Calculates the average for intra-group tolerance to own offspring
CalcGroupAveOwn(int group_id)8305 double cPopulation::CalcGroupAveOwn(int group_id)
8306 {
8307   cDoubleSum own_tolerance;
8308   int single_member_tolerance = 0;
8309   for (int index = 0; index < group_list[group_id].GetSize(); index++) {
8310     single_member_tolerance = group_list[group_id][index]->GetPhenotype().CalcToleranceOffspringOwn();
8311     own_tolerance.Add(single_member_tolerance);
8312   }
8313   double aveown = own_tolerance.Average();
8314   return aveown;
8315 }
8316 
8317 // Calculates the standard deviation for group tolerance to their own offspring
CalcGroupSDevOwn(int group_id)8318 double cPopulation::CalcGroupSDevOwn(int group_id)
8319 {
8320   cDoubleSum own_tolerance;
8321   int single_member_tolerance = 0;
8322   for (int index = 0; index < group_list[group_id].GetSize(); index++) {
8323     single_member_tolerance = group_list[group_id][index]->GetPhenotype().CalcToleranceOffspringOwn();
8324     own_tolerance.Add(single_member_tolerance);
8325   }
8326   double sdevown = own_tolerance.StdDeviation();
8327   return sdevown;
8328 }
8329 
8330 // Calculates the average for intra-group tolerance to other offspring
CalcGroupAveOthers(int group_id)8331 double cPopulation::CalcGroupAveOthers(int group_id)
8332 {
8333   cDoubleSum others_tolerance;
8334   int single_member_tolerance = 0;
8335   for (int index = 0; index < group_list[group_id].GetSize(); index++) {
8336     single_member_tolerance = group_list[group_id][index]->GetPhenotype().CalcToleranceOffspringOthers();
8337     others_tolerance.Add(single_member_tolerance);
8338   }
8339   double aveothers = others_tolerance.Average();
8340   return aveothers;
8341 }
8342 
8343 // Calculates the standard deviation for group tolerance to other group offspring
CalcGroupSDevOthers(int group_id)8344 double cPopulation::CalcGroupSDevOthers(int group_id)
8345 {
8346   cDoubleSum others_tolerance;
8347   int single_member_tolerance = 0;
8348   for (int index = 0; index < group_list[group_id].GetSize(); index++) {
8349     single_member_tolerance = group_list[group_id][index]->GetPhenotype().CalcToleranceOffspringOthers();
8350     others_tolerance.Add(single_member_tolerance);
8351   }
8352   double sdevothers = others_tolerance.StdDeviation();
8353   return sdevothers;
8354 }
8355 
GetGroupIntolerances(int group_id,int tol_num,int mating_type)8356 int& cPopulation::GetGroupIntolerances(int group_id, int tol_num, int mating_type)
8357 {
8358   int& intolerance = m_group_intolerances[group_id][tol_num].second;
8359   if (mating_type == 0) intolerance = m_group_intolerances_females[group_id][tol_num].second;
8360   else if (mating_type == 1) intolerance = m_group_intolerances_males[group_id][tol_num].second;
8361   else if (mating_type == 2) intolerance = m_group_intolerances_juvs[group_id][tol_num].second;
8362   return intolerance;
8363 }
8364 
8365 /*!	Modify current level of the HGT resource.
8366  */
AdjustHGTResource(cAvidaContext & ctx,double delta)8367 void cPopulation::AdjustHGTResource(cAvidaContext& ctx, double delta)
8368 {
8369   if (m_hgt_resid != -1) {
8370     resource_count.Modify(ctx, m_hgt_resid, delta);
8371   }
8372 }
8373 
8374 /*! Mix all organisms in the population.
8375 
8376  This method rearranges the relationship between organisms and cells.  Specifically,
8377  we take all organisms in the population, and assign them to different randomly-selected
8378  cells.
8379 
8380  This isn't really useful in a single population run.  However, a mixing stage is a
8381  key component of biologically-inspired approaches to group selection (ie, Wilson's
8382  and Traulsen's models).
8383 
8384  \warning THIS METHOD CHANGES THE ORGANISM POINTERS OF CELLS.
8385  */
MixPopulation(cAvidaContext & ctx)8386 void cPopulation::MixPopulation(cAvidaContext& ctx)
8387 {
8388   // Get the list of all organism pointers, including nulls:
8389   std::vector<cOrganism*> population(cell_array.GetSize());
8390   for(int i=0; i<cell_array.GetSize(); ++i) {
8391     population[i] = cell_array[i].GetOrganism();
8392   }
8393 
8394   // Shuffle them:
8395   cRandomStdAdaptor adapted_rng(m_world->GetRandom());
8396   std::random_shuffle(population.begin(), population.end(), adapted_rng);
8397 
8398   // Reset the organism pointers of all cells:
8399   for(int i=0; i<cell_array.GetSize(); ++i) {
8400     cell_array[i].RemoveOrganism(ctx);
8401     if (population[i] == 0) {
8402       AdjustSchedule(cell_array[i], cMerit(0));
8403     } else {
8404       cell_array[i].InsertOrganism(population[i], ctx);
8405       AdjustSchedule(cell_array[i], cell_array[i].GetOrganism()->GetPhenotype().GetMerit());
8406     }
8407   }
8408 }
8409 
PlaceAvatar(cOrganism * parent)8410 int cPopulation::PlaceAvatar(cOrganism* parent)
8411 {
8412   int avatar_target_cell = parent->GetOrgInterface().GetAVCellID();
8413   const int avatar_birth = m_world->GetConfig().AVATAR_BIRTH.Get();
8414   if (avatar_birth == 1) avatar_target_cell = m_world->GetRandom().GetUInt(world_x * world_y);
8415   else if (avatar_birth == 2) avatar_target_cell = parent->GetOrgInterface().GetAVFacedCellID();
8416   else if (avatar_birth == 3) {
8417     avatar_target_cell += 1;
8418     if (avatar_target_cell >= world_x * world_y) avatar_target_cell = 0;
8419   }
8420   return avatar_target_cell;
8421 }
8422