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