1 /*
2  *  cEnvironment.cc
3  *  Avida
4  *
5  *  Copyright 1999-2011 Michigan State University. All rights reserved.
6  *  Copyright 1993-2003 California Institute of Technology.
7  *
8  *
9  *  This file is part of Avida.
10  *
11  *  Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
12  *  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
13  *
14  *  Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License along with Avida.
18  *  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "cEnvironment.h"
23 
24 #include "avida/Avida.h"
25 
26 #include "avida/core/Feedback.h"
27 
28 #include "cArgSchema.h"
29 #include "cAvidaContext.h"
30 #include "cContextPhenotype.h"
31 #include "cContextReactionRequisite.h"
32 #include "cEnvReqs.h"
33 #include "cInitFile.h"
34 #include "cOrganism.h"
35 #include "cPhenPlastUtil.h"
36 #include "cPopulation.h"
37 #include "cPopulationCell.h"
38 #include "cRandom.h"
39 #include "cReaction.h"
40 #include "nReaction.h"
41 #include "cReactionProcess.h"
42 #include "cReactionRequisite.h"
43 #include "cReactionResult.h"
44 #include "cResource.h"
45 #include "cStateGrid.h"
46 #include "cStringUtil.h"
47 #include "cTaskEntry.h"
48 #include "cWorld.h"
49 #include "tArray.h"
50 #include "tAutoRelease.h"
51 
52 using namespace Avida;
53 
54 
cEnvironment(cWorld * world)55 cEnvironment::cEnvironment(cWorld* world) : m_world(world) , m_tasklib(world),
56 m_input_size(INPUT_SIZE_DEFAULT), m_output_size(OUTPUT_SIZE_DEFAULT), m_true_rand(false),
57 m_use_specific_inputs(false), m_specific_inputs(), m_mask(0)
58 {
59   mut_rates.Setup(world);
60   if (m_world->GetConfig().DEFAULT_GROUP.Get() != -1) possible_group_ids.insert(m_world->GetConfig().DEFAULT_GROUP.Get());
61 }
62 
~cEnvironment()63 cEnvironment::~cEnvironment()
64 {
65   for (int i = 0; i < m_state_grids.GetSize(); i++) delete m_state_grids[i];
66 }
67 
68 
ParseSetting(cString entry,cString & var_name,cString & var_value,const cString & var_type,Feedback & feedback)69 bool cEnvironment::ParseSetting(cString entry, cString& var_name, cString& var_value, const cString& var_type,
70                                 Feedback& feedback)
71 {
72   // Make sure we have an actual entry to parse.
73   if (entry.GetSize() == 0) {
74     feedback.Error("empty setting to parse in %s", (const char*)var_type);
75     return false;
76   }
77 
78   // Collect the values...
79   var_name = entry.Pop('=');
80   var_value = entry;
81 
82   // Make sure we have both a name and a value...
83   if (var_name.GetSize() == 0) {
84     feedback.Error("no variable povided to set to '%s' in '%s'", (const char*)var_value, (const char*)var_type);
85     return false;
86   }
87 
88   if (var_value.GetSize() == 0) {
89     feedback.Error("no value given for '%s' in %s", (const char*)var_name, (const char*)var_type);
90     return false;
91   }
92 
93   // Make the names case insensitive.
94   var_name.ToLower();
95 
96   return true;
97 }
98 
AssertInputInt(const cString & input,const cString & name,const cString & type,Feedback & feedback)99 bool cEnvironment::AssertInputInt(const cString& input, const cString& name, const cString& type, Feedback& feedback)
100 {
101   if (input.IsNumeric() == false) {
102     feedback.Error("in %s, %s set to non-integer", (const char*)type, (const char*)name);
103     return false;
104   }
105   return true;
106 }
107 
AssertInputDouble(const cString & input,const cString & name,const cString & type,Feedback & feedback)108 bool cEnvironment::AssertInputDouble(const cString& input, const cString& name, const cString& type, Feedback& feedback)
109 {
110   if (input.IsNumber() == false) {
111     feedback.Error("in %s, %s set to non-number", (const char*)type, (const char*)name);
112     return false;
113   }
114   return true;
115 }
116 
AssertInputBool(const cString & input,const cString & name,const cString & type,Feedback & feedback)117 bool cEnvironment::AssertInputBool(const cString& input, const cString& name, const cString& type, Feedback& feedback)
118 {
119   if (input.IsNumber() == false) {
120     feedback.Error("in %s, %s set to non-number", (const char*)type, (const char*)name);
121     return false;
122   }
123   int value = input.AsInt();
124   if ((value != 1) && (value != 0))  {
125     feedback.Error("in %s, %s set to non-bool", (const char*)type, (const char*)name);
126     return false;
127   }
128   return true;
129 }
130 
AssertInputValid(void * input,const cString & name,const cString & type,const cString & value,Feedback & feedback)131 bool cEnvironment::AssertInputValid(void* input, const cString& name, const cString& type, const cString& value,
132                                     Feedback& feedback)
133 {
134   if (input == NULL) {
135     feedback.Error("in %s, '%s' setting of '%s' not found",
136                                   (const char*)type, (const char*)name, (const char*)value);
137     return false;
138   }
139   return true;
140 }
141 
142 
143 
LoadReactionProcess(cReaction * reaction,cString desc,Feedback & feedback)144 bool cEnvironment::LoadReactionProcess(cReaction* reaction, cString desc, Feedback& feedback)
145 {
146   cReactionProcess* new_process = reaction->AddProcess();
147 
148   // Loop through all entries in description.
149   while (desc.GetSize() > 0) {
150     // Entries are divided by colons.
151     cString var_entry = desc.Pop(':');
152     cString var_name;
153     cString var_value;
154     const cString var_type = cStringUtil::Stringf("reaction '%s' process", static_cast<const char*>(reaction->GetName()));
155 
156     // Parse this entry.
157     if (!ParseSetting(var_entry, var_name, var_value, var_type, feedback)) return false;
158 
159     // Now that we know we have a variable name and its value, set it!
160     if (var_name == "resource") {
161       cResource* test_resource = resource_lib.GetResource(var_value);
162       if (!AssertInputValid(test_resource, "resource", var_type, var_value, feedback)) {
163         return false;
164       }
165       new_process->SetResource(test_resource);
166     }
167     else if (var_name == "value") {
168       if (!AssertInputDouble(var_value, "value", var_type, feedback)) return false;
169       new_process->SetValue(var_value.AsDouble());
170     }
171     else if (var_name == "type") {
172       if (var_value=="add") new_process->SetType(nReaction::PROCTYPE_ADD);
173       else if (var_value=="mult") new_process->SetType(nReaction::PROCTYPE_MULT);
174       else if (var_value=="pow") new_process->SetType(nReaction::PROCTYPE_POW);
175       else if (var_value=="lin") new_process->SetType(nReaction::PROCTYPE_LIN);
176       else if (var_value=="energy") new_process->SetType(nReaction::PROCTYPE_ENERGY);
177       else if (var_value=="enzyme") new_process->SetType(nReaction::PROCTYPE_ENZYME);
178       else if (var_value=="exp") new_process->SetType(nReaction::PROCTYPE_EXP);
179       else {
180         feedback.Error("unknown reaction process type '%s' found in '%s'",
181                                       (const char*)var_value, (const char*)reaction->GetName());
182         return false;
183       }
184     }
185     else if (var_name == "max") {
186       if (!AssertInputDouble(var_value, "max", var_type, feedback)) return false;
187       new_process->SetMaxNumber(var_value.AsDouble());
188     }
189     else if (var_name == "min") {
190       if (!AssertInputDouble(var_value, "min", var_type, feedback)) return false;
191       new_process->SetMinNumber(var_value.AsDouble());
192     }
193     else if (var_name == "frac") {
194       if (!AssertInputDouble(var_value, "frac", var_type, feedback)) return false;
195       double in_frac = var_value.AsDouble();
196       if (in_frac > 1.0) in_frac = 1.0;
197       new_process->SetMaxFraction(in_frac);
198     }
199     else if (var_name == "ksubm") {
200       if (!AssertInputDouble(var_value, "ksubm", var_type, feedback)) return false;
201       double in_k_sub_m = var_value.AsDouble();
202       new_process->SetKsubM(in_k_sub_m);
203     }
204     else if (var_name == "product") {
205       cResource* test_resource = resource_lib.GetResource(var_value);
206       if (!AssertInputValid(test_resource, "product", var_type, var_value, feedback)) {
207         return false;
208       }
209       new_process->SetProduct(test_resource);
210     }
211     else if (var_name == "conversion") {
212       if (!AssertInputDouble(var_value, "conversion", var_type, feedback)) return false;
213       new_process->SetConversion(var_value.AsDouble());
214     }
215     else if (var_name == "inst") {
216       new_process->SetInst(var_value);
217     }
218     else if (var_name == "lethal") {
219       if (!AssertInputDouble(var_value, "lethal", var_type, feedback))
220         return false;
221       new_process->SetLethal(var_value.AsDouble());
222     }
223     else if (var_name == "sterilize") {
224       if (!AssertInputBool(var_value, "sterilize", var_type, feedback))
225         return false;
226       new_process->SetSterile(var_value.AsInt());
227     }
228     else if (var_name == "deme") {
229       if (!AssertInputDouble(var_value, "demefrac", var_type, feedback))
230         return false;
231       new_process->SetDemeFraction(var_value.AsDouble());
232     }
233     else if (var_name == "germline") {
234       if (!AssertInputBool(var_value, "germline", var_type, feedback))
235         return false;
236       new_process->SetIsGermline(var_value.AsInt());
237     }
238     else if (var_name == "detect") {
239       cResource* test_resource = resource_lib.GetResource(var_value);
240       if (!AssertInputValid(test_resource, "product", var_type, var_value, feedback)) {
241         return false;
242       }
243       new_process->SetDetect(test_resource);
244     }
245     else if (var_name == "threshold") {
246       if (!AssertInputDouble(var_value, "threshold", var_type, feedback))
247         return false;
248       new_process->SetDetectionThreshold(var_value.AsDouble());
249     }
250     else if (var_name == "detectionerror") {
251       if (!AssertInputDouble(var_value, "detectionerror", var_type, feedback))
252         return false;
253       new_process->SetDetectionError(var_value.AsDouble());
254     }
255     else if (var_name == "string") {
256       new_process->SetMatchString(var_value);
257     }
258     else if (var_name == "depletable") {
259       if (!AssertInputBool(var_value, "depletable", var_type, feedback))
260         return false;
261       new_process->SetDepletable(var_value.AsInt());
262     }
263     else if (var_name == "phenplastbonus") {
264       if (var_value == "nobonus")
265         new_process->SetPhenPlastBonusMethod(NO_BONUS);
266       else if (var_value == "fracbonus")
267         new_process->SetPhenPlastBonusMethod(FRAC_BONUS);
268       else if (var_value == "fullbonus")
269         new_process->SetPhenPlastBonusMethod(FULL_BONUS);
270       else if (var_value == "default")
271         new_process->SetPhenPlastBonusMethod(DEFAULT);
272       else {
273         feedback.Error("invalid setting for phenplastbonus in reaction '%s'", (const char*)reaction->GetName());
274         return false;
275       }
276     }
277     else if ( var_name == "internal") {
278       if (!AssertInputBool(var_value, "internal", var_type, feedback))
279         return false;
280       new_process->SetInternal(var_value.AsInt());
281     }
282     else {
283       feedback.Error("unknown process variable '%s' in reaction '%s'",
284                                     (const char*)var_name, (const char*)reaction->GetName());
285       return false;
286     }
287   }
288 
289   return true;
290 }
291 
LoadReactionRequisite(cReaction * reaction,cString desc,Feedback & feedback)292 bool cEnvironment::LoadReactionRequisite(cReaction* reaction, cString desc, Feedback& feedback)
293 {
294   cReactionRequisite* new_requisite = reaction->AddRequisite();
295 
296   // Loop through all entries in description.
297   while (desc.GetSize() > 0) {
298     // Entries are divided by colons.
299     cString var_entry = desc.Pop(':');
300     cString var_name;
301     cString var_value;
302     const cString var_type = cStringUtil::Stringf("reaction '%s' requisite", static_cast<const char*>(reaction->GetName()));
303 
304     // Parse this entry.
305     if (!ParseSetting(var_entry, var_name, var_value, var_type, feedback)) return false;
306 
307     // Now that we know we have a variable name and its value, set it!
308     if (var_name == "reaction") {
309       cReaction* test_reaction = reaction_lib.GetReaction(var_value);
310       if (!AssertInputValid(test_reaction, "reaction", var_type, var_value, feedback)) {
311         return false;
312       }
313       new_requisite->AddReaction(test_reaction);
314     }
315     else if (var_name == "noreaction") {
316       cReaction* test_reaction = reaction_lib.GetReaction(var_value);
317       if (!AssertInputValid(test_reaction,"noreaction",var_type, var_value, feedback)) {
318         return false;
319       }
320       new_requisite->AddNoReaction(test_reaction);
321     }
322     else if (var_name == "min_count") {
323       if (!AssertInputInt(var_value, "min_count", var_type, feedback)) return false;
324       new_requisite->SetMinTaskCount(var_value.AsInt());
325     }
326     else if (var_name == "max_count") {
327       if (!AssertInputInt(var_value, "max_count", var_type, feedback)) return false;
328       new_requisite->SetMaxTaskCount(var_value.AsInt());
329     }
330     else if (var_name == "reaction_min_count") {
331       if (!AssertInputInt(var_value, "reaction_min_count", var_type, feedback)) return false;
332       new_requisite->SetMinReactionCount(var_value.AsInt());
333     }
334     else if (var_name == "reaction_max_count") {
335       if (!AssertInputInt(var_value, "reaction_max_count", var_type, feedback)) return false;
336       new_requisite->SetMaxReactionCount(var_value.AsInt());
337     }
338     else if (var_name == "divide_only") {
339       if (!AssertInputInt(var_value, "divide_only", var_type, feedback)) return false;
340       new_requisite->SetDivideOnly(var_value.AsInt());
341     }
342     else if (var_name == "min_tot_count") {
343       if (!AssertInputInt(var_value, "min_tot_count", var_type, feedback)) return false;
344       new_requisite->SetMinTotReactionCount(var_value.AsInt());
345     }
346     else if (var_name == "max_tot_count") {
347       if (!AssertInputInt(var_value, "max_tot_count", var_type, feedback)) return false;
348       new_requisite->SetMaxTotReactionCount(var_value.AsInt());
349     }
350     else {
351       feedback.Error("unknown requisite variable '%s' in reaction '%s'",
352                                     (const char*)var_name, (const char*)reaction->GetName());
353       return false;
354     }
355   }
356 
357   return true;
358 }
359 
360 
LoadContextReactionRequisite(cReaction * reaction,cString desc,Feedback & feedback)361 bool cEnvironment::LoadContextReactionRequisite(cReaction* reaction, cString desc, Feedback& feedback)
362 {
363   cContextReactionRequisite* new_requisite = reaction->AddContextRequisite();
364 
365   // Loop through all entries in description.
366   while (desc.GetSize() > 0) {
367     // Entries are divided by colons.
368     cString var_entry = desc.Pop(':');
369     cString var_name;
370     cString var_value;
371     const cString var_type = cStringUtil::Stringf("reaction '%s' requisite", static_cast<const char*>(reaction->GetName()));
372 
373     // Parse this entry.
374     if (!ParseSetting(var_entry, var_name, var_value, var_type, feedback)) return false;
375 
376     // Now that we know we have a variable name and its value, set it!
377     if (var_name == "reaction") {
378       cReaction* test_reaction = reaction_lib.GetReaction(var_value);
379       if (!AssertInputValid(test_reaction, "reaction", var_type, var_value, feedback)) {
380         return false;
381       }
382       new_requisite->AddReaction(test_reaction);
383     }
384     else if (var_name == "noreaction") {
385       cReaction* test_reaction = reaction_lib.GetReaction(var_value);
386       if (!AssertInputValid(test_reaction,"noreaction",var_type, var_value, feedback)) {
387         return false;
388       }
389       new_requisite->AddNoReaction(test_reaction);
390     }
391     else if (var_name == "min_count") {
392       if (!AssertInputInt(var_value, "min_count", var_type, feedback)) return false;
393       new_requisite->SetMinTaskCount(var_value.AsInt());
394     }
395     else if (var_name == "max_count") {
396       if (!AssertInputInt(var_value, "max_count", var_type, feedback)) return false;
397       new_requisite->SetMaxTaskCount(var_value.AsInt());
398     }
399     else if (var_name == "reaction_min_count") {
400       if (!AssertInputInt(var_value, "reaction_min_count", var_type, feedback)) return false;
401       new_requisite->SetMinReactionCount(var_value.AsInt());
402     }
403     else if (var_name == "reaction_max_count") {
404       if (!AssertInputInt(var_value, "reaction_max_count", var_type, feedback)) return false;
405       new_requisite->SetMaxReactionCount(var_value.AsInt());
406     }
407     else if (var_name == "divide_only") {
408       if (!AssertInputInt(var_value, "divide_only", var_type, feedback)) return false;
409       new_requisite->SetDivideOnly(var_value.AsInt());
410     }
411     else if (var_name == "min_tot_count") {
412       if (!AssertInputInt(var_value, "min_tot_count", var_type, feedback)) return false;
413       new_requisite->SetMinTotReactionCount(var_value.AsInt());
414     }
415     else if (var_name == "max_tot_count") {
416       if (!AssertInputInt(var_value, "max_tot_count", var_type, feedback)) return false;
417       new_requisite->SetMaxTotReactionCount(var_value.AsInt());
418     }
419     else {
420       feedback.Error("unknown requisite variable '%s' in reaction '%s'",
421                                     (const char*)var_name, (const char*)reaction->GetName());
422       return false;
423     }
424   }
425 
426   return true;
427 }
428 
429 
430 
LoadResource(cString desc,Feedback & feedback)431 bool cEnvironment::LoadResource(cString desc, Feedback& feedback)
432 {
433   if (desc.GetSize() == 0) {
434     feedback.Warning("resource line with no resources listed");
435     return false;
436   }
437 
438   while (desc.GetSize() > 0) {
439     cString cur_resource = desc.PopWord();
440     const cString name = cur_resource.Pop(':');
441 
442     /* If resource does not already exist create it, however if it already
443      exists (for instance was created as a cell resource) pull it out of
444      the library and modify the existing values */
445 
446     cResource* new_resource;
447     if (! resource_lib.DoesResourceExist(name)) {
448       new_resource = resource_lib.AddResource(name);
449     } else {
450       new_resource = resource_lib.GetResource(name);
451     }
452 
453     while (cur_resource.GetSize() != 0) {
454       cString var_entry = cur_resource.Pop(':');
455       cString var_name;
456       cString var_value;
457       const cString var_type = cStringUtil::Stringf("resource '%s'", static_cast<const char*>(name));
458 
459       // Parse this entry.
460       if (!ParseSetting(var_entry, var_name, var_value, var_type, feedback)) {
461         return false;
462       }
463 
464       if (var_name == "inflow") {
465         if (!AssertInputDouble(var_value, "inflow", var_type, feedback)) return false;
466         new_resource->SetInflow( var_value.AsDouble() );
467       }
468       else if (var_name == "outflow") {
469         if (!AssertInputDouble(var_value, "outflow", var_type, feedback)) return false;
470         new_resource->SetOutflow( var_value.AsDouble() );
471       }
472       else if (var_name == "initial") {
473         if (!AssertInputDouble(var_value, "initial", var_type, feedback)) return false;
474         new_resource->SetInitial( var_value.AsDouble() );
475       }
476       else if (var_name == "geometry") {
477         if (!new_resource->SetGeometry( var_value )) {
478           feedback.Error("in %s, %s unknown geometry", (const char*)var_type, (const char*)var_value);
479           return false;
480         }
481       }
482       else if (var_name == "cells")
483       {
484         tArray<int> cell_list = cStringUtil::ReturnArray(var_value);
485         new_resource->SetCellIdList(cell_list);
486       }
487       else if (var_name == "inflowx1" || var_name == "inflowx") {
488         if (!AssertInputInt(var_value, "inflowX1", var_type, feedback)) return false;
489         new_resource->SetInflowX1( var_value.AsInt() );
490       }
491       else if (var_name == "inflowx2") {
492         if (!AssertInputInt(var_value, "inflowX2", var_type, feedback)) return false;
493         new_resource->SetInflowX2( var_value.AsInt() );
494       }
495       else if (var_name == "inflowy1" || var_name == "inflowy") {
496         if (!AssertInputInt(var_value, "inflowY1", var_type, feedback)) return false;
497         new_resource->SetInflowY1( var_value.AsInt() );
498       }
499       else if (var_name == "inflowy2") {
500         if (!AssertInputInt(var_value, "inflowY2", var_type, feedback)) return false;
501         new_resource->SetInflowY2( var_value.AsInt() );
502       }
503       else if (var_name == "outflowx1" || var_name == "outflowx") {
504         if (!AssertInputInt(var_value, "outflowX1", var_type, feedback)) return false;
505         new_resource->SetOutflowX1( var_value.AsInt() );
506       }
507       else if (var_name == "outflowx2") {
508         if (!AssertInputInt(var_value, "outflowX2", var_type, feedback)) return false;
509         new_resource->SetOutflowX2( var_value.AsInt() );
510       }
511       else if (var_name == "outflowy1" || var_name == "outflowy") {
512         if (!AssertInputInt(var_value, "outflowY1", var_type, feedback)) return false;
513         new_resource->SetOutflowY1( var_value.AsInt() );
514       }
515       else if (var_name == "outflowy2") {
516         if (!AssertInputInt(var_value, "outflowY2", var_type, feedback)) return false;
517         new_resource->SetOutflowY2( var_value.AsInt() );
518       }
519       else if (var_name == "xdiffuse") {
520         if (!AssertInputDouble(var_value, "xdiffuse", var_type, feedback)) return false;
521         new_resource->SetXDiffuse( var_value.AsDouble() );
522       }
523       else if (var_name == "xgravity") {
524         if (!AssertInputDouble(var_value, "xgravity", var_type, feedback)) return false;
525         new_resource->SetXGravity( var_value.AsDouble() );
526       }
527       else if (var_name == "ydiffuse") {
528         if (!AssertInputDouble(var_value, "ydiffuse", var_type, feedback)) return false;
529         new_resource->SetYDiffuse( var_value.AsDouble() );
530       }
531       else if (var_name == "ygravity") {
532         if (!AssertInputDouble(var_value, "ygravity", var_type, feedback)) return false;
533         new_resource->SetYGravity( var_value.AsDouble() );
534       }
535       else if (var_name == "deme") {
536         if (!new_resource->SetDemeResource( var_value )) {
537           feedback.Error("in %s, %s must be true or false", (const char*)var_type, (const char*)var_value);
538           return false;
539         }
540       }
541       else if (var_name == "collectable") {
542         if (!AssertInputBool(var_value, "collectable", var_type, feedback)) return false;
543           new_resource->SetCollectable(var_value.AsInt());
544       }
545       else if (var_name == "energy") {
546         if (!new_resource->SetEnergyResource( var_value )) {
547           feedback.Error("in %s, %s must be true or false", (const char*)var_type, (const char*)var_value);
548           return false;
549         } else if (m_world->GetConfig().ENERGY_ENABLED.Get() == 0) {
550           feedback.Error("energy resources can not be used without the energy model");
551           return false;
552         }
553       }
554       else if (var_name == "hgt") {
555 	// this resource is for HGT -- corresponds to genome fragments present in cells.
556 	if (!AssertInputBool(var_value, "hgt", var_type, feedback)) return false;
557 	new_resource->SetHGTMetabolize(var_value.AsInt());
558       }
559       else {
560         feedback.Error("unknown variable '%s' in resource '%s'", (const char*)var_name, (const char*)name);
561         return false;
562       }
563     }
564 
565     // Now that all geometry, etc. information is known, give the resource an index
566     // within its own type
567     resource_lib.SetResourceIndex(new_resource);
568 
569     // Prevent misconfiguration of HGT:
570 
571     if (new_resource->GetHGTMetabolize() &&
572        ( (new_resource->GetGeometry() != nGeometry::GLOBAL)
573 	 || (new_resource->GetInitial() > 0.0)
574 	 || (new_resource->GetInflow() > 0.0)
575 	 || (new_resource->GetOutflow() > 0.0)
576 	 || (new_resource->GetInflowX1() != -99)
577 	 || (new_resource->GetInflowX2() != -99)
578 	 || (new_resource->GetInflowY1() != -99)
579 	 || (new_resource->GetInflowY2() != -99)
580 	 || (new_resource->GetXDiffuse() != 1.0)
581 	 || (new_resource->GetXGravity() != 0.0)
582 	 || (new_resource->GetYDiffuse() != 1.0)
583 	 || (new_resource->GetYGravity() != 0.0)
584 	 || (new_resource->GetDemeResource() != false))) {
585       feedback.Error("misconfigured HGT resource: %s", (const char*)name);
586       return false;
587     }
588     if (new_resource->GetHGTMetabolize() && !m_world->GetConfig().ENABLE_HGT.Get()) {
589       feedback.Error("resource configured to use HGT, but HGT not enabled");
590       return false;
591     }
592 
593     // If there are valid values for X/Y1's but not for X/Y2's assume that
594     // the user is interested only in one point and set the X/Y2's to the
595     // same value as X/Y1's
596 
597     if (new_resource->GetInflowX1()>-99 && new_resource->GetInflowX2()==-99){
598       new_resource->SetInflowX2(new_resource->GetInflowX1());
599     }
600     if (new_resource->GetInflowY1()>-99 && new_resource->GetInflowY2()==-99){
601       new_resource->SetInflowY2(new_resource->GetInflowY1());
602     }
603     if (new_resource->GetOutflowX1()>-99 && new_resource->GetOutflowX2()==-99) {
604       new_resource->SetOutflowX2(new_resource->GetOutflowX1());
605     }
606     if (new_resource->GetOutflowY1()>-99 && new_resource->GetOutflowY2()==-99) {
607       new_resource->SetOutflowY2(new_resource->GetOutflowY1());
608     }
609   }
610 
611   return true;
612 }
613 
LoadCell(cString desc,Feedback & feedback)614 bool cEnvironment::LoadCell(cString desc, Feedback& feedback)
615 
616 /*****************************************************************************
617  Routine to read in spatial resources loaded in one cell at a time. Syntax:
618 
619  CELL resource_name:cell_list[:options]
620 
621  where options are initial, inflow and outflow
622  *****************************************************************************/
623 
624 {
625   if (desc.GetSize() == 0) {
626     feedback.Warning("CELL line with no resources listed");
627     return false;
628   }
629 
630   cResource* this_resource;
631   while (desc.GetSize() > 0) {
632     cString cur_resource = desc.PopWord();
633     const cString name = cur_resource.Pop(':');
634 
635     /* if this resource has not been already created go ahead and create it and
636      set some default global values */
637 
638     if (! resource_lib.DoesResourceExist(name)) {
639       this_resource = resource_lib.AddResource(name);
640       this_resource->SetInitial(0.0);
641       this_resource->SetInflow(0.0);
642       this_resource->SetOutflow(0.0);
643       this_resource->SetGeometry("GRID");
644       this_resource->SetInflowX1(-99);
645       this_resource->SetInflowX2(-99);
646       this_resource->SetInflowY1(-99);
647       this_resource->SetInflowY2(-99);
648       this_resource->SetOutflowX1(-99);
649       this_resource->SetOutflowX2(-99);
650       this_resource->SetOutflowY1(-99);
651       this_resource->SetOutflowY2(-99);
652       this_resource->SetXDiffuse(0.0);
653       this_resource->SetXGravity(0.0);
654       this_resource->SetYDiffuse(0.0);
655       this_resource->SetYGravity(0.0);
656       this_resource->SetDemeResource("false");
657     } else {
658       this_resource = resource_lib.GetResource(name);
659     }
660     cString cell_list_str = cur_resource.Pop(':');
661     tArray<int> cell_list = cStringUtil::ReturnArray(cell_list_str);
662     double tmp_initial = 0.0;
663     double tmp_inflow = 0.0;
664     double tmp_outflow = 0.0;
665     while (cur_resource.GetSize() != 0) {
666       cString var_entry = cur_resource.Pop(':');
667       cString var_name;
668       cString var_value;
669       const cString var_type =
670       cStringUtil::Stringf("resource '%s'", static_cast<const char*>(name));
671 
672       // Parse this entry.
673       if (!ParseSetting(var_entry, var_name, var_value, var_type, feedback)) {
674         return false;
675       }
676 
677       if (var_name == "inflow") {
678         if (!AssertInputDouble(var_value, "inflow", var_type, feedback)) return false;
679         tmp_inflow = var_value.AsDouble();
680       }
681       else if (var_name == "outflow") {
682         if (!AssertInputDouble(var_value, "outflow", var_type, feedback)) return false;
683         tmp_outflow = var_value.AsDouble();
684       }
685       else if (var_name == "initial") {
686         if (!AssertInputDouble(var_value, "initial", var_type, feedback)) return false;
687         tmp_initial = var_value.AsDouble();
688       }
689       else {
690         feedback.Error("unknown variable '%s' in resource '%s'", (const char*)var_name, (const char*)name);
691         return false;
692       }
693     }
694     for (int i = 0; i < cell_list.GetSize(); i++) {
695       if (cCellResource *CellResourcePtr = this_resource->GetCellResourcePtr(cell_list[i])) {
696         this_resource->UpdateCellResource(CellResourcePtr,tmp_initial, tmp_inflow, tmp_outflow);
697       } else {
698         cCellResource tmp_cell_resource(cell_list[i],tmp_initial, tmp_inflow, tmp_outflow);
699         this_resource->AddCellResource(tmp_cell_resource);
700       }
701     }
702 
703   }
704 
705   return true;
706 }
707 
LoadReaction(cString desc,Feedback & feedback)708 bool cEnvironment::LoadReaction(cString desc, Feedback& feedback)
709 {
710   // Make sure this reaction has a description...
711   if (desc.GetSize() == 0) {
712     feedback.Error("each reaction must include a name and trigger");
713     return false;
714   }
715 
716   // Load in the reaction name
717   const cString name = desc.PopWord();
718   cReaction* new_reaction = reaction_lib.AddReaction(name);
719 
720   // If only a name was present, assume this reaction is a pre-declaration.
721   if (desc.GetSize() == 0) {
722     return true;
723   }
724 
725   // Make sure this reaction hasn't already been loaded with a different
726   // definition.
727   if (new_reaction->GetTask() != NULL) {
728     feedback.Warning("re-defining reaction '%s'", (const char*)name);
729   }
730 
731   // Finish loading in this reaction.
732   cString trigger_info = desc.PopWord();
733   cString trigger = trigger_info.Pop(':');
734 
735   // Load the task trigger
736   cEnvReqs envreqs;
737   cTaskEntry* cur_task = m_tasklib.AddTask(trigger, trigger_info, envreqs, feedback);
738   if (cur_task == NULL) return false;
739   new_reaction->SetTask(cur_task);      // Attack task to reaction.
740 
741   while (desc.GetSize()) {
742     cString desc_entry = desc.PopWord();      // Get the next argument
743     cString entry_type = desc_entry.Pop(':'); // Determine argument type
744     entry_type.ToLower();                     // Make case insensitive.
745 
746     // Determine the type of each argument and process it.
747     if (entry_type == "process") {
748       if (LoadReactionProcess(new_reaction, desc_entry, feedback) == false) {
749         feedback.Error("failed in loading reaction-process...");
750         return false;
751       }
752     }
753     else if (entry_type == "requisite") {
754       if (LoadReactionRequisite(new_reaction, desc_entry, feedback) == false) {
755         feedback.Error("failed in loading reaction-requisite...");
756         return false;
757       }
758     }
759     else if (entry_type == "context_requisite") {
760       if (LoadContextReactionRequisite(new_reaction, desc_entry, feedback) == false) {
761         feedback.Error("failed in loading reaction-requisite...");
762         return false;
763       }
764     }
765     else {
766       feedback.Error("unknown entry type '%s' in reaction '%s'", (const char*)entry_type, (const char*)name);
767       return false;
768     }
769   }
770 
771   // Process the environment requirements of this task
772   if (envreqs.GetMinInputs() > m_input_size) m_input_size = envreqs.GetMinInputs();
773   if (envreqs.GetMinOutputs() > m_output_size) m_output_size = envreqs.GetMinOutputs();
774   if (envreqs.GetTrueRandInputs()) m_true_rand = true;
775 
776   return true;
777 }
778 
LoadGradientResource(cString desc,Feedback & feedback)779 bool cEnvironment::LoadGradientResource(cString desc, Feedback& feedback)
780 {
781   if (desc.GetSize() == 0) {
782     feedback.Error("gradient resource line with no resources listed");
783     return false;
784   }
785 
786   while (desc.GetSize() > 0) {
787     cString cur_resource = desc.PopWord();
788     const cString name = cur_resource.Pop(':');
789 
790     /* If resource does not already exist create it, however if it already
791      exists (for instance was created as a cell resource) return an error*/
792 
793     cResource* new_resource;
794     if (!resource_lib.DoesResourceExist(name)) {
795       new_resource = resource_lib.AddResource(name);
796     } else {
797       new_resource = resource_lib.GetResource(name);
798     }
799 
800     new_resource->SetGeometry("grid");
801     new_resource->SetInitial(0.0);
802     new_resource->SetOutflow(1.0);
803     new_resource->SetXDiffuse(0.0);
804     new_resource->SetYDiffuse(0.0);
805     new_resource->SetXGravity(0.0);
806     new_resource->SetYGravity(0.0);
807     new_resource->SetGradient(true);
808 
809     while (cur_resource.GetSize() != 0) {
810       cString var_entry = cur_resource.Pop(':');
811       cString var_name;
812       cString var_value;
813       const cString var_type = cStringUtil::Stringf("gradient resource '%s'", static_cast<const char*>(name));
814       // Parse this entry.
815       if (!ParseSetting(var_entry, var_name, var_value, var_type, feedback)) {
816         return false;
817       }
818 
819       if (var_name == "peakx") {
820         if (!AssertInputInt(var_value, "peakx", var_type, feedback)) return false;
821         new_resource->SetPeakX( var_value.AsInt() );
822       }
823       else if (var_name == "peaky") {
824         if (!AssertInputInt(var_value, "peaky", var_type, feedback)) return false;
825         new_resource->SetPeakY( var_value.AsInt() );
826       }
827       else if (var_name == "height") {
828         if (!AssertInputInt(var_value, "height", var_type, feedback)) return false;
829         new_resource->SetHeight( var_value.AsInt() );
830       }
831       else if (var_name == "spread") {
832         if (!AssertInputInt(var_value, "spread", var_type, feedback)) return false;
833         new_resource->SetSpread( var_value.AsInt() );
834       }
835       else if (var_name == "plateau") {
836         if (!AssertInputDouble(var_value, "plateau", var_type, feedback)) return false;
837         new_resource->SetPlateau( var_value.AsDouble() );
838       }
839       else if (var_name == "decay") {
840         if (!AssertInputInt(var_value, "decay", var_type, feedback)) return false;
841         new_resource->SetDecay( var_value.AsInt() );
842       }
843       else if (var_name == "max_x") {
844         if (!AssertInputInt(var_value, "max_x", var_type, feedback)) return false;
845         new_resource->SetMaxX( var_value.AsInt() );
846       }
847       else if (var_name == "max_y") {
848         if (!AssertInputInt(var_value, "max_y", var_type, feedback)) return false;
849         new_resource->SetMaxY( var_value.AsInt() );
850       }
851       else if (var_name == "min_x") {
852         if (!AssertInputInt(var_value, "min_x", var_type, feedback)) return false;
853         new_resource->SetMinX( var_value.AsInt() );
854       }
855       else if (var_name == "min_y") {
856         if (!AssertInputInt(var_value, "min_y", var_type, feedback)) return false;
857         new_resource->SetMinY( var_value.AsInt() );
858       }
859       else if (var_name == "move_a_scaler") {
860         if (!AssertInputDouble(var_value, "move_a_scaler", var_type, feedback)) return false;
861         new_resource->SetAscaler( var_value.AsDouble() );
862       }
863       else if (var_name == "updatestep") {
864         if (!AssertInputInt(var_value, "updatestep", var_type, feedback)) return false;
865         new_resource->SetUpdateStep( var_value.AsInt() );
866       }
867       else if (var_name == "halo") {
868         if (!AssertInputInt(var_value, "halo", var_type, feedback)) return false;
869         new_resource->SetHalo( var_value.AsInt() );
870       }
871       else if (var_name == "halo_inner_radius") {
872         if (!AssertInputInt(var_value, "halo_inner_radius", var_type, feedback)) return false;
873         new_resource->SetHaloInnerRadius( var_value.AsInt() );
874       }
875       else if (var_name == "halo_anchor_x") {
876         if (!AssertInputInt(var_value, "halo_halo_anchor_x", var_type, feedback)) return false;
877         new_resource->SetHaloAnchorX( var_value.AsInt() );
878       }
879       else if (var_name == "halo_anchor_y") {
880         if (!AssertInputInt(var_value, "halo_halo_anchor_y", var_type, feedback)) return false;
881         new_resource->SetHaloAnchorY( var_value.AsInt() );
882       }
883       else if (var_name == "move_speed") {
884         if (!AssertInputInt(var_value, "move_speed", var_type, feedback)) return false;
885         new_resource->SetMoveSpeed( var_value.AsInt() );
886       }
887       else if (var_name == "halo_width") {
888         if (!AssertInputInt(var_value, "halo_width", var_type, feedback)) return false;
889         new_resource->SetHaloWidth( var_value.AsInt() );
890       }
891       else if (var_name == "plateau_inflow") {
892         if (!AssertInputDouble(var_value, "plateau_inflow", var_type, feedback)) return false;
893         new_resource->SetPlateauInflow( var_value.AsDouble() );
894       }
895       else if (var_name == "plateau_outflow") {
896         if (!AssertInputDouble(var_value, "plateau_outflow", var_type, feedback)) return false;
897         new_resource->SetPlateauOutflow( var_value.AsDouble() );
898       }
899       else if (var_name == "cone_inflow") {
900         if (!AssertInputDouble(var_value, "cone_inflow", var_type, feedback)) return false;
901         new_resource->SetConeInflow( var_value.AsDouble() );
902       }
903       else if (var_name == "cone_outflow") {
904         if (!AssertInputDouble(var_value, "cone_outflow", var_type, feedback)) return false;
905         new_resource->SetConeOutflow( var_value.AsDouble() );
906       }
907       else if (var_name == "gradient_inflow") {
908         if (!AssertInputDouble(var_value, "gradient_inflow", var_type, feedback)) return false;
909         new_resource->SetGradientInflow( var_value.AsDouble() );
910       }
911       else if (var_name == "initial") {
912         if (!AssertInputDouble(var_value, "initial", var_type, feedback)) return false;
913         new_resource->SetPlatInitial( var_value.AsDouble() );
914       }
915       else if (var_name == "common") {
916         if (!AssertInputInt(var_value, "common", var_type, feedback)) return false;
917         new_resource->SetIsPlateauCommon( var_value.AsInt() );
918       }
919       else if (var_name == "floor") {
920         if (!AssertInputDouble(var_value, "floor", var_type, feedback)) return false;
921         new_resource->SetFloor( var_value.AsDouble() );
922       }
923       else if (var_name == "habitat") {
924         if (!AssertInputInt(var_value, "habitat", var_type, feedback)) return false;
925         new_resource->SetHabitat( var_value.AsInt() );
926         AddHabitat(var_value.AsInt());
927       }
928       else if (var_name == "min_size") {
929         if (!AssertInputInt(var_value, "min_size", var_type, feedback)) return false;
930         new_resource->SetMinSize( var_value.AsInt() );
931       }
932       else if (var_name == "max_size") {
933         if (!AssertInputInt(var_value, "max_size", var_type, feedback)) return false;
934         new_resource->SetMaxSize( var_value.AsInt() );
935       }
936       else if (var_name == "config") {
937         if (!AssertInputInt(var_value, "config", var_type, feedback)) return false;
938         new_resource->SetConfig( var_value.AsInt() );
939       }
940       else if (var_name == "count") {
941         if (!AssertInputInt(var_value, "count", var_type, feedback)) return false;
942         new_resource->SetCount( var_value.AsInt() );
943       }
944       else if (var_name == "resistance") {
945         if (!AssertInputDouble(var_value, "resistance", var_type, feedback)) return false;
946         new_resource->SetResistance( var_value.AsDouble() );
947       }
948       else if (var_name == "threshold") {
949         if (!AssertInputDouble(var_value, "threshold", var_type, feedback)) return false;
950         new_resource->SetThreshold( var_value.AsDouble() );
951       }
952       else if (var_name == "refuge") {
953         if (!AssertInputInt(var_value, "refuge", var_type, feedback)) return false;
954         new_resource->SetRefuge( var_value.AsInt() );
955       }
956       else {
957         feedback.Error("unknown variable '%s' in gradient resource '%s'",
958                                       (const char*)var_name, (const char*)name);
959         return false;
960       }
961     }
962   }
963 
964   return true;
965 }
966 
967 //Dummy Function for Loading Dynamic Resources
LoadDynamicResource(cString desc,Feedback & feedback)968 bool cEnvironment::LoadDynamicResource(cString desc, Feedback& feedback) //JW
969 {
970   if (desc.GetSize() == 0) {
971     feedback.Error("dynamic resource line with no resources listed");
972     return false;
973   }
974 
975   while (desc.GetSize() > 0) {
976     cString cur_resource = desc.PopWord();
977     const cString name = cur_resource.Pop(':');
978 
979     /* If resource does not already exist create it, however if it already
980      exists (for instance was created as a cell resource) return an error*/
981 
982     cResource* new_resource;
983     if (! resource_lib.DoesResourceExist(name)) {
984       new_resource = resource_lib.AddResource(name);
985     } else {
986       feedback.Error("resource %s already exists", (const char*)name);
987       return false;
988     }
989 
990     new_resource->SetGeometry("grid");
991     new_resource->SetInitial(0.0);
992     new_resource->SetOutflow(1.0);
993     new_resource->SetXDiffuse(0.0);
994     new_resource->SetYDiffuse(0.0);
995     new_resource->SetXGravity(0.0);
996     new_resource->SetYGravity(0.0);
997     new_resource->SetDynamicResource(true);
998 
999     while (cur_resource.GetSize() != 0) {
1000       cString var_entry = cur_resource.Pop(':');
1001       cString var_name;
1002       cString var_value;
1003       const cString var_type = cStringUtil::Stringf("dynamic resource '%s'", static_cast<const char*>(name));
1004       // Parse this entry.
1005       if (!ParseSetting(var_entry, var_name, var_value, var_type, feedback)) {
1006         return false;
1007       }
1008 
1009       if (var_name == "peaks") {
1010         if (!AssertInputInt(var_value, "peaks", var_type, feedback)) return false;
1011         /*if(peaks > MAX_PEAKS){
1012          cerr << "Error: peaks of " << name << " exceeds limits of " << MAX_PEAKS << endl;
1013          return false;
1014          }*/
1015         new_resource->SetPeaks( var_value.AsInt() );
1016       }
1017       else if (var_name == "min_height") {
1018         if (!AssertInputDouble(var_value, "min_height", var_type, feedback)) return false;
1019         new_resource->SetMinHeight( var_value.AsDouble() );
1020       }
1021       else if (var_name == "height_range") {
1022         if (!AssertInputDouble(var_value, "height_range", var_type, feedback)) return false;
1023         new_resource->SetHeightRange( var_value.AsDouble() );
1024       }
1025       else if (var_name == "min_radius") {
1026         if (!AssertInputDouble(var_value, "min_radius", var_type, feedback)) return false;
1027         new_resource->SetMinRadius( var_value.AsDouble() );
1028       }
1029       else if (var_name == "radius_range") {
1030         if (!AssertInputDouble(var_value, "radius_range", var_type, feedback)) return false;
1031         new_resource->SetRadiusRange( var_value.AsDouble() );
1032       }
1033       else if (var_name == "ah") {
1034         if (!AssertInputDouble(var_value, "ah", var_type, feedback)) return false;
1035         new_resource->SetAh( var_value.AsDouble() );
1036       }
1037       else if (var_name == "ar") {
1038         if (!AssertInputDouble(var_value, "ar", var_type, feedback)) return false;
1039         new_resource->SetAr( var_value.AsDouble() );
1040       }
1041       else if (var_name == "acx") {
1042         if (!AssertInputDouble(var_value, "acx", var_type, feedback)) return false;
1043         new_resource->SetAcx( var_value.AsDouble() );
1044       }
1045       else if (var_name == "acy") {
1046         if (!AssertInputDouble(var_value, "acy", var_type, feedback)) return false;
1047         new_resource->SetAcy( var_value.AsDouble() );
1048       }
1049       else if (var_name == "hstepscale") {
1050         if (!AssertInputDouble(var_value, "hstepscale", var_type, feedback)) return false;
1051         new_resource->SetHStepscale( var_value.AsDouble() );
1052       }
1053       else if (var_name == "rstepscale") {
1054         if (!AssertInputDouble(var_value, "rstepscale", var_type, feedback)) return false;
1055         new_resource->SetRStepscale( var_value.AsDouble() );
1056       }
1057       else if (var_name == "cstepscalex") {
1058         if (!AssertInputDouble(var_value, "cstepscalex", var_type, feedback)) return false;
1059         new_resource->SetCStepscaleX( var_value.AsDouble() );
1060       }
1061       else if (var_name == "cstepscaley") {
1062         if (!AssertInputDouble(var_value, "cstepscaley", var_type, feedback)) return false;
1063         new_resource->SetCStepscaleY( var_value.AsDouble() );
1064       }
1065       else if (var_name == "hstep") {
1066         if (!AssertInputDouble(var_value, "hstep", var_type, feedback)) return false;
1067         new_resource->SetHStep( var_value.AsDouble() );
1068       }
1069       else if (var_name == "rstep") {
1070         if (!AssertInputDouble(var_value, "rstep", var_type, feedback)) return false;
1071         new_resource->SetRStep( var_value.AsDouble() );
1072       }
1073       else if (var_name == "cstepx") {
1074         if (!AssertInputDouble(var_value, "cstepx", var_type, feedback)) return false;
1075         new_resource->SetCStepX( var_value.AsDouble() );
1076       }
1077       else if (var_name == "cstepy") {
1078         if (!AssertInputDouble(var_value, "cstepy", var_type, feedback)) return false;
1079         new_resource->SetCStepY( var_value.AsDouble() );
1080       }
1081       else if (var_name == "update_dynamic") {
1082         if (!AssertInputInt(var_value, "update_dynamic", var_type, feedback)) return false;
1083         new_resource->SetUpdateDynamic( var_value.AsInt() );
1084       }
1085       else {
1086         feedback.Error("unknown variable '%s' in dynamic resource '%s'",
1087                                       (const char*)var_name, (const char*)name);
1088         return false;
1089       }
1090     }
1091   }
1092 
1093   return true;
1094 }
1095 
LoadStateGrid(cString desc,Feedback & feedback)1096 bool cEnvironment::LoadStateGrid(cString desc, Feedback& feedback)
1097 {
1098   // First component is the name
1099   cString name = desc.Pop(':');
1100 
1101   cArgSchema schema(':','=');
1102 
1103   // Integer Arguments
1104   schema.AddEntry("width", 0, 0, INT_MAX);
1105   schema.AddEntry("height", 1, 0, INT_MAX);
1106   schema.AddEntry("initx", 2, 0, INT_MAX);
1107   schema.AddEntry("inity", 3, 0, INT_MAX);
1108   schema.AddEntry("initfacing", 4, 0, 7);
1109 
1110   // String Arguments
1111   schema.AddEntry("states", 0, cArgSchema::SCHEMA_STRING);
1112   schema.AddEntry("grid", 1, cArgSchema::SCHEMA_STRING);
1113 
1114   // Load the Arguments
1115   tAutoRelease<cArgContainer> args(cArgContainer::Load(desc, schema, feedback));
1116 
1117   // Check for errors loading the arguments
1118   if (args.IsNull()) return false;
1119 
1120   // Extract and validate the arguments
1121   int width = args->GetInt(0);
1122   int height = args->GetInt(1);
1123   int initx = args->GetInt(2);
1124   int inity = args->GetInt(3);
1125   int initfacing = args->GetInt(4);
1126 
1127   if (initx >= width || inity >= height) {
1128     feedback.Error("initx and inity must not exceed (width - 1) and (height - 1)");
1129     return false;
1130   }
1131 
1132 
1133   // Load the states
1134   cString statename;
1135   cString statesensestr;
1136 
1137   tArray<cString> states;
1138   tArray<int> state_sense;
1139   cString statestr = args->GetString(0);
1140   statestr.Trim();
1141   while (statestr.GetSize()) {
1142     statesensestr = statestr.Pop(',');
1143     statename = statesensestr.Pop('=');
1144     statename.Trim();
1145 
1146     // Check for duplicate state definition
1147     for (int i = 0; i < states.GetSize(); i++) {
1148       if (statename == states[i]) {
1149         feedback.Error("duplicate state identifier for state grid %s", (const char*)name);
1150         return false;
1151       }
1152     }
1153 
1154     // Add state to the collection
1155     states.Push(statename);
1156 
1157     // Determing the value returned when sense operations are run on this state
1158     int state_sense_value = states.GetSize(); // Default value is the order in which the states are loaded
1159     if (statesensestr.GetSize()) state_sense_value = statesensestr.AsInt();
1160     state_sense.Push(state_sense_value);
1161   }
1162   if (states.GetSize() == 0) {
1163     feedback.Error("no states defined for state grid %s", (const char*)name);
1164     return false;
1165   }
1166 
1167   // Load the state grid itself
1168   tArray<int> lgrid(width * height);
1169   cString gridstr = args->GetString(1);
1170   int cell = 0;
1171   while (gridstr.GetSize() && cell < lgrid.GetSize()) {
1172     statename = gridstr.Pop(',');
1173     statename.Trim();
1174     bool found = false;
1175     for (int i = 0; i < states.GetSize(); i++) {
1176       if (statename == states[i]) {
1177         lgrid[cell++] = i;
1178         found = true;
1179         break;
1180       }
1181     }
1182     if (!found) {
1183       feedback.Error("state identifier undefined for cell (%d, %d) in state grid %s",
1184                                     (cell / width), (cell % width), (const char*)name);
1185       return false;
1186     }
1187   }
1188   if (cell != lgrid.GetSize() || gridstr.GetSize() > 0) {
1189     feedback.Error("grid definition size mismatch for state grid %s", (const char*)name);
1190     return false;
1191   }
1192 
1193   // Invert row ordering so that it is interpreted as the highest indexed row comes first.  i.e. -
1194   // | a a |
1195   // | b a |
1196   // would be a,a,b,a
1197   tArray<int> grid(lgrid.GetSize());
1198   for (int y = 0; y < height; y++) {
1199     int off = y * width;
1200     int loff = (height - y - 1) * width;
1201     for (int x = 0; x < width; x++) {
1202       grid[off + x] = lgrid[loff + x];
1203     }
1204   }
1205 
1206   m_state_grids.Push(new cStateGrid(name, width, height, initx, inity, initfacing, states, state_sense, grid));
1207   return true;
1208 }
1209 
LoadSetActive(cString desc,Feedback & feedback)1210 bool cEnvironment::LoadSetActive(cString desc, Feedback& feedback)
1211 {
1212   cString item_type = desc.PopWord();
1213   item_type.ToUpper();
1214 
1215   cString item_name = desc.PopWord();
1216 
1217   cString item_active = desc.PopWord();
1218   item_active.ToUpper();
1219 
1220   bool new_active = true;
1221   if (item_active == "0" || item_active == "FALSE") new_active = false;
1222 
1223   if (item_type == "REACTION") {
1224     cReaction* cur_reaction = reaction_lib.GetReaction(item_name);
1225     if (cur_reaction == NULL) {
1226       feedback.Error("unknown REACTION: '%s'", (const char*)item_name);
1227       return false;
1228     }
1229     cur_reaction->SetActive(new_active);
1230   } else if (item_type == "") {
1231     feedback.Notify("format: SET_ACTIVE <type> <name> <new_status=true>");
1232   } else {
1233     feedback.Error("cannot deactivate items of type %s", (const char*)item_type);
1234     return false;
1235   }
1236 
1237   return true;
1238 }
1239 
LoadLine(cString line,Feedback & feedback)1240 bool cEnvironment::LoadLine(cString line, Feedback& feedback)
1241 
1242 /* Routine to read in a line from the enviroment file and hand that line
1243  line to the approprate routine to process it.                         */
1244 {
1245   cString type = line.PopWord();      // Determine type of this entry.
1246   type.ToUpper();                     // Make type case insensitive.
1247 
1248   bool load_ok = true;
1249   if (type == "RESOURCE") load_ok = LoadResource(line, feedback);
1250   else if (type == "REACTION") load_ok = LoadReaction(line, feedback);
1251   else if (type == "SET_ACTIVE") load_ok = LoadSetActive(line, feedback);
1252   else if (type == "CELL") load_ok = LoadCell(line, feedback);
1253   else if (type == "GRID") load_ok = LoadStateGrid(line, feedback);
1254   else if (type == "DYNAMIC_RESOURCE") load_ok = LoadDynamicResource(line, feedback); //JW
1255   else if (type == "GRADIENT_RESOURCE") load_ok = LoadGradientResource(line, feedback);
1256   else {
1257     feedback.Error("unknown environment keyword '%s'", (const char*)type);
1258     return false;
1259   }
1260 
1261   if (load_ok == false) {
1262     feedback.Error("failed in loading '%s'", (const char*)type);
1263     return false;
1264   }
1265 
1266   return true;
1267 }
1268 
Load(const cString & filename,const cString & working_dir,Feedback & feedback)1269 bool cEnvironment::Load(const cString& filename, const cString& working_dir, Feedback& feedback)
1270 {
1271   cInitFile infile(filename, working_dir);
1272   if (!infile.WasOpened()) {
1273     for (int i = 0; i < infile.GetFeedback().GetNumMessages(); i++) {
1274       switch (infile.GetFeedback().GetMessageType(i)) {
1275         case cUserFeedback::UF_ERROR:
1276           feedback.Error(infile.GetFeedback().GetMessage(i));
1277           break;
1278         case cUserFeedback::UF_WARNING:
1279           feedback.Warning(infile.GetFeedback().GetMessage(i));
1280           break;
1281         default:
1282           feedback.Notify(infile.GetFeedback().GetMessage(i));
1283       }
1284     }
1285     feedback.Error("failed to load environment '%s'", (const char*)filename);
1286     return false;
1287   }
1288 
1289   for (int line_id = 0; line_id < infile.GetNumLines(); line_id++) {
1290     // Load the next line from the file.
1291     bool load_ok = LoadLine(infile.GetLine(line_id), feedback);
1292     if (load_ok == false) return false;
1293   }
1294 
1295   // Make sure that all pre-declared reactions have been loaded correctly.
1296   for (int i = 0; i < reaction_lib.GetSize(); i++) {
1297     if (reaction_lib.GetReaction(i)->GetTask() == NULL) {
1298       feedback.Error("pre-declared reaction '%s' never defined",
1299                                     (const char*)reaction_lib.GetReaction(i)->GetName());
1300       return false;
1301     }
1302   }
1303 
1304   return true;
1305 }
1306 
1307 
SetupInputs(cAvidaContext & ctx,tArray<int> & input_array,bool random) const1308 void cEnvironment::SetupInputs(cAvidaContext& ctx, tArray<int>& input_array, bool random) const
1309 {
1310   input_array.Resize(m_input_size);
1311 
1312   if (m_use_specific_inputs)
1313   {
1314     // Specific inputs trump everything
1315     input_array = m_specific_inputs;
1316 
1317     // If a mask has been set, process the inputs with it
1318     if (m_mask) {
1319       for (int i = 0; i < m_input_size; i++) {
1320         input_array[i] = (input_array[i] & ~m_mask) | (m_mask & ctx.GetRandom().GetUInt(1 << 24));
1321       }
1322     }
1323   } else if (random) {
1324     if (m_true_rand) {
1325       for (int i = 0; i < m_input_size; i++) {
1326         input_array[i] = ctx.GetRandom().GetUInt((unsigned int) 1 << 31);
1327       }
1328     } else {
1329       // Set the top 8 bits of the input buffer...
1330       input_array[0] = (15 << 24) + ctx.GetRandom().GetUInt(1 << 24);  // 00001111
1331       input_array[1] = (51 << 24) + ctx.GetRandom().GetUInt(1 << 24);  // 00110011
1332       input_array[2] = (85 << 24) + ctx.GetRandom().GetUInt(1 << 24);  // 01010101
1333 
1334       // And randomize the rest...
1335       for (int i = 3; i < m_input_size; i++) {
1336         input_array[i] = ctx.GetRandom().GetUInt(1 << 24);
1337       }
1338     }
1339   } else {
1340     // We make sure that all combinations of inputs are present.  This is
1341     // done explicitly in the key columns... (0f, 33, and 55)
1342     input_array[0] = 0x0f13149f;  // 00001111 00010011 00010100 10011111
1343     input_array[1] = 0x3308e53e;  // 00110011 00001000 11100101 00111110
1344     input_array[2] = 0x556241eb;  // 01010101 01100010 01000001 11101011
1345 
1346     // Fill out the rest with deterministically bit-shifted versions of the default 3
1347     for (int i = 3; i < m_input_size; i++) {
1348       input_array[i] = input_array[i % 3] << (i / 3);
1349     }
1350   }
1351 }
1352 
1353 
SwapInputs(cAvidaContext & ctx,tArray<int> & src_input_array,tArray<int> & dest_input_array) const1354 void cEnvironment::SwapInputs(cAvidaContext& ctx, tArray<int>& src_input_array, tArray<int>& dest_input_array) const
1355 {
1356   tArray<int> tmp_input_array = dest_input_array;
1357 
1358   dest_input_array = src_input_array;
1359   src_input_array = tmp_input_array;
1360 }
1361 
1362 
TestInput(cReactionResult & result,const tBuffer<int> & inputs,const tBuffer<int> & outputs,const tArray<double> & resource_count) const1363 bool cEnvironment::TestInput(cReactionResult& result, const tBuffer<int>& inputs,
1364                              const tBuffer<int>& outputs, const tArray<double>& resource_count) const
1365 {
1366   // @CAO nothing for the moment...
1367   return false;
1368 }
1369 
1370 
TestOutput(cAvidaContext & ctx,cReactionResult & result,cTaskContext & taskctx,const tArray<int> & task_count,tArray<int> & reaction_count,const tArray<double> & resource_count,const tArray<double> & rbins_count,bool is_parasite,cContextPhenotype * context_phenotype) const1371 bool cEnvironment::TestOutput(cAvidaContext& ctx, cReactionResult& result,
1372                               cTaskContext& taskctx, const tArray<int>& task_count,
1373                               tArray<int>& reaction_count,
1374                               const tArray<double>& resource_count,
1375                               const tArray<double>& rbins_count,
1376                               bool is_parasite, cContextPhenotype* context_phenotype) const
1377 {
1378   //flag to skip processing of parasite tasks
1379   bool skipProcessing = false;
1380 
1381   if (is_parasite && m_world->GetConfig().PARASITE_SKIP_REACTIONS.Get())
1382     skipProcessing = true;
1383 
1384   // Do setup for reaction tests...
1385   m_tasklib.SetupTests(taskctx);
1386 
1387   // Loop through all reactions to see if any have been triggered...
1388   const int num_reactions = reaction_lib.GetSize();
1389   for (int i = 0; i < num_reactions; i++) {
1390     cReaction* cur_reaction = reaction_lib.GetReaction(i);
1391     assert(cur_reaction != NULL);
1392 
1393     // Only use active reactions...
1394     if (cur_reaction->GetActive() == false) continue;
1395 
1396     // Examine the task trigger associated with this reaction
1397     cTaskEntry* cur_task = cur_reaction->GetTask();
1398     assert(cur_task != NULL);
1399 
1400     taskctx.SetTaskEntry(cur_task); // Set task entry in the context, so that tasks can reference task settings
1401     const int task_id = cur_task->GetID();
1402     const int task_cnt = task_count[task_id];
1403     const bool on_divide = taskctx.GetOnDivide();
1404 
1405     // Examine requisites on this reaction
1406     if (TestRequisites(taskctx, cur_reaction, task_cnt, reaction_count, on_divide) == false) {
1407       if (!skipProcessing){
1408         continue;
1409       }
1410     }
1411 
1412     if (context_phenotype != 0) {
1413       tArray<int> blank_tasks;
1414       tArray<int> blank_reactions;
1415       blank_tasks.ResizeClear(task_count.GetSize());
1416       for(int count=0;count<task_count.GetSize();count++) {
1417         blank_tasks[count] = 0;
1418       }
1419       blank_reactions.ResizeClear(this->GetReactionLib().GetSize());
1420       for(int count=0;count<reaction_count.GetSize();count++) {
1421         blank_reactions[count] = 0;
1422       }
1423       context_phenotype->AddTaskCounts(blank_tasks.GetSize(), blank_tasks);
1424       context_phenotype->AddReactionCounts(blank_reactions.GetSize(), blank_reactions);
1425       int context_task_count = context_phenotype->GetTaskCounts()[task_id];
1426       if (TestContextRequisites(cur_reaction, context_task_count, context_phenotype->GetReactionCounts(), on_divide) == false) {
1427         if (!skipProcessing) {  // for those parasites again
1428           continue;
1429         }
1430       }
1431     }
1432 
1433     const double task_quality = m_tasklib.TestOutput(taskctx);
1434     assert(task_quality >= 0.0);
1435 
1436     // If this task wasn't performed, move on to the next one.
1437 
1438     // @MRR task_probability will be either the probability [0,1] for the task or it will
1439     // be -1.0 if the value is not needed for this reaction.
1440     bool force_mark_task = false; //@MRR Some phenplastbonus settings will force a task to be counted even if it isn't demonstrated.
1441     double task_probability = GetTaskProbability(ctx, taskctx, cur_reaction->GetProcesses(), force_mark_task);
1442 
1443     if (task_quality == 0.0 && !force_mark_task) continue;
1444 
1445     // Mark this task as performed...
1446     result.MarkTask(task_id, task_quality, taskctx.GetTaskValue());
1447 
1448     if (!skipProcessing) {
1449       // And let's process it!
1450       DoProcesses(ctx, cur_reaction->GetProcesses(), resource_count, rbins_count,
1451                   task_quality, task_probability, task_cnt, i, result, taskctx);
1452 
1453       if (result.ReactionTriggered(i) == true) {
1454         reaction_count[i]++;
1455         taskctx.GetOrganism()->GetPhenotype().SetFirstReactionCycle(i);
1456         taskctx.GetOrganism()->GetPhenotype().SetFirstReactionExec(i);
1457       }
1458       // Note: the reaction is actually marked as being performed inside DoProcesses.
1459     }
1460   }
1461 
1462   return result.GetActive();
1463 }
1464 
TestRequisites(cTaskContext & taskctx,const cReaction * cur_reaction,int task_count,const tArray<int> & reaction_count,const bool on_divide) const1465 bool cEnvironment::TestRequisites(cTaskContext& taskctx, const cReaction* cur_reaction,
1466                                   int task_count, const tArray<int>& reaction_count, const bool on_divide) const
1467 {
1468   const tList<cReactionRequisite>& req_list = cur_reaction->GetRequisites();
1469   const int num_reqs = req_list.GetSize();
1470 
1471   // If there are no requisites, there is nothing to meet!
1472   // (unless this is a check upon dividing, in which case we want the default to be to not check the task
1473   // and only if the requisite has been added to check it
1474   if (num_reqs == 0) {
1475     return !on_divide;
1476   }
1477 
1478   tLWConstListIterator<cReactionRequisite> req_it(req_list);
1479   for (int i = 0; i < num_reqs; i++) {
1480     // See if this requisite batch can be satisfied.
1481     const cReactionRequisite* cur_req = req_it.Next();
1482     bool satisfied = true;
1483 
1484     if (taskctx.GetOrganism()) {
1485       // Have all reactions been met?
1486       const tArray<int> stolen_reactions = taskctx.GetOrganism()->GetPhenotype().GetStolenReactionCount();
1487       tLWConstListIterator<cReaction> reaction_it(cur_req->GetReactions());
1488       while (reaction_it.Next() != NULL) {
1489         int react_id = reaction_it.Get()->GetID();
1490         if (reaction_count[react_id] == 0 && stolen_reactions[react_id] == 0) {
1491           satisfied = false;
1492           break;
1493         }
1494       }
1495     }
1496     // If being called as a deme reaction..
1497     else {
1498       tLWConstListIterator<cReaction> reaction_it(cur_req->GetReactions());
1499       while (reaction_it.Next() != NULL) {
1500         int react_id = reaction_it.Get()->GetID();
1501         if (reaction_count[react_id] == 0) {
1502           satisfied = false;
1503           break;
1504         }
1505       }
1506     }
1507 
1508     if (satisfied == false) continue;
1509 
1510     // Have all no-reactions been met?
1511     tLWConstListIterator<cReaction> noreaction_it(cur_req->GetNoReactions());
1512     while (noreaction_it.Next() != NULL) {
1513       int react_id = noreaction_it.Get()->GetID();
1514       if (reaction_count[react_id] != 0) {
1515         satisfied = false;
1516         break;
1517       }
1518     }
1519     if (satisfied == false) continue;
1520 
1521     // Have all task counts been met?
1522     if (task_count < cur_req->GetMinTaskCount()) continue;
1523     if (task_count >= cur_req->GetMaxTaskCount()) continue;
1524 
1525     // Have all reaction counts been met?
1526     if (reaction_count[cur_reaction->GetID()] < cur_req->GetMinReactionCount()) continue;
1527     if (reaction_count[cur_reaction->GetID()] >= cur_req->GetMaxReactionCount()) continue;
1528 
1529     // Have all total reaction counts been met?
1530     int tot_reactions = 0;
1531     for (int i=0; i<reaction_count.GetSize(); i++) {
1532       tot_reactions += reaction_count[i];
1533     }
1534     if (tot_reactions < cur_req->GetMinTotReactionCount()) continue;
1535     if (tot_reactions >= cur_req->GetMaxTotReactionCount()) continue;
1536 
1537 
1538     // Have divide task reqs been met?
1539     // If div_type is 0 we only check on IO, if 1 we only check on divide,
1540     // if 2 we check always
1541     int div_type = cur_req->GetDivideOnly();
1542     if (div_type == 1 && !on_divide) continue;
1543     if (div_type == 0 && on_divide) continue;
1544 
1545     return true;
1546   }
1547 
1548   return false;
1549 }
1550 
1551 
TestContextRequisites(const cReaction * cur_reaction,int task_count,const tArray<int> & reaction_count,const bool on_divide) const1552 bool cEnvironment::TestContextRequisites(const cReaction* cur_reaction,
1553 					 int task_count, const tArray<int>& reaction_count,
1554 					 const bool on_divide) const
1555 {
1556   const tList<cContextReactionRequisite>& req_list = cur_reaction->GetContextRequisites();
1557   const int num_reqs = req_list.GetSize();
1558 
1559   // If there are no requisites, there is nothing to meet!
1560   // (unless this is a check upon dividing, in which case we want the default to be to not check the task
1561   // and only if the requisite has been added to check it
1562   if (num_reqs == 0) {
1563     return !on_divide;
1564   }
1565 
1566   tLWConstListIterator<cContextReactionRequisite> req_it(req_list);
1567   for (int i = 0; i < num_reqs; i++) {
1568     // See if this requisite batch can be satisfied.
1569     const cContextReactionRequisite* cur_req = req_it.Next();
1570     bool satisfied = true;
1571 
1572     // Have all reactions been met?
1573     tLWConstListIterator<cReaction> reaction_it(cur_req->GetReactions());
1574     while (reaction_it.Next() != NULL) {
1575       int react_id = reaction_it.Get()->GetID();
1576       if (reaction_count[react_id] == 0) {
1577         satisfied = false;
1578         break;
1579       }
1580     }
1581     if (satisfied == false) continue;
1582 
1583     // Have all no-reactions been met?
1584     tLWConstListIterator<cReaction> noreaction_it(cur_req->GetNoReactions());
1585     while (noreaction_it.Next() != NULL) {
1586       int react_id = noreaction_it.Get()->GetID();
1587       if (reaction_count[react_id] != 0) {
1588         satisfied = false;
1589         break;
1590       }
1591     }
1592     if (satisfied == false) continue;
1593 
1594     // Have all task counts been met?
1595     if (task_count < cur_req->GetMinTaskCount()) continue;
1596     if (task_count >= cur_req->GetMaxTaskCount()) continue;
1597 
1598     // Have all reaction counts been met?
1599     if (reaction_count[cur_reaction->GetID()] < cur_req->GetMinReactionCount()) continue;
1600     if (reaction_count[cur_reaction->GetID()] >= cur_req->GetMaxReactionCount()) continue;
1601 
1602     // Have all total reaction counts been met?
1603     int tot_reactions = 0;
1604     for (int i=0; i<reaction_count.GetSize(); i++) {
1605       tot_reactions += reaction_count[i];
1606     }
1607     if (tot_reactions < cur_req->GetMinTotReactionCount()) continue;
1608     if (tot_reactions >= cur_req->GetMaxTotReactionCount()) continue;
1609 
1610     // Have divide task reqs been met?
1611     // If div_type is 0 we only check on IO, if 1 we only check on divide,
1612     // if 2 we check always
1613     int div_type = cur_req->GetDivideOnly();
1614     if (div_type == 1 && !on_divide) continue;
1615     if (div_type == 0 && on_divide) continue;
1616 
1617     return true;
1618   }
1619 
1620   return false;
1621 }
1622 
1623 
1624 
1625 
GetTaskProbability(cAvidaContext & ctx,cTaskContext & taskctx,const tList<cReactionProcess> & req_proc,bool & force_mark_task) const1626 double cEnvironment::GetTaskProbability(cAvidaContext& ctx, cTaskContext& taskctx,
1627                                         const tList<cReactionProcess>& req_proc, bool& force_mark_task) const
1628 {
1629   force_mark_task = false;
1630   if (ctx.GetTestMode()) { //If we're in test-cpu mode, do not do this.
1631     return -1.0;
1632   }
1633 
1634   double task_prob = -1.0;
1635   tLWConstListIterator<cReactionProcess> proc_it(req_proc);
1636   cReactionProcess* cur_proc;
1637   bool test_plasticity = false;
1638   while ( (cur_proc = proc_it.Next()) != NULL){  //Determine whether or not we need to test for plastcity
1639     ePHENPLAST_BONUS_METHOD pp_meth = cur_proc->GetPhenPlastBonusMethod();
1640     if (pp_meth != DEFAULT){  //DEFAULT doesn't modify bonuses
1641       test_plasticity = true;
1642       if (pp_meth == FULL_BONUS || pp_meth == FRAC_BONUS)  //These will require us to force a task to be marked
1643         force_mark_task = true;
1644     }
1645   }
1646   if (test_plasticity){  //We have to test for plasticity, so try to get it
1647     int task_id = taskctx.GetTaskEntry()->GetID();
1648     task_prob = cPhenPlastUtil::GetTaskProbability(ctx, m_world, taskctx.GetOrganism()->GetBioGroup("genotype"), task_id);
1649   }
1650   force_mark_task = force_mark_task && (task_prob > 0.0);  //If the task isn't demonstrated, we don't need to worry about marking it.
1651   return task_prob;
1652 }
1653 
1654 
1655 
DoProcesses(cAvidaContext & ctx,const tList<cReactionProcess> & process_list,const tArray<double> & resource_count,const tArray<double> & rbins_count,const double task_quality,const double task_probability,const int task_count,const int reaction_id,cReactionResult & result,cTaskContext & taskctx) const1656 void cEnvironment::DoProcesses(cAvidaContext& ctx, const tList<cReactionProcess>& process_list,
1657                                const tArray<double>& resource_count, const tArray<double>& rbins_count,
1658                                const double task_quality, const double task_probability, const int task_count,
1659                                const int reaction_id, cReactionResult& result, cTaskContext& taskctx) const
1660 {
1661   const int num_process = process_list.GetSize();
1662 
1663   tLWConstListIterator<cReactionProcess> process_it(process_list);
1664   for (int i = 0; i < num_process; i++) {
1665     // See if this requisite batch can be satisfied.
1666     const cReactionProcess* cur_process = process_it.Next();
1667     const double max_consumed = cur_process->GetMaxNumber();
1668     const double min_consumed = cur_process->GetMinNumber();
1669 
1670     ePHENPLAST_BONUS_METHOD pp_meth = cur_process->GetPhenPlastBonusMethod();
1671     const double task_plasticity_modifier =
1672     (pp_meth == NO_BONUS && task_probability != 1.0) ? 0.0 :
1673     (pp_meth == FRAC_BONUS) ? task_probability : 1.0;
1674 
1675     //Phenplast full bonus will use a 1.0 task quality
1676     const double local_task_quality =
1677     (pp_meth == FULL_BONUS || pp_meth == FRAC_BONUS) ? 1.0 : task_quality;
1678 
1679     // Determine resource consumption
1680     double consumed = 0.0;
1681     cResource* in_resource = cur_process->GetResource();
1682 
1683     if (in_resource == NULL) {
1684       // Test if infinite resource
1685       consumed = max_consumed * local_task_quality * task_plasticity_modifier;
1686 
1687     } else if (in_resource->GetHGTMetabolize()) {
1688       /* HGT Metabolism
1689        This bit of code is triggered when ENABLE_HGT=1 and a resource has hgt=1.
1690        Here's the idea: Each cell in the environment holds a buffer of genome fragments,
1691        where these fragments are drawn from the remains of organisms that have died.
1692        These remains are a potential source of energy to the current inhabitant of the
1693        cell.  This code metabolizes one of those fragments by pretending that it's just
1694        another resource.  Task quality can be used to control the conversion of fragments
1695        to bonus, but the amount of resource consumed is always equal to the length of the
1696        fragment.
1697        */
1698       int cellid = taskctx.GetOrganism()->GetCellID();
1699       if (cellid != -1) { // can't do this in the test cpu
1700         cPopulationCell& cell = m_world->GetPopulation().GetCell(cellid);
1701         if (cell.CountGenomeFragments() > 0) {
1702           Sequence fragment = cell.PopGenomeFragment();
1703           consumed = local_task_quality * fragment.GetSize();
1704           result.Consume(in_resource->GetID(), fragment.GetSize(), true);
1705           m_world->GetStats().GenomeFragmentMetabolized(taskctx.GetOrganism(), fragment);
1706         }
1707       }
1708       // if we can't metabolize a fragment, stop here.
1709       if (consumed == 0.0) { continue; }
1710     } else {
1711       // Otherwise we're using a finite resource
1712       const int res_id = in_resource->GetID();
1713 
1714       // check to see if the value of this resource was set to 0 for this cell
1715       if (resource_count[res_id]==0) {
1716         consumed = 0;
1717       } else {
1718         assert(resource_count[res_id] >= 0);
1719         assert(result.GetConsumed(res_id) >= 0);
1720         consumed = resource_count[res_id] - result.GetConsumed(res_id);
1721         consumed *= cur_process->GetMaxFraction();
1722         assert(consumed >= 0.0);
1723       }
1724 
1725       bool may_use_rbins = m_world->GetConfig().USE_RESOURCE_BINS.Get();
1726       bool using_rbins = false;  //default: not using resource bins
1727 
1728       if (may_use_rbins) assert(rbins_count.GetSize() > res_id);
1729 
1730       if (cur_process->GetInternal())
1731       {
1732         consumed = rbins_count[res_id];
1733         using_rbins = true;
1734       }
1735       /* Check to see if we do want to use this resource from a bin instead of the environment:
1736        * - Can we use the resource bins?
1737        * - Is there anything in the bin for this resource?
1738        * - Is the usable fraction in the bin strictly greater than the threshold fraction
1739        *   of what we could consume from the outside environment?
1740        */
1741       else if (may_use_rbins && rbins_count[res_id] > 0 &&
1742           (m_world->GetConfig().USE_STORED_FRACTION.Get() * rbins_count[res_id]) >
1743           (m_world->GetConfig().ENV_FRACTION_THRESHOLD.Get() * consumed)
1744           ) {
1745         consumed = m_world->GetConfig().USE_STORED_FRACTION.Get() * rbins_count[res_id];
1746         using_rbins = true;
1747       }
1748 
1749       // Make sure we're not above the maximum consumption.
1750       if (consumed > max_consumed) consumed = max_consumed;
1751 
1752       // Multiply by task_quality
1753       assert((local_task_quality >= 0.0) && (local_task_quality <= 1.0));
1754       consumed = consumed * local_task_quality * task_plasticity_modifier;  // modify consumed based on task quality and plasticity
1755 
1756       // Test if we are below the minimum consumption.
1757       if (consumed < min_consumed) consumed = 0.0;
1758 
1759       // If we don't actually have any resource to consume stop here.
1760       if (consumed == 0.0) continue;
1761 
1762       // Can't consume more resource than what's available.
1763       if (!using_rbins) consumed = std::min(consumed, resource_count[res_id]);
1764       else consumed = std::min(consumed, rbins_count[res_id]);
1765 
1766       // Mark in the results the resource consumed.
1767 			if (cur_process->GetDepletable()) {
1768       	result.Consume(res_id, consumed, !using_rbins);
1769       }
1770     }
1771 
1772     // Mark the reaction as having been performed if we get here.
1773     result.MarkReaction(reaction_id);
1774 
1775     double bonus = consumed * cur_process->GetValue();
1776 
1777     if (!cur_process->GetIsGermline())
1778     {
1779       // normal bonus
1780       double deme_bonus = 0;
1781 
1782       // How much of this bonus belongs to the deme, and how much belongs to the organism?
1783       if (cur_process->GetDemeFraction()) {
1784         deme_bonus = cur_process->GetDemeFraction() * bonus;
1785         bonus = (1-cur_process->GetDemeFraction()) * bonus;
1786       }
1787 
1788       // Take care of the organism's bonus:
1789       switch (cur_process->GetType()) {
1790         case nReaction::PROCTYPE_ADD:
1791           result.AddBonus(bonus, reaction_id);
1792           result.AddDemeBonus(deme_bonus);
1793           break;
1794         case nReaction::PROCTYPE_MULT:
1795           result.MultBonus(bonus);
1796           // @JEB: since deme_bonus is ZERO by default this will cause
1797           // a problem if we unintentionally multiply the deme's bonus
1798           // when we do not make a deme reaction, i.e. deme=0!
1799           // Other cases ADD zero, so they don't necessarily need this check.
1800           if (cur_process->GetDemeFraction()) result.MultDemeBonus(deme_bonus);
1801           break;
1802         case nReaction::PROCTYPE_POW:
1803           result.MultBonus(pow(2.0, bonus));
1804           result.MultDemeBonus(pow(2.0, deme_bonus));
1805           break;
1806         case nReaction::PROCTYPE_LIN:
1807           result.AddBonus(bonus * task_count, reaction_id);
1808           break;
1809         case nReaction::PROCTYPE_ENERGY:
1810           result.AddEnergy(bonus);
1811           assert(deme_bonus == 0.0);
1812           break;
1813         case nReaction::PROCTYPE_ENZYME: //@JEB -- experimental
1814         {
1815 	  const int res_id = in_resource->GetID();
1816           assert(cur_process->GetMaxFraction() != 0);
1817           assert(resource_count[res_id] != 0);
1818           // double reward = cur_process->GetValue() * resource_count[res_id] / (resource_count[res_id] + cur_process->GetMaxFraction());
1819           double reward = cur_process->GetValue() * resource_count[res_id] / (resource_count[res_id] + cur_process->GetKsubM());
1820           result.AddBonus( reward , reaction_id);
1821           break;
1822         }
1823         case nReaction::PROCTYPE_EXP: //@JEB -- experimental
1824         {
1825           // Cumulative rewards are Value * integral (exp (-MaxFraction * TaskCount))
1826           // Evaluate to get stepwise amount to add per task executed.
1827           assert(task_count >= 1);
1828           const double decay = cur_process->GetMaxFraction();
1829           const double value = cur_process->GetValue();
1830           result.AddBonus( value * (1.0 / decay) * ( exp((task_count-1) * decay) - exp(task_count * decay)), reaction_id );
1831           break;
1832         }
1833 
1834         default:
1835           assert(false);  // Should not get here!
1836           break;
1837       }
1838     } else {  // if (cur_process->GetIsGermline())
1839       // @JEB -- this process changes germline propensities, not bonus
1840       switch (cur_process->GetType()) {
1841         case nReaction::PROCTYPE_ADD:
1842           result.AddGermline(bonus);
1843           break;
1844         case nReaction::PROCTYPE_MULT:
1845           result.MultGermline(bonus);
1846           break;
1847         case nReaction::PROCTYPE_POW:
1848           result.MultGermline(pow(2.0, bonus));
1849           break;
1850 
1851         default:
1852           assert(false);  // Should not get here!
1853           break;
1854       }
1855     }
1856 
1857     // Determine detection events
1858     cResource* detected = cur_process->GetDetect();
1859     if (detected != NULL) {
1860       const int detected_id = detected->GetID();
1861       const double real_amount = resource_count[detected_id];
1862       double estimated_amount = ctx.GetRandom().GetRandNormal(real_amount, cur_process->GetDetectionError() * real_amount);
1863       if (estimated_amount < cur_process->GetDetectionThreshold()) {
1864         result.Detect(detected_id, 0.0);
1865       } else {
1866         result.Detect(detected_id, estimated_amount);
1867       }
1868     }
1869 
1870     // Determine byproducts
1871     cResource* product = cur_process->GetProduct();
1872     if (product != NULL) {
1873       int product_id = product->GetID();
1874       double product_size = consumed * cur_process->GetConversion();
1875       if (!cur_process->GetInternal())
1876         result.Produce(product_id, product_size, true);
1877       else
1878         result.Produce(product_id, product_size, false);
1879     }
1880 
1881     // Determine what instructions should be run...
1882     const cString& inst = cur_process->GetInst();
1883     if (inst != "") result.AddInst(inst);
1884 
1885     double prob_lethal = cur_process->GetLethal();
1886     bool lethal = false;
1887 
1888     if (prob_lethal != 0 && prob_lethal != 1) {
1889       // hjg
1890       double x = ctx.GetRandom().GetDouble();
1891       if (x < prob_lethal) {
1892 	lethal = true;
1893       }
1894     }
1895 
1896     result.Lethal(lethal);
1897     result.Sterilize(cur_process->GetSterilize());
1898   }
1899 }
1900 
GetReactionName(int reaction_id) const1901 const cString& cEnvironment::GetReactionName(int reaction_id) const
1902 {
1903   return reaction_lib.GetReaction(reaction_id)->GetName();
1904 }
1905 
GetReactionValue(int reaction_id)1906 double cEnvironment::GetReactionValue(int reaction_id)
1907 {
1908   cReaction* found_reaction = reaction_lib.GetReaction(reaction_id);
1909   if (found_reaction == NULL) return 0.0;
1910   return found_reaction->GetValue();
1911 }
1912 
SetReactionValue(cAvidaContext & ctx,const cString & name,double value)1913 bool cEnvironment::SetReactionValue(cAvidaContext& ctx, const cString& name, double value)
1914 {
1915   const int num_reactions = reaction_lib.GetSize();
1916 
1917   // See if this should be applied to all reactions.
1918   if (name == "ALL") {
1919     // Loop through all reactions to update their values.
1920     for (int i = 0; i < num_reactions; i++) {
1921       cReaction* cur_reaction = reaction_lib.GetReaction(i);
1922       assert(cur_reaction != NULL);
1923       cur_reaction->ModifyValue(value);
1924     }
1925 
1926     return true;
1927   }
1928 
1929   // See if this should be applied to random reactions.
1930   if (name.IsSubstring("RANDOM:", 0)) {
1931     // Determine how many reactions to set.
1932     const int num_set = name.Substring(7, name.GetSize()-7).AsInt();
1933     if (num_set > num_reactions) return false;
1934 
1935     // Choose the reactions.
1936     tArray<int> reaction_ids(num_set);
1937     ctx.GetRandom().Choose(num_reactions, reaction_ids);
1938 
1939     // And set them...
1940     for (int i = 0; i < num_set; i++) {
1941       cReaction* cur_reaction = reaction_lib.GetReaction(reaction_ids[i]);
1942       assert(cur_reaction != NULL);
1943       cur_reaction->ModifyValue(value);
1944     }
1945     return true;
1946   }
1947 
1948   cReaction* found_reaction = reaction_lib.GetReaction(name);
1949   if (found_reaction == NULL) return false;
1950   found_reaction->ModifyValue(value);
1951   return true;
1952 }
1953 
SetReactionValueMult(const cString & name,double value_mult)1954 bool cEnvironment::SetReactionValueMult(const cString& name, double value_mult)
1955 {
1956   cReaction* found_reaction = reaction_lib.GetReaction(name);
1957   if (found_reaction == NULL) return false;
1958   found_reaction->MultiplyValue(value_mult);
1959   return true;
1960 }
1961 
SetReactionInst(const cString & name,cString inst_name)1962 bool cEnvironment::SetReactionInst(const cString& name, cString inst_name)
1963 {
1964   cReaction* found_reaction = reaction_lib.GetReaction(name);
1965   if (found_reaction == NULL) return false;
1966   found_reaction->ModifyInst(inst_name);
1967   return true;
1968 }
1969 
SetReactionMinTaskCount(const cString & name,int min_count)1970 bool cEnvironment::SetReactionMinTaskCount(const cString& name, int min_count)
1971 {
1972   cReaction* found_reaction = reaction_lib.GetReaction(name);
1973   if (found_reaction == NULL) return false;
1974   return found_reaction->SetMinTaskCount( min_count );
1975 }
1976 
SetReactionMaxTaskCount(const cString & name,int max_count)1977 bool cEnvironment::SetReactionMaxTaskCount(const cString& name, int max_count)
1978 {
1979   cReaction* found_reaction = reaction_lib.GetReaction(name);
1980   if (found_reaction == NULL) return false;
1981   return found_reaction->SetMaxTaskCount( max_count );
1982 }
1983 
SetReactionMinCount(const cString & name,int reaction_min_count)1984 bool cEnvironment::SetReactionMinCount(const cString& name, int reaction_min_count)
1985 {
1986   cReaction* found_reaction = reaction_lib.GetReaction(name);
1987   if (found_reaction == NULL) return false;
1988   return found_reaction->SetMinReactionCount( reaction_min_count );
1989 }
1990 
SetReactionMaxCount(const cString & name,int reaction_max_count)1991 bool cEnvironment::SetReactionMaxCount(const cString& name, int reaction_max_count)
1992 {
1993   cReaction* found_reaction = reaction_lib.GetReaction(name);
1994   if (found_reaction == NULL) return false;
1995   return found_reaction->SetMaxReactionCount( reaction_max_count );
1996 }
1997 
SetReactionTask(const cString & name,const cString & task)1998 bool cEnvironment::SetReactionTask(const cString& name, const cString& task)
1999 {
2000   cReaction* found_reaction = reaction_lib.GetReaction(name);
2001   if (found_reaction == NULL) return false;
2002 
2003   for (int i=0; i<m_tasklib.GetSize(); i++)
2004   {
2005     if (m_tasklib.GetTask(i).GetName() == task)
2006     {
2007       found_reaction->SetTask( m_tasklib.GetTaskReference(i) );
2008       return true;
2009     }
2010   }
2011 
2012   return false;
2013 }
2014 
SetResourceInflow(const cString & name,double _inflow)2015 bool cEnvironment::SetResourceInflow(const cString& name, double _inflow )
2016 {
2017   cResource* found_resource = resource_lib.GetResource(name);
2018   if (found_resource == NULL) return false;
2019   found_resource->SetInflow( _inflow );
2020   return true;
2021 }
2022 
SetResourceOutflow(const cString & name,double _outflow)2023 bool cEnvironment::SetResourceOutflow(const cString& name, double _outflow )
2024 {
2025   cResource* found_resource = resource_lib.GetResource(name);
2026   if (found_resource == NULL) return false;
2027   found_resource->SetOutflow( _outflow );
2028   return true;
2029 }
2030 
2031 /*
2032  helper function that checks if this is a valid group id. The ids are specified
2033  in the environment file as tasks.
2034  */
IsGroupID(int test_id)2035 bool cEnvironment::IsGroupID(int test_id)
2036 {
2037   bool val = false;
2038   if (possible_group_ids.find(test_id) != possible_group_ids.end()) {
2039     val = true;
2040   }
2041   return val;
2042 
2043 }
2044 
2045 /*
2046  helper function that checks if this is a valid target id. The ids are specified
2047  in the environment file as tasks.
2048  */
IsTargetID(int test_id)2049 bool cEnvironment::IsTargetID(int test_id)
2050 {
2051   bool val = false;
2052   if (possible_target_ids.find(test_id) != possible_target_ids.end()) {
2053     val = true;
2054   }
2055   return val;
2056 }
2057 
IsHabitat(int test_habitat)2058 bool cEnvironment::IsHabitat(int test_habitat)
2059 {
2060   bool val = false;
2061   if (possible_habitats.find(test_habitat) != possible_habitats.end()) {
2062     val = true;
2063   }
2064   return val;
2065 }
2066