1 /*
2  *  cPopulationCell.cc
3  *  Avida
4  *
5  *  Called "pop_cell.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 "cPopulationCell.h"
24 
25 #include "cDoubleSum.h"
26 #include "nHardware.h"
27 #include "cOrganism.h"
28 #include "cWorld.h"
29 #include "cEnvironment.h"
30 #include "cPopulation.h"
31 #include "cDeme.h"
32 
33 #include <cmath>
34 #include <iterator>
35 
36 using namespace std;
37 
38 
cPopulationCell(const cPopulationCell & in_cell)39 cPopulationCell::cPopulationCell(const cPopulationCell& in_cell)
40 : m_world(in_cell.m_world)
41 , m_organism(in_cell.m_organism)
42 , m_hardware(in_cell.m_hardware)
43 , m_inputs(in_cell.m_inputs)
44 , m_cell_id(in_cell.m_cell_id)
45 , m_deme_id(in_cell.m_deme_id)
46 , m_cell_data(in_cell.m_cell_data)
47 , m_spec_state(in_cell.m_spec_state)
48 , can_input(false)
49 , can_output(false)
50 , m_hgt(0)
51 {
52   // Copy the mutation rates into a new structure
53   m_mut_rates = new cMutationRates(*in_cell.m_mut_rates);
54 
55   // Copy the connection list
56   tConstListIterator<cPopulationCell> conn_it(in_cell.m_connections);
57   cPopulationCell* test_cell;
58   while ((test_cell = const_cast<cPopulationCell*>(conn_it.Next()))) m_connections.PushRear(test_cell);
59 
60 	// copy the hgt information, if needed.
61 	if(in_cell.m_hgt) {
62 		InitHGTSupport();
63 		*m_hgt = *in_cell.m_hgt;
64 	}
65 }
66 
operator =(const cPopulationCell & in_cell)67 void cPopulationCell::operator=(const cPopulationCell& in_cell)
68 {
69 	if(this != &in_cell) {
70 		m_world = in_cell.m_world;
71 		m_organism = in_cell.m_organism;
72 		m_hardware = in_cell.m_hardware;
73 		m_inputs = in_cell.m_inputs;
74 		m_cell_id = in_cell.m_cell_id;
75 		m_deme_id = in_cell.m_deme_id;
76 		m_cell_data = in_cell.m_cell_data;
77 		m_spec_state = in_cell.m_spec_state;
78         can_input = in_cell.can_input;
79         can_output = in_cell.can_output;
80 
81 		// Copy the mutation rates, constructing the structure as necessary
82 		if (m_mut_rates == NULL)
83 			m_mut_rates = new cMutationRates(*in_cell.m_mut_rates);
84 		else
85 			m_mut_rates->Copy(*in_cell.m_mut_rates);
86 
87 		// Copy the connection list
88 		tConstListIterator<cPopulationCell> conn_it(in_cell.m_connections);
89 		cPopulationCell* test_cell;
90 		while ((test_cell = const_cast<cPopulationCell*>(conn_it.Next()))) m_connections.PushRear(test_cell);
91 
92 		// copy hgt information, if needed.
93 		delete m_hgt;
94 		m_hgt = 0;
95 		if(in_cell.m_hgt) {
96 			InitHGTSupport();
97 			*m_hgt = *in_cell.m_hgt;
98 		}
99 	}
100 }
101 
Setup(cWorld * world,int in_id,const cMutationRates & in_rates,int x,int y)102 void cPopulationCell::Setup(cWorld* world, int in_id, const cMutationRates& in_rates, int x, int y)
103 {
104   m_world = world;
105   m_cell_id = in_id;
106   m_x = x;
107   m_y = y;
108   m_deme_id = -1;
109   m_cell_data.contents = 0;
110   m_cell_data.org_id = -1;
111   m_cell_data.update = -1;
112   m_cell_data.territory = -1;
113   m_spec_state = 0;
114 
115   if (m_mut_rates == NULL)
116     m_mut_rates = new cMutationRates(in_rates);
117   else
118     m_mut_rates->Copy(in_rates);
119 }
120 
Rotate(cPopulationCell & new_facing)121 void cPopulationCell::Rotate(cPopulationCell& new_facing)
122 {
123   // @CAO Note, this breaks avida if new_facing is not in connection_list
124 
125   //@AWC if this cell contains a migrant then we assume new_facing is not in the connection list and bail out ...
126   if(IsMigrant()){
127     UnsetMigrant(); //@AWC -- unset the migrant flag for the next time this cell is used
128     return;
129   }
130 
131 #ifdef DEBUG
132   int scan_count = 0;
133 #endif
134   while (m_connections.GetFirst() != &new_facing) {
135     m_connections.CircNext();
136 #ifdef DEBUG
137     assert(++scan_count < m_connections.GetSize());
138 #endif
139   }
140 }
141 
142 /*! This method recursively builds a set of cells that neighbor this cell, out to
143  the given depth.  The set must be passed in by-reference, as calls to this method
144  must share a common set of already-visited cells.
145  */
GetNeighboringCells(std::set<cPopulationCell * > & cell_set,int depth) const146 void cPopulationCell::GetNeighboringCells(std::set<cPopulationCell*>& cell_set, int depth) const {
147 	typedef std::set<cPopulationCell*> cell_set_t;
148 
149   // For each cell in our connection list...
150   tConstListIterator<cPopulationCell> i(m_connections);
151   while(!i.AtEnd()) {
152 		// store the cell pointer, and check to see if we've already visited that cell...
153     cPopulationCell* cell = i.Next();
154 		assert(cell != 0); // cells should never be null.
155 		std::pair<cell_set_t::iterator, bool> ins = cell_set.insert(cell);
156 		// and if so, recurse to it...
157 		if(ins.second && (depth > 1)) {
158 			cell->GetNeighboringCells(cell_set, depth-1);
159 		}
160 	}
161 }
162 
163 /*! Recursively build a set of occupied cells that neighbor this one, out to the given depth.
164 */
GetOccupiedNeighboringCells(std::set<cPopulationCell * > & occupied_cell_set,int depth) const165 void cPopulationCell::GetOccupiedNeighboringCells(std::set<cPopulationCell*>& occupied_cell_set, int depth) const {
166 	// we'll do this the easy way, and just filter the neighbor set.
167 	std::set<cPopulationCell*> cell_set;
168 	GetNeighboringCells(cell_set, depth);
169 	for(std::set<cPopulationCell*>::iterator i=cell_set.begin(); i!=cell_set.end(); ++i) {
170 		if((*i)->IsOccupied()) {
171 			occupied_cell_set.insert(*i);
172 		}
173 	}
174 }
175 
GetOccupiedNeighboringCells(Apto::Array<cPopulationCell * > & occupied_cells) const176 void cPopulationCell::GetOccupiedNeighboringCells(Apto::Array<cPopulationCell*>& occupied_cells) const
177 {
178   occupied_cells.Resize(m_connections.GetSize());
179   int occupied_count = 0;
180 
181   tLWConstListIterator<cPopulationCell> i(m_connections);
182   while(!i.AtEnd()) {
183     cPopulationCell* cell = i.Next();
184 		assert(cell); // cells should never be null.
185     if (cell->IsOccupied()) occupied_cells[occupied_count++] = cell;
186   }
187 
188   occupied_cells.Resize(occupied_count);
189 }
190 
191 
192 /*! These values are chosen so as to make loops on the facing 'easy'.
193  111 = NE
194  101 = E
195  100 = SE
196  000 = S
197  001 = SW
198  011 = W
199  010 = NW
200  110 = N
201 
202  Facing is determined by the relative positions of this cell and the cell that
203  is currently faced. Note that we cannot differentiate between directions on a 2x2
204  torus.
205  */
GetFacing()206 int cPopulationCell::GetFacing()
207 {
208   // This whole function is a hack.
209 	cPopulationCell* faced = ConnectionList().GetFirst();
210 
211 	int x=0,y=0,lr=0,du=0;
212 	faced->GetPosition(x,y);
213 
214 	if((x==m_x-1) || (x>m_x+1))
215 		lr = -1; //left
216 	else if((x==m_x+1) || (x<m_x-1))
217 		lr = 1; //right
218 
219 	if((y==m_y-1) || (y>m_y+1))
220 		du = -1; //up
221 	else if((y==m_y+1) || (y<m_y-1))
222 		du = 1; //down
223 
224 	// This is hackish.
225 	// If you change these return values then the directional send tasks, like sent-north, need to be updated.
226 	if(lr==0 && du==-1) return 0; //N
227 	else if(lr==-1 && du==-1) return 1; //NW
228 	else if(lr==-1 && du==0) return 3; //W
229 	else if(lr==-1 && du==1) return 2; //SW
230 	else if(lr==0 && du==1) return 6; //S
231 	else if(lr==1 && du==1) return 7; //SE
232 	else if(lr==1 && du==0) return 5; //E
233 	else if(lr==1 && du==-1) return 4; //NE
234 
235 	assert(false);
236 
237   return 0;
238 }
239 
GetFacedDir()240 int cPopulationCell::GetFacedDir()
241 {
242   const int facing = GetFacing();
243   int faced_dir = 0;
244   if (facing == 0) faced_dir = 0;          //N
245   else if (facing == 1) faced_dir = 7;    //NW
246   else if (facing == 3) faced_dir = 6;    //W
247   else if (facing == 2) faced_dir = 5;    //SW
248   else if (facing == 6) faced_dir = 4;     //S
249   else if (facing == 7) faced_dir = 3;     //SE
250   else if (facing == 5) faced_dir = 2;     //E
251   else if (facing == 4) faced_dir = 1;     //NE
252   return faced_dir;
253 
254 }
ResetInputs(cAvidaContext & ctx)255 void cPopulationCell::ResetInputs(cAvidaContext& ctx)
256 {
257   m_world->GetEnvironment().SetupInputs(ctx, m_inputs);
258 }
259 
260 
InsertOrganism(cOrganism * new_org,cAvidaContext & ctx)261 void cPopulationCell::InsertOrganism(cOrganism* new_org, cAvidaContext& ctx)
262 {
263   assert(new_org != NULL);
264   assert(m_organism == NULL);
265 
266   // Adjust this cell's attributes to account for the new organism.
267   m_organism = new_org;
268   m_hardware = &new_org->GetHardware();
269   m_world->GetStats().AddSpeculativeWaste(m_spec_state);
270   m_spec_state = 0;
271 
272   // Adjust the organism's attributes to match this cell.
273   m_organism->GetOrgInterface().SetCellID(m_cell_id);
274   m_organism->GetOrgInterface().SetDemeID(m_deme_id);
275 
276   // If this organism is new, set the previously-seen cell id
277   if(m_organism->GetOrgInterface().GetPrevSeenCellID() == -1) {
278     m_organism->GetOrgInterface().SetPrevSeenCellID(m_cell_id);
279   }
280 
281   if(m_world->GetConfig().ENERGY_ENABLED.Get() == 1 && m_world->GetConfig().FRAC_ENERGY_TRANSFER.Get() > 0.0) {
282     // uptake all the cells energy
283     double uptake_energy = UptakeCellEnergy(1.0, ctx);
284     if(uptake_energy != 0.0) {
285       // update energy and merit
286       cPhenotype& phenotype = m_organism->GetPhenotype();
287       phenotype.ReduceEnergy(-1.0 * uptake_energy);
288       phenotype.SetMerit(cMerit(phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy() * phenotype.GetEnergyUsageRatio())));
289     }
290   }
291 }
292 
RemoveOrganism(cAvidaContext & ctx)293 cOrganism * cPopulationCell::RemoveOrganism(cAvidaContext& ctx)
294 {
295   if (m_organism == NULL) return NULL;   // Nothing to do!
296 
297   // For the moment, the cell doesn't keep track of much...
298   cOrganism * out_organism = m_organism;
299   if(m_world->GetConfig().ENERGY_ENABLED.Get() == 1 && m_world->GetConfig().FRAC_ENERGY_TRANSFER.Get() > 0.0
300 		 && m_world->GetConfig().FRAC_ENERGY_DECAY_AT_DEME_BIRTH.Get() != 1.0) { // hack
301     m_world->GetPopulation().GetDeme(m_deme_id).GiveBackCellEnergy(m_cell_id, m_organism->GetPhenotype().GetStoredEnergy() * m_world->GetConfig().FRAC_ENERGY_TRANSFER.Get(), ctx);
302   }
303   m_organism = NULL;
304   m_hardware = NULL;
305   return out_organism;
306 }
307 
UptakeCellEnergy(double frac_to_uptake,cAvidaContext & ctx)308 double cPopulationCell::UptakeCellEnergy(double frac_to_uptake, cAvidaContext& ctx) {
309   assert(0.0 <= frac_to_uptake);
310   assert(frac_to_uptake <= 1.0);
311 
312   double cell_energy = m_world->GetPopulation().GetDeme(m_deme_id).GetAndClearCellEnergy(m_cell_id, ctx);
313   double uptakeAmount = cell_energy * frac_to_uptake;
314   cell_energy -= uptakeAmount;
315   m_world->GetPopulation().GetDeme(m_deme_id).GiveBackCellEnergy(m_cell_id, cell_energy, ctx);
316   return uptakeAmount;
317 }
318 
319 
320 // -------- Avatar support --------
321 /* In the avatar system, each cell contains an array of organism pointers to tie the cell
322  * back to all organisms with avatars in that cell. Each organism then contains a list
323  * (in cPopulationInterface) of all it's avatars and the cell for each avatar.
324  * Currently there are two supported avatar types, input and output,
325  * which are also used as predators and prey, respectively.
326  */
327 
328 // Adds an organism to the cell's input avatars, then keeps the list mixed by swapping the new avatar into a random position in the array
AddInputAV(cOrganism * org)329 void cPopulationCell::AddInputAV(cOrganism* org)
330 {
331   m_av_inputs.Push(org);
332   // Swaps the added avatar into a random position in the array
333   int loc = m_world->GetRandom().GetUInt(0, m_av_inputs.GetSize());
334   cOrganism* exist_org = m_av_inputs[loc];
335   m_av_inputs.Swap(loc, m_av_inputs.GetSize() - 1);
336   exist_org->SetAVInIndex(m_av_inputs.GetSize() - 1);
337   org->SetAVInIndex(loc);
338 }
339 
340 // Adds an organism to the cell's output avatars, then keeps the list mixed by swapping the new avatar into a random position in the array
AddOutputAV(cOrganism * org)341 void cPopulationCell::AddOutputAV(cOrganism* org)
342 {
343   m_av_outputs.Push(org);
344   // Swaps the added avatar into a random position in the array
345   int loc = m_world->GetRandom().GetUInt(0, m_av_outputs.GetSize());
346   cOrganism* exist_org = m_av_outputs[loc];
347   m_av_outputs.Swap(loc, m_av_outputs.GetSize() - 1);
348   exist_org->SetAVOutIndex(m_av_outputs.GetSize() - 1);
349   org->SetAVOutIndex(loc);
350 }
351 
352 // Removes the organism from the cell's input avatars (predator)
RemoveInputAV(cOrganism * org)353 void cPopulationCell::RemoveInputAV(cOrganism* org)
354 {
355   assert(HasInputAV());
356   assert(m_av_inputs[org->GetAVInIndex()] == org);
357   unsigned int last = GetNumAVInputs() - 1;
358   cOrganism* exist_org = m_av_inputs[last];
359   exist_org->SetAVInIndex(org->GetAVInIndex());
360   m_av_inputs.Swap(org->GetAVInIndex(), last);
361   m_av_inputs.Pop();
362 }
363 
364 // Removes the organism from the cell's output avatars (prey)
RemoveOutputAV(cOrganism * org)365 void cPopulationCell::RemoveOutputAV(cOrganism* org)
366 {
367   assert(HasOutputAV());
368   assert(m_av_outputs[org->GetAVOutIndex()] == org);
369   unsigned int last = GetNumAVOutputs() - 1;
370   cOrganism* exist_org = m_av_outputs[last];
371   exist_org->SetAVOutIndex(org->GetAVOutIndex());
372   m_av_outputs.Swap(org->GetAVOutIndex(), last);
373   m_av_outputs.Pop();
374 }
375 
376 // Returns whether a cell has an output AV that the org will be able to receive messages from.
HasOutputAV(cOrganism * org)377 bool cPopulationCell::HasOutputAV(cOrganism* org)
378 {
379   // No output avatars
380   if (!HasOutputAV()) return false;
381   // If org can talk to itself, any avatar in the cell works
382   if (m_world->GetConfig().SELF_COMMUNICATION.Get()) return true;
383 
384   // If no self-messaging, is there an output avatar for another organism in the cell
385   for (int i = 0; i < GetNumAVOutputs(); i++) {
386     if (m_av_outputs[i] != org) {
387       return true;
388     }
389   }
390   return false;
391 }
392 
393 // Randomly returns an avatar from the cell, all avatars equally likely
394 //********** DO NOT CALL FROM VIEWER OR DATA COLLECTION, DOING SO WILL AFFECT RESULTS DURING RUN **********
GetRandAV() const395 cOrganism* cPopulationCell::GetRandAV() const
396 {
397   if (HasAV()) {
398     int rand = m_world->GetRandom().GetUInt(0, GetNumAV());
399     if (rand < GetNumAVInputs()) {
400       return m_av_inputs[rand];
401     }
402     else {
403       return m_av_outputs[rand - GetNumAVInputs()];
404     }
405   }
406   return NULL;
407 }
408 
409 // Returns the first predator (input) avatar, which should be random as the list is mixed whenever a new avatar is added
GetRandPredAV() const410 cOrganism* cPopulationCell::GetRandPredAV() const
411 {
412   if (HasInputAV()) {
413     return m_av_inputs[0];
414   }
415   return NULL;
416 }
417 
418 // Returns the first prey (output) avatar, which should be random as the list is mixed whenever a new avatar is added
GetRandPreyAV() const419 cOrganism* cPopulationCell::GetRandPreyAV() const
420 {
421   if (HasOutputAV()) {
422     return m_av_outputs[0];
423   }
424   return NULL;
425 }
426 
427 // Returns all input avatars (organisms) contained in the cell
GetCellInputAVs()428 tArray<cOrganism*> cPopulationCell::GetCellInputAVs()
429 {
430   assert(HasInputAV());
431   tArray<cOrganism*> avatar_inputs;
432   avatar_inputs.Resize(GetNumAVInputs());
433   for (int i = 0; i < GetNumAVInputs(); i++) {
434     avatar_inputs[i] = m_av_inputs[i];
435   }
436   return avatar_inputs;
437 }
438 
439 // Returns all output avatars (organisms) contained in the cell
GetCellOutputAVs()440 tArray<cOrganism*> cPopulationCell::GetCellOutputAVs()
441 {
442   assert(HasOutputAV());
443   tArray<cOrganism*> avatar_outputs;
444   avatar_outputs.Resize(GetNumAVOutputs());
445   for (int i = 0; i < GetNumAVOutputs(); i++) {
446     avatar_outputs[i] = m_av_outputs[i];
447   }
448   return avatar_outputs;
449 }
450 
451 // Returns all avatars (organisms) contained in the cell
GetCellAVs()452 tArray<cOrganism*> cPopulationCell::GetCellAVs()
453 {
454   assert(HasAV());
455   tArray<cOrganism*> avatars;
456   const int num_outputs = GetNumAVOutputs();
457   avatars.Resize(GetNumAV());
458   for (int i = 0; i < GetNumAVOutputs(); i++) {
459     avatars[i] = m_av_outputs[i];
460   }
461   for (int i = 0; i < GetNumAVInputs(); i++) {
462     avatars[i + num_outputs] = m_av_inputs[i];
463   }
464   return avatars;
465 }
466 
467 
468 
469 /*! Diffuse genome fragments from this cell to its neighbors.
470 
471  NOTE: This method is for OUTGOING diffusion only.
472 
473  There are many possible ways in which genome fragments could be diffused.  We'll
474  put in the framework to support those other mechanisms, but we're not going to
475  worry about this until we need it.  Not terribly interested in recreating an
476  artificial chemistry here...
477  */
DiffuseGenomeFragments()478 void cPopulationCell::DiffuseGenomeFragments() {
479 	InitHGTSupport();
480 
481 	switch(m_world->GetConfig().HGT_DIFFUSION_METHOD.Get()) {
482 			case 0: { // none
483 				break;
484 			}
485 			default: {
486 				m_world->GetDriver().RaiseFatalException(-1, "Unrecognized diffusion type in cPopulationCell::DiffuseGenomeFragments().");
487 			}
488 	}
489 }
490 
491 /*! Add fragments from the passed-in genome to the HGT fragments contained in this cell.
492 
493  Split the passed-in genome into fragments according to a normal distribution specified
494  by HGT_FRAGMENT_SIZE_MEAN and HGT_FRAGMENT_SIZE_VARIANCE.  These fragments are added
495  to this cell's fragment list.
496 
497  As a safety measure, we also remove old fragments to conserve memory.  Specifically, we
498  remove old fragments until at most HGT_MAX_FRAGMENTS_PER_CELL fragments remain.
499  */
AddGenomeFragments(cAvidaContext & ctx,const Sequence & genome)500 void cPopulationCell::AddGenomeFragments(cAvidaContext& ctx, const Sequence& genome) {
501 	assert(genome.GetSize()>0); // oh, sweet sanity.
502 	InitHGTSupport();
503 
504 	m_world->GetPopulation().AdjustHGTResource(ctx, genome.GetSize());
505 
506 
507 	cGenomeUtil::RandomSplit(ctx,
508 													 m_world->GetConfig().HGT_FRAGMENT_SIZE_MEAN.Get(),
509 													 m_world->GetConfig().HGT_FRAGMENT_SIZE_VARIANCE.Get(),
510 													 genome,
511 													 m_hgt->fragments);
512 
513 	// pop off the front of this cell's buffer until we have <= HGT_MAX_FRAGMENTS_PER_CELL.
514 	while(m_hgt->fragments.size()>(unsigned int)m_world->GetConfig().HGT_MAX_FRAGMENTS_PER_CELL.Get()) {
515 		m_world->GetPopulation().AdjustHGTResource(ctx, -m_hgt->fragments.front().GetSize());
516 		m_hgt->fragments.pop_front();
517 	}
518 }
519 
520 /*! Retrieve the number of genome fragments currently found in this cell.
521  */
CountGenomeFragments() const522 unsigned int cPopulationCell::CountGenomeFragments() const {
523 	if(IsHGTInitialized()) {
524 		return m_hgt->fragments.size();
525 	} else {
526 		return 0;
527 	}
528 }
529 
530 /*! Remove and return a random genome fragment.
531  */
PopGenomeFragment()532 Sequence cPopulationCell::PopGenomeFragment() {
533 	assert(m_hgt!=0);
534 	fragment_list_type::iterator i = m_hgt->fragments.begin();
535 	std::advance(i, m_world->GetRandom().GetUInt(0, m_hgt->fragments.size()));
536 	Sequence tmp = *i;
537 	m_hgt->fragments.erase(i);
538 	return tmp;
539 }
540 
541 /*! Retrieve the list of fragments from this cell.
542  */
GetFragments()543 cPopulationCell::fragment_list_type& cPopulationCell::GetFragments() {
544 	InitHGTSupport();
545 	return m_hgt->fragments;
546 }
547 
548 /*!	Clear all fragments from this cell, adjust resources as required.
549  */
ClearFragments(cAvidaContext & ctx)550 void cPopulationCell::ClearFragments(cAvidaContext& ctx) {
551 	InitHGTSupport();
552 	for(fragment_list_type::iterator i=m_hgt->fragments.begin(); i!=m_hgt->fragments.end(); ++i) {
553 		m_world->GetPopulation().AdjustHGTResource(ctx, -i->GetSize());
554 	}
555 	m_hgt->fragments.clear();
556 }
557 
SetCellData(int data,int org_id)558 void cPopulationCell::SetCellData(int data, int org_id)
559 {
560   m_cell_data.contents = data;
561   m_cell_data.org_id = org_id;
562   m_cell_data.update = m_world->GetStats().GetUpdate();
563   if (m_organism != NULL) {
564     if (m_organism->HasOpinion()) {
565       m_cell_data.territory = m_organism->GetOpinion().first;
566     }
567     m_cell_data.forager = m_organism->GetForageTarget();
568   }
569 }
570 
ClearCellData()571 void cPopulationCell::ClearCellData()
572 {
573   m_cell_data.contents = 0;
574   m_cell_data.org_id = -1;
575   m_cell_data.update = -1;
576   m_cell_data.territory = -1;
577   m_cell_data.forager = -99;
578 }
579 
UpdateCellDataExpired()580 void cPopulationCell::UpdateCellDataExpired()
581 {
582   const int expiration = m_world->GetConfig().MARKING_EXPIRE_DATE.Get();
583   const int update = m_world->GetStats().GetUpdate();
584   const int ud_marked = m_cell_data.update;
585   // update only if marked, can expire, and enough time has passed
586   if (ud_marked != -1 && expiration != -1 && (expiration < (update - ud_marked))) ClearCellData();
587 }
588