[Avida-SVN] r3049 - in branches/movement: documentation source/main

welsberr at myxo.css.msu.edu welsberr at myxo.css.msu.edu
Mon Dec 15 13:13:27 PST 2008


Author: welsberr
Date: 2008-12-15 16:13:27 -0500 (Mon, 15 Dec 2008)
New Revision: 3049

Modified:
   branches/movement/documentation/environment.html
   branches/movement/source/main/cEnvironment.cc
   branches/movement/source/main/cEnvironment.h
Log:
Added ResourcePeak to cEnvironment

Modified: branches/movement/documentation/environment.html
===================================================================
--- branches/movement/documentation/environment.html	2008-12-15 16:56:07 UTC (rev 3048)
+++ branches/movement/documentation/environment.html	2008-12-15 21:13:27 UTC (rev 3049)
@@ -21,8 +21,8 @@
 This is the setup file for the task/resource system in Avida.
 </p>
 <p>
-Five main keywords are used in this file, RESOURCE, REACTION, CELL, MUTATION, 
-and SET_ACTIVE.  Their
+Six main keywords are used in this file, RESOURCE, REACTION, CELL, MUTATION,
+RESOURCEPEAK, and SET_ACTIVE.  Their
 formats are:
 </p>
 <pre>
@@ -30,6 +30,7 @@
   <a href="#REACTION">REACTION</a>  reaction_name  task  [process:...]  [requisite:...]
   <a href="#CELL">CELL</a> resource_name:cell_list[:flow]
   <a href="#MUTATION">MUTATION</a> name trigger scope type rate
+  <a href="#RESOURCEPEAK">RESOURCEPEAK</a> resource_name[:options]
   <a href="#SET_ACTIVE">SET_ACTIVE</a> type name new_status(default=true)
 </pre>
 
@@ -850,5 +851,120 @@
 <hr />
 <p><a href="index.html">Return to the Index</a></p>
 
+<h3>RESOURCEPEAK Command</h3>
+<p>
+Allows user to compactly specify a spatially distributed peak in a resource.
+</p>
+<p>
+The syntax for the ResourcePeak command is:
+</p>
+  <pre><a name="RESOURCEPEAK">RESOURCEPEAK</a> resource_name[:options]</pre>
+
+<blockquote> 
+<p>
+Where <code>resource_name</code> is a unique name of the resource.
+This name should be used by the <code>REACTION</code> to define which
+resource is consumed/created by a reaction. This command sets all
+relevant properties of all grid cells, and thus will nullify any
+previous <code>CELL</code> commands for the resource specified.
+</p>
+<p>
+Where <code>options</code> is a colon delimited list of factors that
+modify the resource. The following chart specifies these options.
+</p>
+<p>
+ResourcePeak can define two regimes of linearly decreasing
+resources. The peak itself is defined by grid cell coordinates. Inflow
+is defined for this peak, for the minimum inflow at the maximally
+distant grid cell, and an intermediate inflow at a specified distance
+from the peak. This defines a circular region around the peak with
+higher resource inflow, and the remainder of the grid gets a linearly
+decreasing amount of inflow of the resource as distance increases from
+the peak.
+</p>
+<p>
+This environment command sets properties for every cell in the
+grid. The user should be aware that this will require much more memory
+space than a global resource. As a practical matter, resource
+gradients in the range of [0..1] should have the reaction set to use
+"pow" as the type.
+</p>
+</blockquote>
+<div align="center">
+<p>&nbsp;</p>
+<h3>Table 1: <span>ResourcePeak Options</span></h3>
+<table border="1" cellpadding="2">
+<tr>
+  <th>Argument</th>
+  <th>Description</th>
+  <th>Default</th>
+</tr>
+<tr>
+  <td class="resall">peakx</td>
+  <td>The X coordinate of the resource peak</td>
+  <td>1/2 of "world_x" or middle of the ordinate</td>
+</tr>
+<tr>
+  <td class="resall">peaky</td>
+  <td>
+    The Y coordinate of the resource peak
+  </td>
+  <td>
+    1/2 of "world_y" or middle of the abscissa
+  </td>
+</tr>
+<tr>
+  <td class="resall">initres</td>
+  <td>
+    The initial abundance of the resource in the population at the
+    start of an experiment. The initial amount is spread evenly to
+    each cell in the world grid.
+  </td>
+  <td>1.0</td>
+</tr>
+<tr>
+  <td class="resall">spread</td>
+  <td>
+    The <i>radius</i> in grid cell units of the region centered on the
+    resource peak where a higher resource inflow is maintained.
+  </td>
+  <td>8.0</td>
+</tr>
+<tr>
+  <td class="resall">maxflow</td>
+  <td>
+    The resource inflow rate at the resource peak.
+  </td>
+  <td>0.2</td>
+</tr>
+<tr>
+  <td class="resall">minflow</td>
+  <td>
+    The resource inflow that a grid cell at a distance from the
+    resource peak equal to that of a diagonal across the grid would
+    receive.
+  </td>
+  <td>0.001</td>
+</tr>
+<tr>
+  <td class="resall">joinflow</td>
+  <td>
+    The resource inflow at the point of change between the local peak
+    resource and the global gradient.
+  </td>
+  <td>maxflow * 0.333333</td>
+</tr>
+<tr>
+  <td class="resall">outflow</td>
+  <td>
+    The global rate of outflow from all cells in the grid.
+  </td>
+  <td>0.5</td>
+</tr>
+</table>
+
+<hr />
+<p><a href="index.html">Return to the Index</a></p>
+
 </body>
 </html>

