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