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