Modified: branches/movement/source/main/cEnvironment.cc
===================================================================
--- branches/movement/source/main/cEnvironment.cc	2008-12-15 16:56:07 UTC (rev 3048)
+++ branches/movement/source/main/cEnvironment.cc	2008-12-15 21:13:27 UTC (rev 3049)
@@ -548,6 +548,203 @@
   return true;
 }
 
+// @WRE: environment method to set up a resource peak
+bool cEnvironment::LoadResourcePeak(cString desc)
+/*****************************************************************************
+
+   RESOURCEPEAK resource_name:peakx=nn:peaky=nn:spread=nn.nn:initres=nn.nn:minflow=nn.nn:maxflow=nn.nn:outflow:nn.nn:joinflow=nn.nn
+
+   allows a resource peak to be specified in the configuration.
+   There are a bunch of parameters, but it is less work than setting it up by 
+   specifying each CELL in the environment file.
+
+   peakx, peaky : the coordinates in the grid where the peak of the spatial
+     resource is located
+   spread : The distance from the peak where a higher resource gradient is
+     in effect
+   initres : the initial amount of resource in each cell
+   minflow, maxflow : the minimum and maximum inflow values. Highest at the 
+     peak, linearly decreasing in two ranges: within the "spread" value, and
+     from "spread" to the edges of the grid
+   joinflow : the amount of inflow at distance "spread"
+   outflow : proportion of resource that exits each cell when updated 
+
+   ASCII representation of a resource peak on a 7x7 grid, peak at [3,3]:
+
+   . . . , . . .
+   . + + + + + .
+   . + * * * + .
+   , + * @ * + ,
+   . + * * * + .
+   . + + + + + .
+   . . . , . . .
+
+ *****************************************************************************/
+{
+  // Define some variables
+  const int world_x = m_world->GetConfig().WORLD_X.Get();
+  const int world_y = m_world->GetConfig().WORLD_Y.Get();
+
+  // Set of defaults for values
+  int tmp_peakx = world_x / 2; 
+  int tmp_peaky = world_y / 2;
+  double tmp_initres = 1.0; // Initial resource amount
+  double tmp_spread = 8.0;       // grid unit radius from peak inflow to joinflow
+  double tmp_maxflow = 0.2; // peak inflow
+  double tmp_minflow = 0.001; //  minimum inflow
+  double tmp_joinflow = tmp_maxflow * 0.33333333; // inflow at change between local peak and global gradient
+  double tmp_outflow = 0.5; //       : outflow from cell
+  int gx = 0;
+  int gy = 0; // : coordinates of current grid cell
+
+  // Echo the input string
+  cout << "LoadResourcePeak: " << desc << endl;
+
+  // Parsing the input
+  cResource* this_resource;
+  while (desc.GetSize() > 0) {
+    cString cur_resource = desc.PopWord();
+    const cString resname = cur_resource.Pop(':');
+
+    cout << "..PopWord: " << cur_resource << "; ..Pop':': " << resname <<  endl;
+
+    /* if this resource has not been already created go ahead and create it and
+       set some default global values */
+    if (! resource_lib.DoesResourceExist(resname)) {
+      this_resource = resource_lib.AddResource(resname);
+      this_resource->SetInitial(0.0);
+      this_resource->SetInflow(0.0);
+      this_resource->SetOutflow(0.0);
+      this_resource->SetGeometry("GRID");
+      this_resource->SetInflowX1(-99);
+      this_resource->SetInflowX2(-99);
+      this_resource->SetInflowY1(-99);
+      this_resource->SetInflowY2(-99);
+      this_resource->SetOutflowX1(-99);
+      this_resource->SetOutflowX2(-99);
+      this_resource->SetOutflowY1(-99);
+      this_resource->SetOutflowY2(-99);
+      this_resource->SetXDiffuse(0.0);
+      this_resource->SetXGravity(0.0);
+      this_resource->SetYDiffuse(0.0);
+      this_resource->SetYGravity(0.0);
+      this_resource->SetDemeResource("false");
+    } else {
+      this_resource = resource_lib.GetResource(resname);
+    }
+
+    while (cur_resource.GetSize() != 0) {
+      cString var_entry = cur_resource.Pop(':');
+      cString var_name;
+      cString var_value;
+      const cString var_type = 
+        cStringUtil::Stringf("resource '%s'", static_cast<const char*>(resname));
+      
+      // Parse this entry.
+      if (!ParseSetting(var_entry, var_name, var_value, var_type)) {
+        return false;
+      }
+      
+      // Got the parts for this option, now recognize it
+      if (var_name == "peakx") {
+	cout << "..peakx recognized" << endl;
+	if (!AssertInputInt(var_value, "peakx", var_type)) return false;
+	tmp_peakx = var_value.AsInt();
+	if ((0 > tmp_peakx) || (world_x < tmp_peakx)) return false;  // Sanity check on input value
+	cout << "..peakx = " << tmp_peakx << endl;
+      }
+      else if (var_name == "peaky") {
+	cout << "..peaky recognized" << endl;
+	if (!AssertInputInt(var_value, "peaky", var_type)) return false;
+	tmp_peaky = var_value.AsInt();
+	if ((0 > tmp_peaky) || (world_y < tmp_peaky)) return false;  // Sanity check on input value
+	cout << "..peaky = " << tmp_peaky << endl;
+      }
+      else if (var_name == "initres") {
+	cout << "..initres recognized" << endl;
+	if (!AssertInputDouble(var_value, "initres", var_type)) return false;
+        tmp_initres = var_value.AsDouble();
+	cout << "..initres = " << tmp_initres << endl;
+      }
+      else if (var_name == "spread") {
+	cout << "..spread recognized" << endl;
+	if (!AssertInputDouble(var_value, "spread", var_type)) return false;
+        tmp_spread = var_value.AsDouble();
+	cout << "..spread = " << tmp_spread << endl;
+      }
+      else if (var_name == "maxflow") {
+	cout << "..maxflow recognized" << endl;
+	if (!AssertInputDouble(var_value, "maxflow", var_type)) return false;
+        tmp_maxflow = var_value.AsDouble();
+	cout << "..maxflow = " << tmp_maxflow << endl;
+      }
+      else if (var_name == "minflow") {
+	cout << "..minflow recognized" << endl;
+	if (!AssertInputDouble(var_value, "minflow", var_type)) return false;
+        tmp_minflow = var_value.AsDouble();
+	cout << "..minflow = " << tmp_minflow << endl;
+      }
+      else if (var_name == "joinflow") {
+	cout << "..joinflow recognized" << endl;
+	if (!AssertInputDouble(var_value, "joinflow", var_type)) return false;
+        tmp_joinflow = var_value.AsDouble();
+	cout << "..joinflow = " << tmp_joinflow << endl;
+      }
+      else if (var_name == "outflow") {
+	cout << "..outflow recognized" << endl;
+	if (!AssertInputDouble(var_value, "outflow", var_type)) return false;
+        tmp_outflow = var_value.AsDouble();
+	cout << "..outflow = " << tmp_outflow << endl;
+      }
+      else {
+        cerr << "Error: Unknown variable '" << var_name
+        << "' in resource '" << resname << "'" << endl;
+        return false;
+      }
+    }
+    desc = cur_resource;
+  }
+
+  // The parsing of parameters is now done. Time to set up the cells individually.
+
+  // @WRE: First, clear out previous spatial resource definitions
+  // this_resource->ClearCellResourceList(); // No such method now. I thnk BB had such a method at one point.
+  // Find max distance; take that as diagonal across world grid
+  double d1 = EuclideanDistance2D(0,0,world_x,world_y);
+
+  // Variables to hold cell X and Y coordinates
+  int cx = 0;
+  int cy = 0;
+  double thisdistance = 0.0;
+  double thisinflow = 0.0;
+
+  // @WRE: Now, go over all cells and set them according to parameters
+  for (int i=0; i < (world_x * world_y); i++) {
+    // Determine coordinates for this cell
+    cx = i % world_x;
+    cy = i / world_x;
+
+    // Calculate distance from cell to peak inflow cell
+    thisdistance = EuclideanDistance2D(tmp_peakx,tmp_peaky,cx,cy);
+    // Calculate inflow amount conditionally based on distance
+    if (thisdistance <= tmp_spread) { // Local ramp to peak resource inflow
+      thisinflow = LinMap(thisdistance,0.0,tmp_spread,tmp_maxflow,tmp_joinflow);
+    } else { // Global ramp to joinflow
+      thisinflow = LinMap(thisdistance,0.0,d1,tmp_joinflow,tmp_minflow);
+    }
+
+    cout << "..cell xy=[" << cx << "," << cy <<  "] initres=" << 
+      tmp_initres << " cell inflow=" << thisinflow << " cell outflow=" << 
+      tmp_outflow << endl;
+
+    cCellResource tmp_cell_resource(i,tmp_initres,
+				    thisinflow, tmp_outflow);
+    this_resource->AddCellResource(tmp_cell_resource);
+  }
+
+  return true;
+}
+
 bool cEnvironment::LoadReaction(cString desc)
 {
   // Make sure this reaction has a description...
@@ -765,6 +962,7 @@
   else if (type == "MUTATION") load_ok = LoadMutation(line);
   else if (type == "SET_ACTIVE") load_ok = LoadSetActive(line);
   else if (type == "CELL") load_ok = LoadCell(line);
+  else if (type == "RESOURCEPEAK") load_ok = LoadResourcePeak(line);
   else {
     cerr << "Error: Unknown environment keyword '" << type << "." << endl;
     return false;
@@ -1006,7 +1204,7 @@
     } else {
       // Otherwise we're using a finite resource      
       const int res_id = in_resource->GetID();
-      
+
       assert(resource_count[res_id] >= 0);
       assert(result.GetConsumed(res_id) >= 0);
       consumed = resource_count[res_id] - result.GetConsumed(res_id);
@@ -1304,3 +1502,33 @@
   return true;
 }
 
+// @WRE: helper method to allow easy linear interpolation 
+// Given a domain interval [dlow..dhigh] and a corresponding range
+// interval [rlow..rhigh], and a value in the domain, dy, return the
+// linearly interpolated range value for dy. Note that dy need not be
+// in the interval [dlow..dhigh].
+double cEnvironment::LinMap(double dy, double dlow, double dhigh, double rlow, double rhigh)
+{
+  double ry;
+
+  if (dlow != dhigh) {
+    ry = (dy - dlow) * ((rhigh - rlow) / (dhigh - dlow)) + rlow;
+  } else {
+    ry = 0.0;
+  }
+  return ry;
+}
+
+// @WRE: helper method to get euclidean distances from grid coordinates
+// Given points [x1,y1] and [x2,y2], return the Euclidean distance between
+// them.
+double cEnvironment::EuclideanDistance2D(int x1, int y1, int x2, int y2)
+{
+  double ed = 0.0;
+  int xs = abs(x1 - x2);
+  int ys = abs(y1 - y2);
+
+  ed = sqrt((xs * xs) + (ys * ys));
+
+  return ed;
+}

Modified: branches/movement/source/main/cEnvironment.h
===================================================================
--- branches/movement/source/main/cEnvironment.h	2008-12-15 16:56:07 UTC (rev 3048)
+++ branches/movement/source/main/cEnvironment.h	2008-12-15 21:13:27 UTC (rev 3049)
@@ -107,6 +107,8 @@
   bool LoadCell(cString desc);
   bool LoadReaction(cString desc);
   bool LoadMutation(cString desc);
+  // @WRE: Add environment option to define a spatial resource peak
+  bool LoadResourcePeak(cString desc);
 
   bool LoadSetActive(cString desc);
 
@@ -170,6 +172,9 @@
   bool SetResourceInflow(const cString& name, double _inflow );
   bool SetResourceOutflow(const cString& name, double _outflow );
   
+  // @WRE: helper methods for resource peak method
+  double LinMap(double dy, double dlow, double dhigh, double rlow, double rhigh);
+  double EuclideanDistance2D(int x1, int y1, int x2, int y2);
 };
 
 




More information about the Avida-cvs mailing list