1 /*
2  *  cSpatialResCount.cc
3  *  Avida
4  *
5  *  Called "spatial_res_count.cc" prior to 12/5/05.
6  *  Copyright 1999-2011 Michigan State University. All rights reserved.
7  *  Copyright 1993-2001 California Institute of Technology.
8  *
9  *
10  *  This file is part of Avida.
11  *
12  *  Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
13  *  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
14  *
15  *  Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public License along with Avida.
19  *  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "cSpatialResCount.h"
23 
24 #include "AvidaTools.h"
25 #include "nGeometry.h"
26 
27 #include <cmath>
28 
29 using namespace std;
30 using namespace AvidaTools;
31 
32 /* Setup a single spatial resource with known flows */
33 
cSpatialResCount(int inworld_x,int inworld_y,int ingeometry,double inxdiffuse,double inydiffuse,double inxgravity,double inygravity)34 cSpatialResCount::cSpatialResCount(int inworld_x, int inworld_y, int ingeometry, double inxdiffuse, double inydiffuse,
35                                    double inxgravity, double inygravity)
36 : grid(inworld_x * inworld_y), m_initial(0.0), m_modified(false)
37 {
38   int i;
39 
40   xdiffuse = inxdiffuse;
41   ydiffuse = inydiffuse;
42   xgravity = inxgravity;
43   ygravity = inygravity;
44   world_x = inworld_x;
45   world_y = inworld_y;
46   geometry = ingeometry;
47   num_cells = world_x * world_y;
48   for (i = 0; i < GetSize(); i++) {
49     cSpatialCountElem tmpelem;
50     grid[i] = tmpelem;
51   }
52   SetPointers();
53 }
54 
55 /* Setup a single spatial resource using default flow amounts  */
56 
cSpatialResCount(int inworld_x,int inworld_y,int ingeometry)57 cSpatialResCount::cSpatialResCount(int inworld_x, int inworld_y, int ingeometry)
58 : grid(inworld_x * inworld_y), m_initial(0.0), m_modified(false)
59 {
60   int i;
61 
62   xdiffuse = 1.0;
63   ydiffuse = 1.0;
64   xgravity = 0.0;
65   ygravity = 0.0;
66   world_x = inworld_x;
67   world_y = inworld_y;
68   geometry = ingeometry;
69   num_cells = world_x * world_y;
70   for (i = 0; i < GetSize(); i++) {
71     cSpatialCountElem tmpelem;
72     grid[i] = tmpelem;
73    }
74    SetPointers();
75 }
76 
cSpatialResCount()77 cSpatialResCount::cSpatialResCount() : m_initial(0.0), xdiffuse(1.0), ydiffuse(1.0), xgravity(0.0), ygravity(0.0), m_modified(false)
78 {
79   geometry = nGeometry::GLOBAL;
80 }
81 
~cSpatialResCount()82 cSpatialResCount::~cSpatialResCount() { ; }
83 
84 
ResizeClear(int inworld_x,int inworld_y,int ingeometry)85 void cSpatialResCount::ResizeClear(int inworld_x, int inworld_y, int ingeometry)
86 {
87   int i;
88 
89   grid.ResizeClear(inworld_x * inworld_y);
90   world_x = inworld_x;
91   world_y = inworld_y;
92   geometry = ingeometry;
93   num_cells = world_x * world_y;
94   for (i = 0; i < GetSize(); i++) {
95     cSpatialCountElem tmpelem;
96     grid[i] = tmpelem;
97    }
98    SetPointers();
99 }
100 
SetPointers()101 void cSpatialResCount::SetPointers()
102 {
103   /* Pointer 0 will point to the cell above and to the left the current cell
104      and will go clockwise around the cell.                               */
105 
106   int     i,ii;
107   double  SQRT2 = sqrt(2.0);
108 
109   /* First treat all cells like they are in a torus */
110 
111   for (i = 0; i < GetSize(); i++) {
112     grid[i].SetPtr(0 ,GridNeighbor(i, world_x, world_y, -1, -1), -1, -1, SQRT2);
113     grid[i].SetPtr(1 ,GridNeighbor(i, world_x, world_y,  0, -1),  0, -1, 1.0);
114     grid[i].SetPtr(2 ,GridNeighbor(i, world_x, world_y, +1, -1), +1, -1, SQRT2);
115     grid[i].SetPtr(3 ,GridNeighbor(i, world_x, world_y, +1,  0), +1,  0, 1.0);
116     grid[i].SetPtr(4 ,GridNeighbor(i, world_x, world_y, +1, +1), +1, +1, SQRT2);
117     grid[i].SetPtr(5 ,GridNeighbor(i, world_x, world_y,  0, +1),  0, +1, 1.0);
118     grid[i].SetPtr(6 ,GridNeighbor(i, world_x, world_y, -1, +1), -1, +1, SQRT2);
119     grid[i].SetPtr(7 ,GridNeighbor(i, world_x, world_y, -1,  0), -1,  0, 1.0);
120   }
121 
122   /* Fix links for top, bottom and sides for non-torus */
123 
124   if (geometry == nGeometry::GRID) {
125     /* Top and bottom */
126 
127     for (i = 0; i < world_x; i++) {
128       grid[i].SetPtr(0, -99, -99, -99, -99.0);
129       grid[i].SetPtr(1, -99, -99, -99, -99.0);
130       grid[i].SetPtr(2, -99, -99, -99, -99.0);
131       ii = num_cells-1-i;
132       grid[ii].SetPtr(4, -99, -99, -99, -99.0);
133       grid[ii].SetPtr(5, -99, -99, -99, -99.0);
134       grid[ii].SetPtr(6, -99, -99, -99, -99.0);
135     }
136 
137     /* fix links for right and left sides */
138 
139     for (i = 0; i < world_y; i++) {
140       ii = i * world_x;
141       grid[ii].SetPtr(0, -99, -99, -99, -99.0);
142       grid[ii].SetPtr(7, -99, -99, -99, -99.0);
143       grid[ii].SetPtr(6, -99, -99, -99, -99.0);
144       ii = ((i + 1) * world_x) - 1;
145       grid[ii].SetPtr(2, -99, -99, -99, -99.0);
146       grid[ii].SetPtr(3, -99, -99, -99, -99.0);
147       grid[ii].SetPtr(4, -99, -99, -99, -99.0);
148     }
149   }
150 }
151 
152 
CheckRanges()153 void cSpatialResCount::CheckRanges()
154 {
155 
156   // Check that the x, y ranges of the inflow and outflow rectangles
157   // are valid
158 
159   /* check range of inputs */
160 
161   if (inflowX1 < 0) {
162     inflowX1 = 0;
163   } else if (inflowX1 > world_x) {
164     inflowX1 = world_x;
165   }
166   if (inflowX2 < 0) {
167      inflowX2 = 0;
168   } else if (inflowX2 > world_x) {
169      inflowX2 = world_x;
170   }
171   if (inflowY1 < 0) {
172     inflowY1 = 0;
173   } else if (inflowY1 > world_y) {
174     inflowY1 = world_y;
175   }
176   if (inflowY2 < 0) {
177     inflowY2 = 0;
178   } else if (inflowY2 > world_y) {
179     inflowY2 = world_y;
180   }
181 
182   /* allow for rectangles that cross over the zero X or zero Y boundry */
183 
184   if (inflowX2 < inflowX1) { inflowX2 += world_x; }
185   if (inflowY2 < inflowY1) { inflowY2 += world_y; }
186 
187   if (outflowX1 < 0) {
188     outflowX1 = 0;
189   } else if (outflowX1 > world_x) {
190     outflowX1 = world_x;
191   }
192   if (outflowX2 < 0) {
193      outflowX2 = 0;
194   } else if (outflowX2 > world_x) {
195      outflowX2 = world_x;
196   }
197   if (outflowY1 < 0) {
198     outflowY1 = 0;
199   } else if (outflowY1 > world_y) {
200     outflowY1 = world_y;
201   }
202   if (outflowY2 < 0) {
203     outflowY2 = 0;
204   } else if (outflowY2 > world_y) {
205     outflowY2 = world_y;
206   }
207 
208   /* allow for rectangles that cross over the zero X or zero Y boundry */
209 
210   if (outflowX2 < outflowX1) { outflowX2 += world_x; }
211   if (outflowY2 < outflowY1) { outflowY2 += world_y; }
212 
213 }
214 
215 /* Set all the individual cells to their initial values */
SetCellList(tArray<cCellResource> * in_cell_list_ptr)216 void cSpatialResCount::SetCellList(tArray<cCellResource>* in_cell_list_ptr)
217 {
218   cell_list_ptr = in_cell_list_ptr;
219   for (int i = 0; i < cell_list_ptr->GetSize(); i++) {
220     int cell_id = (*cell_list_ptr)[i].GetId();
221 
222     /* Be sure the user entered a valid cell id or if the the program is loading
223        the resource for the testCPU that does not have a grid set up */
224 
225     if (cell_id >= 0 && cell_id <= grid.GetSize()) {
226       Rate((*cell_list_ptr)[i].GetId(), (*cell_list_ptr)[i].GetInitial());
227       State((*cell_list_ptr)[i].GetId());
228       Element(cell_id).SetInitial((*cell_list_ptr)[i].GetInitial());
229     }
230   }
231 }
232 
233 /* Set the rate variable for one element using the array index */
234 
Rate(int x,double ratein) const235 void cSpatialResCount::Rate(int x, double ratein) const {
236   if (x >= 0 && x < grid.GetSize()) {
237     grid[x].Rate(ratein);
238   } else {
239     assert(false); // x not valid id
240   }
241 }
242 
243 /* Set the rate variable for one element using the x,y coordinate */
244 
Rate(int x,int y,double ratein) const245 void cSpatialResCount::Rate(int x, int y, double ratein) const {
246   if (x >= 0 && x < world_x && y>= 0 && y < world_y) {
247     grid[y * world_x + x].Rate(ratein);
248   } else {
249     assert(false); // x or y not valid id
250   }
251 }
252 
253 /* Fold the rate variable into the resource state for one element using
254    the array index */
255 
State(int x)256 void cSpatialResCount::State(int x) {
257   if (x >= 0 && x < grid.GetSize()) {
258     grid[x].State();
259   } else {
260     assert(false); // x not valid id
261   }
262 }
263 
264 /* Fold the rate variable into the resource state for one element using
265    the x,y coordinate */
266 
State(int x,int y)267 void cSpatialResCount::State(int x, int y) {
268   if (x >= 0 && x < world_x && y >= 0 && y < world_y) {
269     grid[y*world_x + x].State();
270   } else {
271     assert(false); // x or y not valid id
272   }
273 }
274 
275 /* Get the state of one element using the array index */
276 
GetAmount(int x) const277 double cSpatialResCount::GetAmount(int x) const {
278   if (x >= 0 && x < grid.GetSize()) {
279     return grid[x].GetAmount();
280   } else {
281     return -99.9;
282   }
283 }
284 
285 /* Get the state of one element using the the x,y coordinate */
286 
GetAmount(int x,int y) const287 double cSpatialResCount::GetAmount(int x, int y) const {
288   if (x >= 0 && x < world_x && y >= 0 && y < world_y) {
289     return grid[y*world_x + x].GetAmount();
290   } else {
291     return -99.9;
292   }
293 }
294 
RateAll(double ratein)295 void cSpatialResCount::RateAll(double ratein) {
296 
297   int i;
298 
299   for (i = 0; i < num_cells; i++) {
300     grid[i].Rate(ratein);
301   }
302 }
303 
304 /* For each cell in the grid add the changes stored in the rate variable
305    with the total of the resource */
306 
StateAll()307 void cSpatialResCount::StateAll() {
308 
309   int i;
310 
311   for (i = 0; i < num_cells; i++) {
312     grid[i].State();
313   }
314 }
315 
FlowAll()316 void cSpatialResCount::FlowAll() {
317 
318   // @JEB save time if diffusion and gravity off...
319   if ((xdiffuse == 0.0) && (ydiffuse == 0.0) && (xgravity == 0.0) && (ygravity == 0.0)) return;
320 
321   int     i,k,ii,xdist,ydist;
322   double  dist;
323 
324   for (i = 0; i < num_cells; i++) {
325 
326     /* because flow is two way we must check only half the neighbors to
327        prevent double flow calculations */
328 
329     for (k = 3; k <= 6; k++) {
330       ii = grid[i].GetElemPtr(k);
331       xdist = grid[i].GetPtrXdist(k);
332       ydist = grid[i].GetPtrYdist(k);
333       dist = grid[i].GetPtrDist(k);
334       if (ii >= 0) {
335         FlowMatter(grid[i],grid[ii],xdiffuse,ydiffuse,xgravity,ygravity,
336                    xdist, ydist, dist);
337       }
338     }
339   }
340 }
341 
342 /* Total up all the resources in each cell */
343 
SumAll() const344 double cSpatialResCount::SumAll() const{
345 
346   int i;
347   double sum = 0.0;
348 
349   for (i = 0; i < num_cells; i++) {
350     sum += GetAmount(i);
351   }
352   return sum;
353 }
354 
355 /* Take a given amount of resource and spread it among all the cells in the
356    inflow rectange */
357 
Source(double amount) const358 void cSpatialResCount::Source(double amount) const {
359   int     i, j, elem;
360   double  totalcells;
361 
362   totalcells = (inflowY2 - inflowY1 + 1) * (inflowX2 - inflowX1 + 1) * 1.0;
363   amount /= totalcells;
364 
365   for (i = inflowY1; i <= inflowY2; i++) {
366     for (j = inflowX1; j <= inflowX2; j++) {
367       elem = (Mod(i,world_y) * world_x) + Mod(j,world_x);
368       Rate(elem,amount);
369     }
370   }
371 }
372 
373 /* Handle the inflow for a list of individual cells */
374 
CellInflow() const375 void cSpatialResCount::CellInflow() const {
376   for (int i=0; i < cell_list_ptr->GetSize(); i++) {
377     const int cell_id = (*cell_list_ptr)[i].GetId();
378 
379     /* Be sure the user entered a valid cell id or if the the program is loading
380        the resource for the testCPU that does not have a grid set up */
381 
382     if (cell_id >= 0 && cell_id < grid.GetSize()) {
383       Rate(cell_id, (*cell_list_ptr)[i].GetInflow());
384     }
385   }
386 }
387 
388 /* Take away a give percentage of a resource from outflow rectangle */
389 
Sink(double decay) const390 void cSpatialResCount::Sink(double decay) const {
391 
392   int     i, j, elem;
393   double  deltaamount;
394 
395   if (outflowX1 == -99 || outflowY1 == -99 || outflowX2 == -99 || outflowY2 == -99) return;
396 
397   for (i = outflowY1; i <= outflowY2; i++) {
398     for (j = outflowX1; j <= outflowX2; j++) {
399       elem = (Mod(i,world_y) * world_x) + Mod(j,world_x);
400       deltaamount = Max((GetAmount(elem) * (1.0 - decay)), 0.0);
401       Rate(elem,-deltaamount);
402     }
403   }
404 }
405 
406 /* Take away a give percentage of a resource from individual cells */
407 
CellOutflow() const408 void cSpatialResCount::CellOutflow() const {
409 
410   double deltaamount = 0.0;
411 
412   for (int i=0; i < cell_list_ptr->GetSize(); i++) {
413     const int cell_id = (*cell_list_ptr)[i].GetId();
414 
415     /* Be sure the user entered a valid cell id or if the the program is loading
416        the resource for the testCPU that does not have a grid set up */
417 
418     if (cell_id >= 0 && cell_id < grid.GetSize()) {
419       deltaamount = Max((GetAmount(cell_id) *
420                          (*cell_list_ptr)[i].GetOutflow()), 0.0);
421     }
422     Rate((*cell_list_ptr)[i].GetId(), -deltaamount);
423   }
424 }
425 
SetCellAmount(int cell_id,double res)426 void cSpatialResCount::SetCellAmount(int cell_id, double res)
427 {
428   if (cell_id >= 0 && cell_id < grid.GetSize())
429   {
430     Element(cell_id).SetAmount(res);
431   }
432 }
433 
434 
ResetResourceCounts()435 void cSpatialResCount::ResetResourceCounts()
436 {
437   for (int i = 0; i < grid.GetSize(); i++) grid[i].ResetResourceCount(m_initial);
438 }
439