1
2 ///////////////////////////////////////////////////////////
3 // //
4 // SAGA //
5 // //
6 // System for Automated Geoscientific Analyses //
7 // //
8 // Tool Library //
9 // sim_cellular_automata //
10 // //
11 //-------------------------------------------------------//
12 // //
13 // Wator.cpp //
14 // //
15 // Copyright (C) 2003 by //
16 // Olaf Conrad //
17 // //
18 //-------------------------------------------------------//
19 // //
20 // This file is part of 'SAGA - System for Automated //
21 // Geoscientific Analyses'. SAGA is free software; you //
22 // can redistribute it and/or modify it under the terms //
23 // of the GNU General Public License as published by the //
24 // Free Software Foundation, either version 2 of the //
25 // License, or (at your option) any later version. //
26 // //
27 // SAGA is distributed in the hope that it will be //
28 // useful, but WITHOUT ANY WARRANTY; without even the //
29 // implied warranty of MERCHANTABILITY or FITNESS FOR A //
30 // PARTICULAR PURPOSE. See the GNU General Public //
31 // License for more details. //
32 // //
33 // You should have received a copy of the GNU General //
34 // Public License along with this program; if not, see //
35 // <http://www.gnu.org/licenses/>. //
36 // //
37 //-------------------------------------------------------//
38 // //
39 // e-mail: oconrad@saga-gis.org //
40 // //
41 // contact: Olaf Conrad //
42 // Institute of Geography //
43 // University of Goettingen //
44 // Goldschmidtstr. 5 //
45 // 37077 Goettingen //
46 // Germany //
47 // //
48 ///////////////////////////////////////////////////////////
49
50 //---------------------------------------------------------
51 #include "Wator.h"
52
53 //---------------------------------------------------------
54 #define FISH 1
55 #define SHARK 2
56
57
58 ///////////////////////////////////////////////////////////
59 // //
60 // //
61 // //
62 ///////////////////////////////////////////////////////////
63
64 //---------------------------------------------------------
CWator(void)65 CWator::CWator(void)
66 {
67 Set_Name (_TL("Wa-Tor"));
68
69 Set_Author ("O.Conrad (c) 2003");
70
71 Set_Description (_TW(
72 "Wa-Tor - an ecological simulation of predator-prey populations - "
73 "is based upon A. K. Dewdney's 'Computer Recreations' article "
74 "in the December 1984 issue of Scientific American."
75 ));
76
77 Add_Reference("Dewdney, A.K.", "1984",
78 "Sharks and fish Wage an ecological War on the toroidal planet Wa-Tor",
79 "Scientific American. pp. I4�22."
80 );
81
82 //-----------------------------------------------------
83 m_Grid_Target.Create(&Parameters, false, "", "TARGET_");
84
85 m_Grid_Target.Add_Grid("GRID", _TL("Wa-Tor"), false);
86
87 //-----------------------------------------------------
88 Parameters.Add_Bool("",
89 "REFRESH" , _TL("Refresh"),
90 _TL(""),
91 true
92 );
93
94 Parameters.Add_Double("REFRESH",
95 "INIT_FISH" , _TL("Initial Number of Fishes [%]"),
96 _TL(""),
97 30., 0., true, 100., true
98 );
99
100 Parameters.Add_Double("REFRESH",
101 "INIT_SHARK" , _TL("Initial Number of Sharks [%]"),
102 _TL(""),
103 7.5, 0., true, 100., true
104 );
105
106 Parameters.Add_Table("",
107 "TABLE" , _TL("Cycles"),
108 _TL(""),
109 PARAMETER_OUTPUT
110 );
111
112 Parameters.Add_Int("",
113 "FISH_BIRTH" , _TL("Birth Rate of Fishes"),
114 _TL(""),
115 3, 0, true
116 );
117
118 Parameters.Add_Int("",
119 "SHARK_BIRTH" , _TL("Birth Rate of Sharks"),
120 _TL(""),
121 12, 0, true
122 );
123
124 Parameters.Add_Int("",
125 "SHARK_STARVE" , _TL("Max. Starvation Time for Sharks"),
126 _TL(""),
127 4, 0, true
128 );
129 }
130
131
132 ///////////////////////////////////////////////////////////
133 // //
134 ///////////////////////////////////////////////////////////
135
136 //---------------------------------------------------------
On_Parameter_Changed(CSG_Parameters * pParameters,CSG_Parameter * pParameter)137 int CWator::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
138 {
139 m_Grid_Target.On_Parameter_Changed(pParameters, pParameter);
140
141 return( CSG_Tool::On_Parameter_Changed(pParameters, pParameter) );
142 }
143
144 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)145 int CWator::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
146 {
147 m_Grid_Target.On_Parameters_Enable(pParameters, pParameter);
148
149 return( CSG_Tool::On_Parameters_Enable(pParameters, pParameter) );
150 }
151
152
153 ///////////////////////////////////////////////////////////
154 // //
155 ///////////////////////////////////////////////////////////
156
157 //---------------------------------------------------------
On_Execute(void)158 bool CWator::On_Execute(void)
159 {
160 m_pWator = m_Grid_Target.Get_Grid("GRID", SG_DATATYPE_Byte);
161
162 if( !m_pWator )
163 {
164 Error_Set(_TL("could not create target grid"));
165
166 return( false );
167 }
168
169 //-----------------------------------------------------
170 m_pWator->Set_Name(_TL("Wa-Tor"));
171 m_pWator->Set_NoData_Value(-1);
172
173 CSG_Colors Colors(3);
174
175 Colors.Set_Color(0, SG_COLOR_BLACK);
176 Colors.Set_Color(1, SG_COLOR_GREEN);
177 Colors.Set_Color(2, SG_COLOR_RED );
178
179 DataObject_Add (m_pWator);
180 DataObject_Set_Colors(m_pWator, Colors);
181 DataObject_Update (m_pWator, 0, 2, SG_UI_DATAOBJECT_SHOW);
182
183 //-----------------------------------------------------
184 if( Parameters("REFRESH")->asBool() )
185 {
186 double Fish_perc = Parameters("INIT_FISH" )->asDouble();
187 double Shark_perc = Parameters("INIT_SHARK")->asDouble() + Fish_perc;
188
189 #pragma omp parallel for
190 for(int y=0; y<m_pWator->Get_NY(); y++)
191 {
192 for(int x=0; x<m_pWator->Get_NX(); x++)
193 {
194 double perc = CSG_Random::Get_Uniform(0, 100);
195
196 if( perc <= Fish_perc )
197 {
198 m_pWator->Set_Value(x, y, FISH);
199 }
200 else if( perc <= Shark_perc )
201 {
202 m_pWator->Set_Value(x, y, SHARK);
203 }
204 else
205 {
206 m_pWator->Set_Value(x, y, 0);
207 }
208 }
209 }
210 }
211
212 //-----------------------------------------------------
213 CSG_Table *pTable = Parameters("TABLE")->asTable();
214
215 pTable->Destroy();
216 pTable->Set_Name(_TL("Wa-Tor"));
217
218 pTable->Add_Field("Cycle" , SG_DATATYPE_Int);
219 pTable->Add_Field("Fishes", SG_DATATYPE_Int);
220 pTable->Add_Field("Sharks", SG_DATATYPE_Int);
221
222 //-----------------------------------------------------
223 m_Fish_Birth = Parameters("FISH_BIRTH" )->asInt();
224 m_Shark_Birth = Parameters("SHARK_BIRTH" )->asInt();
225 m_Shark_Starve = Parameters("SHARK_STARVE")->asInt();
226
227 m_Next .Create(m_pWator, SG_DATATYPE_Byte);
228 m_Age .Create(m_pWator, SG_DATATYPE_Byte);
229 m_Starve.Create(m_pWator, SG_DATATYPE_Byte);
230
231 #pragma omp parallel for
232 for(int y=0; y<m_pWator->Get_NY(); y++)
233 {
234 for(int x=0; x<m_pWator->Get_NX(); x++)
235 {
236 switch( m_pWator->asByte(x, y) )
237 {
238 case FISH:
239 m_Age .Set_Value(x, y, CSG_Random::Get_Uniform(0., m_Fish_Birth ));
240 break;
241
242 case SHARK:
243 m_Age .Set_Value(x, y, CSG_Random::Get_Uniform(0., m_Shark_Birth ));
244 m_Starve.Set_Value(x, y, CSG_Random::Get_Uniform(0., m_Shark_Starve));
245 break;
246 }
247 }
248 }
249
250 //-----------------------------------------------------
251 int i;
252
253 SG_UI_Progress_Lock(true);
254
255 for(i=1; Process_Get_Okay(true) && Next_Cycle(); i++)
256 {
257 Process_Set_Text("%s: %d", _TL("Life Cycle"), i);
258
259 CSG_Table_Record *pRecord = pTable->Add_Record();
260
261 pRecord->Set_Value(0, i);
262 pRecord->Set_Value(1, m_nFishes);
263 pRecord->Set_Value(2, m_nSharks);
264
265 DataObject_Update(m_pWator, 0, 2);
266 DataObject_Update(pTable);
267 }
268
269 SG_UI_Progress_Lock(false);
270
271 //-----------------------------------------------------
272 m_Next .Destroy();
273 m_Age .Destroy();
274 m_Starve.Destroy();
275
276 if( is_Progress() )
277 {
278 Message_Fmt("\n%s %d %s", _TL("Dead after"), i, _TL("Life Cycles"));
279 }
280
281 return( true );
282 }
283
284
285 ///////////////////////////////////////////////////////////
286 // //
287 ///////////////////////////////////////////////////////////
288
289 //---------------------------------------------------------
290 #define GET_NEIGHBOR {\
291 ix = m_pWator->Get_System().Get_xTo(i, x); if( ix < 0 ) ix = m_pWator->Get_NX() - 1; else if( ix >= m_pWator->Get_NX() ) ix = 0;\
292 iy = m_pWator->Get_System().Get_yTo(i, y); if( iy < 0 ) iy = m_pWator->Get_NY() - 1; else if( iy >= m_pWator->Get_NY() ) iy = 0;\
293 }
294
295 #define GET_NEIGHBOR_RANDOMLY {\
296 i = iNeighbor[(int)((double)rand() * nNeighbors / (double)RAND_MAX)];\
297 ix = m_pWator->Get_System().Get_xTo(i, x); if( ix < 0 ) ix = m_pWator->Get_NX() - 1; else if( ix >= m_pWator->Get_NX() ) ix = 0;\
298 iy = m_pWator->Get_System().Get_yTo(i, y); if( iy < 0 ) iy = m_pWator->Get_NY() - 1; else if( iy >= m_pWator->Get_NY() ) iy = 0;\
299 }
300
301 //---------------------------------------------------------
Next_Cycle(void)302 bool CWator::Next_Cycle(void)
303 {
304 static int iDir = 0;
305
306 int x, y, i, ix, iy, xx, yy, ax, ay, dx, dy,
307 iNeighbor[8], nNeighbors,
308 Age, Starve;
309
310 //-----------------------------------------------------
311 m_nFishes = 0;
312 m_nSharks = 0;
313
314 m_Next.Assign(0.);
315
316 switch( iDir )
317 {
318 default: ay = m_pWator->Get_NY() - 1; dy = -1; ax = m_pWator->Get_NX() - 1; dx = -1; iDir=0; break;
319 case 2: ay = 0; dy = 1; ax = m_pWator->Get_NX() - 1; dx = -1; iDir++; break;
320 case 1: ay = m_pWator->Get_NY() - 1; dy = -1; ax = 0; dx = 1; iDir++; break;
321 case 0: ay = 0; dy = 1; ax = 0; dx = 1; iDir++; break;
322 }
323
324 //-----------------------------------------------------
325 for(yy=0, y=ay; yy<m_pWator->Get_NY(); yy++, y+=dy)
326 {
327 for(xx=0, x=ax; xx<m_pWator->Get_NX(); xx++, x+=dx)
328 {
329 if( m_pWator->asByte(x, y) == FISH )
330 {
331 m_nFishes++;
332
333 Age = m_Age.asInt(x, y) + 1;
334
335 m_Age.Set_Value(x, y, 0);
336
337 for(i=0, nNeighbors=0; i<8; i++)
338 {
339 GET_NEIGHBOR;
340
341 if( m_pWator->asByte(ix, iy) == 0 && m_Next.asByte(ix, iy) == 0 )
342 {
343 iNeighbor[nNeighbors++] = i;
344 }
345 }
346
347 if( nNeighbors > 0 )
348 {
349 GET_NEIGHBOR_RANDOMLY;
350
351 m_Next.Set_Value(ix, iy, FISH);
352 m_Age .Set_Value(ix, iy, Age >= m_Fish_Birth ? 0 : Age);
353
354 if( Age >= m_Fish_Birth )
355 {
356 m_Next.Set_Value(x, y, FISH);
357 m_Age .Set_Value(x, y, CSG_Random::Get_Uniform(0, m_Fish_Birth));
358 }
359 else
360 {
361 m_pWator->Set_Value(x, y, 0);
362 }
363 }
364 else
365 {
366 m_Next.Set_Value(x, y, FISH);
367 m_Age .Set_Value(x, y, Age >= m_Fish_Birth ? 0 : m_Fish_Birth);
368 }
369 }
370 }
371 }
372
373 //-----------------------------------------------------
374 for(yy=0, y=ay; yy<m_pWator->Get_NY(); yy++, y+=dy)
375 {
376 for(xx=0, x=ax; xx<m_pWator->Get_NX(); xx++, x+=dx)
377 {
378 if( m_pWator->asByte(x, y) == SHARK )
379 {
380 m_nSharks++;
381
382 Age = m_Age.asInt(x, y) + 1;
383
384 m_Age.Set_Value(x, y, 0);
385
386 Starve = m_Starve.asInt(x, y) + 1;
387 m_Starve.Set_Value(x, y, 0);
388
389 for(i=0, nNeighbors=0; i<8; i++)
390 {
391 GET_NEIGHBOR;
392
393 if( m_Next.asByte(ix, iy) == FISH )
394 {
395 iNeighbor[nNeighbors++] = i;
396 }
397 }
398
399 if( nNeighbors > 0 )
400 {
401 GET_NEIGHBOR_RANDOMLY;
402
403 m_nFishes--;
404 m_pWator->Set_Value(ix, iy, 0);
405 m_Next .Set_Value(ix, iy, SHARK);
406 m_Age .Set_Value(ix, iy, Age >= m_Shark_Birth ? 0 : Age);
407 m_Starve .Set_Value(ix, iy, 0);
408
409 if( Age >= m_Shark_Birth )
410 {
411 m_Next .Set_Value(x, y, SHARK);
412 m_Age .Set_Value(x, y, CSG_Random::Get_Uniform(0, m_Shark_Birth));
413 m_Starve .Set_Value(x, y, 0);
414 }
415 else
416 {
417 m_pWator->Set_Value(x, y, 0);
418 }
419 }
420 else if( Starve <= m_Shark_Starve )
421 {
422 for(i=0, nNeighbors=0; i<8; i++)
423 {
424 GET_NEIGHBOR;
425
426 if( m_pWator->asByte(ix, iy) == 0 && m_Next.asByte(ix, iy) == 0 )
427 {
428 iNeighbor[nNeighbors++] = i;
429 }
430 }
431
432 if( nNeighbors > 0 )
433 {
434 GET_NEIGHBOR_RANDOMLY;
435
436 m_Next .Set_Value(ix, iy, SHARK);
437 m_Age .Set_Value(ix, iy, Age >= m_Shark_Birth ? 0 : Age);
438 m_Starve.Set_Value(ix, iy, Starve);
439
440 if( Age >= m_Shark_Birth )
441 {
442 m_Next .Set_Value(x, y, SHARK);
443 m_Age .Set_Value(x, y, CSG_Random::Get_Uniform(0, m_Shark_Birth));
444 m_Starve .Set_Value(x, y, Starve);
445 }
446 else
447 {
448 m_pWator ->Set_Value( x, y, 0);
449 }
450 }
451 else
452 {
453 m_Next .Set_Value(x, y, SHARK);
454 m_Age .Set_Value(x, y, Age >= m_Shark_Birth ? 0 : m_Shark_Birth);
455 m_Starve.Set_Value(x, y, Starve);
456 }
457 }
458 else
459 {
460 m_nSharks--;
461 }
462 }
463 }
464 }
465
466 //-----------------------------------------------------
467 #pragma omp parallel for private(x, y)
468 for(y=0; y<m_pWator->Get_NY(); y++)
469 {
470 for(x=0; x<m_pWator->Get_NX(); x++)
471 {
472 m_pWator->Set_Value(x, y, m_Next.asByte(x, y));
473 }
474 }
475
476 return( (m_nFishes > 0 && m_nFishes < m_pWator->Get_NCells()) || m_nSharks > 0 );
477 }
478
479
480 ///////////////////////////////////////////////////////////
481 // //
482 // //
483 // //
484 ///////////////////////////////////////////////////////////
485
486 //---------------------------------------------------------
487