Source code: org/mrd/models/cagn/CagnModel.java
1
2 /**
3 * Copyright (C) 2002-2003, Mark Diggory
4 *
5 * This file is part of the CAGN model project.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. License
20 * information is also available at http://www.gnu.org.
21 *
22 */
23 package org.mrd.models.cagn;
24
25 import java.util.*;
26 import java.awt.Point;
27 import org.mrd.repast.util.*;
28 import org.mrd.analysis.*;
29 import cern.jet.random.*;
30 import edu.cornell.lassp.houle.RngPack.RandomElement;
31
32 import uchicago.src.sim.engine.*;
33 import uchicago.src.sim.util.*;
34
35 import org.apache.commons.pool.*;
36 import org.apache.commons.pool.impl.*;
37 import org.apache.commons.logging.*;
38
39 /**
40 * The CAGN Model.
41 * @author Mark Diggory <mdiggory@latte.harvard.edu>
42 */
43 public class CagnModel extends SimModelImpl implements Stepable{
44
45 /** logging is always good to do, learn to use it. */
46 protected Log log = LogFactory.getLog(this.getClass().getName());
47
48 /** Every model must have a schedule */
49 protected Schedule schedule;
50
51 /** Holds value of property maxIterations, stop is scheduled using this. */
52 protected double maxIterations = Double.MAX_VALUE;
53
54 /** Holds value of property maxIterations, stop is scheduled using this. */
55 protected ObjectPool pool = null;
56
57 /** the landscape encapsulates agentList and grid datastructures. */
58 protected Landscape landscape;
59
60 /** Holds the location of the PGM file used to load the landscape */
61 protected String habitatSpaceFile;
62
63 /** Used to generate the currentIterationSurvival probability. This is later used
64 * by the pairs in calculating thier survival
65 */
66 protected Beta iteration_survivial_distribution = null;
67
68 /** Used in the Bernoulli trials of all the pairs to determine their survival roll.
69 */
70 protected RandomElement survival_generator = null;
71
72 /** Used in the Bernoulli trials of all the pairs to determine reproduction roll.
73 */
74 protected RandomElement rep_generator = null;
75
76 /** Used in all the pairs to determine their dispersal distance.
77 */
78 protected RandomElement disp_generator = null;
79
80 /** Holds value of property pairClutchSize. */
81 protected int pairClutchSize;
82
83 /** Holds value of property pairSearchTime. */
84 protected int pairSearchTime;
85
86 /** Holds value of property pairMeanDispersalDistance. */
87 protected double pairMeanDispersalDistance;
88
89 /** Holds value of property modelInitialPairs. */
90 protected int modelInitialPairs;
91
92 /** Holds value of property pairSurvivalSeed. */
93 protected int pairSurvivalSeed = (int)System.currentTimeMillis();
94
95 /** Holds value of property pairReproductionSeed. */
96 protected int pairReproductionSeed = (int)System.currentTimeMillis();
97
98 /** Holds value of property pairDispersalSeed. */
99 protected int pairDispersalSeed = (int)System.currentTimeMillis();
100
101 /** Holds value of property ageSurvivalTable.
102 */
103 protected double[] ageSurvivalTable = new double[]{1 ,1 ,1 ,.75,.001};
104
105 /** Holds value of property ageReproductionTable. */
106 protected double[] ageReproductionTable = new double[]{.75 ,1 ,1 ,.75,.75 };
107
108 /** Holds value of property landReproductionTable. */
109 protected double[] landReproductionTable = new double[]{.001,.25,.50,.75,1.00};
110
111 /** Holds value of property landSurvivalTable. */
112 protected double[] landSurvivalTable = new double[]{.001,.25,.50,.75,1.00};
113
114 /** Holds value of property iterationSurvivalMean. */
115 protected double iterationSurvivalMean = 0.9;
116
117 /** Holds value of property iterationSurvivalStd. */
118 protected double iterationSurvivalStd = 0.1;
119
120 /** Holds value of property currentIterationSurvival. */
121 protected double currentIterationSurvival;
122
123 /** Holds value of property iterationDispersalSurvival. */
124 private double iterationDispersalSurvival = 1.0;
125
126 private RunningBasicStatistics dispersalStatistics;
127
128
129 public CagnModel(){
130 super();
131 /*in future these sescriptors can be added to support array functionality in the GUI*/
132 //descriptors.put("AgeReproductionTable",new ArrayPropertyDescriptor("AgeReproductionTable",ageReproductionTable));
133 //descriptors.put("LandReproductionTable",new ArrayPropertyDescriptor("LandReproductionTable",landReproductionTable));
134 //descriptors.put("AgeSurvivalTable",new ArrayPropertyDescriptor("AgeSurvivalTable",ageSurvivalTable));
135 //descriptors.put("LandSurvivalTable",new ArrayPropertyDescriptor("LandSurvivalTable",landSurvivalTable));
136 }
137
138 /** Model is setup from this method. Runs first.
139 */
140 public void setup() {
141
142 try{
143 /*
144 * create a new schedule with an interval of one.
145 */
146 schedule = new Schedule(1.0);
147
148 /*
149 * this is an object pool capable of recycling the pair agents,
150 * I use this because it reduces the overhead of instantiating
151 * each new pair when its born, the model will only support x
152 * number of pairs, that is all I need to instantiate
153 */
154 pool = new StackObjectPool(new PairFactory(this), 500);
155
156 /*
157 * the landscape is a datastructure that combines several features
158 * into one object.
159 * 1.) the agent list for optimized update of the pairs
160 * 2.) the agent grid that establishes "position" for the pairs"
161 * 3.) the habitat grid that establishes "habitat quality" for
162 * the pairs position in the landscape
163 */
164 landscape = new Landscape(pool, habitatSpaceFile);
165
166 /* use the seeds that are either generated or parameterized to
167 * initialize their corresponding generators
168 */
169 survival_generator = new cern.jet.random.engine.MersenneTwister(pairSurvivalSeed);
170 rep_generator = new cern.jet.random.engine.MersenneTwister(pairReproductionSeed);
171 disp_generator = new cern.jet.random.engine.MersenneTwister(pairDispersalSeed);
172
173
174 /* This distribution generates temporal variation over simulation
175 * iterations. It uses a Beta Distribution configured using mean and
176 * std. Currently uses the SurvivalGenerator to genrate pseudorandom
177 * numbers.
178 */
179
180 /* This is to assure that the std + mean cannot be greater than 1*/
181 if(iterationSurvivalMean + iterationSurvivalStd > 1)
182 iterationSurvivalStd = 1-iterationSurvivalMean;
183
184 /* This is to assure that the mean - std cannot be less than or equal to 0*/
185 if(iterationSurvivalMean - iterationSurvivalStd <= 0)
186 iterationSurvivalStd = iterationSurvivalMean;
187
188 /* This is to assure that the std cannot be less than or equal to 0*/
189 if (iterationSurvivalStd <= 0){
190 iterationSurvivalStd = .00000001;
191 }
192
193 /* This is to assure that the mean cannot be less than or equal to 0*/
194 if (iterationSurvivalMean <= 0){
195 iterationSurvivalMean = .00000001;
196 }
197
198 iteration_survivial_distribution = new org.mrd.random.LimitedBeta(iterationSurvivalMean, iterationSurvivalStd,survival_generator,true,true);
199
200 /*
201 * get the variation occuring for the "0" iteration of the model.
202 */
203 currentIterationSurvival = iteration_survivial_distribution.nextDouble();
204
205 /*
206 * The next section is strictly to setup a randomized distribution of
207 * intial pairs.
208 *
209 * 1.) make sure our number isn't larger than the spaces available
210 * in the landscape.
211 */
212
213 if(this.modelInitialPairs >= landscape.getSizeX()*landscape.getSizeY()){
214 Exception e = new Exception("Initial Population too large.");
215 log.error(e.getMessage(),e);
216 }
217
218 /*
219 * 2.) we create a list of all possible places on the grid and
220 * randomly shuffle this list"
221 */
222 List shuffle = new ArrayList();
223 for(int i = 0;i < landscape.getSizeX();i++){
224 for(int j = 0 ; j < landscape.getSizeY();j++){
225 shuffle.add(new Point(i,j));
226 }
227 }
228
229 /** Used to initialize the landscape with pairs.*/
230 Uniform init_distribution = new Uniform(
231 new cern.jet.random.engine.MersenneTwister((int)this.getRngSeed())
232 );
233
234 /*
235 * 3.) add the initial pairs to the randomly chosen locations
236 */
237
238 SimUtilities.shuffle(shuffle,init_distribution);
239 Iterator points = shuffle.iterator();
240
241 for (int i = 0; i < modelInitialPairs; i++){
242 if(points.hasNext()){
243 Point p = (Point)points.next();
244 Pair pair = (Pair)pool.borrowObject();
245 pair.setCurrentAge(init_distribution.nextIntFromTo(0,this.getPairMaxAge()));
246 landscape.putAgentAt(p.x,p.y,pair);
247
248 }
249 }
250
251 /*
252 * 4.) birth the pairs into the agents list.
253 */
254 landscape.birthAgents();
255
256 /*
257 * 5.) Because the pairs are now "overdispersed", we us the pairs
258 * disperse() method which optimizes thier location if better
259 * habitat is available. In Pair, disperse() provides for dispersing
260 * without the risk of mortality, keeping the inital # of agents
261 * the same.
262 *
263 * Note: the mean dispersal distance is increased to allow the
264 * agents ample capability to get into better position.
265 * Otherwise, even if they were dispersed numerous times
266 * they still may not change position. The mean is adjusted
267 * back after the search is complete.
268 */
269 for (java.util.Iterator iter = landscape.getAgents().iterator(); iter.hasNext();) {
270 Pair pair = (Pair)iter.next();
271 pair.setDispersalDistance(landscape.getSizeX(), this.disp_generator);
272 Point disp = pair.search();
273 pair.setDispersalDistance(this.pairMeanDispersalDistance,this.disp_generator);
274 if(disp != null){
275 landscape.moveAgentTo(pair,disp.x,disp.y);
276 }
277
278 }
279
280 /* lets add in the RunningBAsicStat to collect Average/Std survival */
281 this.dispersalStatistics = new RunningBasicStatistics();
282 }catch(Exception e){
283 log.error(e.getMessage(),e);
284 }
285
286
287 }
288
289 /** Model begins from this method. Executes second.
290 */
291 public void begin() {
292 log.debug("begin()");
293
294 /*
295 * Add the neccessary events to the schedule, these setup to occur in
296 * the order they are added.
297 */
298 schedule.scheduleActionAtInterval(1.0,this,"step", Schedule.LAST);
299 schedule.scheduleActionAtIntervalRnd(1.0,landscape.getAgents(),"step", Schedule.LAST);
300 schedule.scheduleActionAtInterval(
301 1.0,
302 new BasicAction(){
303 public void execute(){
304 double surv_disp = (double)landscape.getBirthQueue().size();
305 double fail_disp = (double)landscape.getReaperQueue().size();
306
307 if(surv_disp != 0){
308 iterationDispersalSurvival = surv_disp / (surv_disp + fail_disp);
309 dispersalStatistics.incriment( iterationDispersalSurvival );
310 }
311 }
312 },
313 Schedule.LAST
314 );
315
316 schedule.scheduleActionAtInterval(1.0,landscape,"birthAgents", Schedule.LAST);
317 schedule.scheduleActionAtInterval(1.0,landscape,"reapAgents", Schedule.LAST);
318 schedule.scheduleActionAt(maxIterations, this, "stop", Schedule.LAST);
319 schedule.scheduleActionAtInterval(
320 1.0,
321 new BasicAction(){
322 public void execute(){
323 if(landscape.getAgents().size() < 1 ){
324 stop();
325 }
326 }
327 },
328 Schedule.LAST
329 );
330 }
331
332 /** This method is defined in the stepable interface, it is scheduled
333 * from with the begin method. Any code added here will be executed
334 * when the scheduled event occurs (currently once each iteration).
335 *
336 */
337 public void step(){
338 log.debug("step()");
339 /* get the variation occuring this iteration */
340 currentIterationSurvival = iteration_survivial_distribution.nextDouble();
341
342
343 }
344
345 /** a required method - displayed on the Controller toolbar.
346 * @return String value for the Name of the model.
347 *
348 */
349 public java.lang.String getName() {
350 return "Simple CAGN Model";
351 }
352
353 /** Used by the GUI to expose the Parameters that can be Manipulated.
354 * @return the String Array of Parameters that can be accessed from the gui
355 */
356 public java.lang.String[] getInitParam(){
357 return new String[]{
358 "ModelInitialPairs" ,
359 "MaxIterations",
360
361 "PairDispersalSeed",
362 "PairMeanDispersalDistance",
363 "PairSearchTime",
364
365 "PairSurvivalSeed",
366 "AgeSurvivalTable",
367 "LandSurvivalTable",
368
369 "PairReproductionSeed",
370 "LandReproductionTable",
371 "AgeReproductionTable",
372 "PairClutchSize",
373
374 "PairMaxAge",
375
376 "IterationSurvivalMean",
377 "IterationSurvivalStd",
378 };
379 }
380
381 /** Getter for property pairClutchSize.
382 * @return Value of property pairClutchSize.
383 */
384 public int getPairClutchSize() {
385 return this.pairClutchSize;
386 }
387
388 /** Setter for property pairClutchSize.
389 * @param pairClutchSize New value of property pairClutchSize.
390 */
391 public void setPairClutchSize(int pairClutchSize) {
392 this.pairClutchSize = pairClutchSize;
393 }
394
395 /** Getter for property pairSearchTime.
396 * @return Value of property pairSearchTime.
397 */
398 public int getPairSearchTime() {
399 return this.pairSearchTime;
400 }
401
402 /** Setter for property pairSearchTime.
403 * @param pairSearchTime New value of property pairSearchTime.
404 */
405 public void setPairSearchTime(int pairSearchTime) {
406 this.pairSearchTime = pairSearchTime;
407 }
408
409 /** Getter for property pairMeanDispersalDistance.
410 * @return Value of property pairMeanDispersalDistance.
411 */
412 public double getPairMeanDispersalDistance() {
413 return this.pairMeanDispersalDistance;
414 }
415
416 /** Setter for property pairMeanDispersalDistance.
417 * @param pairMeanDispersalDistance New value of property pairMeanDispersalDistance.
418 */
419 public void setPairMeanDispersalDistance(double pairMeanDispersalDistance) {
420 this.pairMeanDispersalDistance = pairMeanDispersalDistance;
421 }
422
423 /** Getter for property modelInitialPairs.
424 * @return Value of property modelInitialPairs.
425 */
426 public int getModelInitialPairs() {
427 return this.modelInitialPairs;
428 }
429
430 /** Setter for property modelInitialPairs.
431 * @param modelInitialPairs New value of property modelInitialPairs.
432 */
433 public void setModelInitialPairs(int modelInitialPairs) {
434 this.modelInitialPairs = modelInitialPairs;
435 }
436
437 /** Getter for property pairSurvivalSeed.
438 * @return Value of property pairSurvivalSeed.
439 */
440 public int getPairSurvivalSeed() {
441 return this.pairSurvivalSeed;
442 }
443
444 /** Setter for property pairSurvivalSeed.
445 * @param pairSurvivalSeed New value of property pairSurvivalSeed.
446 */
447 public void setPairSurvivalSeed(int pairSurvivalSeed) {
448 this.pairSurvivalSeed = pairSurvivalSeed;
449 }
450
451 /** Getter for property pairReproductionSeed.
452 * @return Value of property pairReproductionSeed.
453 */
454 public int getPairReproductionSeed() {
455 return this.pairReproductionSeed;
456 }
457
458 /** Setter for property pairReproductionSeed.
459 * @param pairReproductionSeed New value of property pairReproductionSeed.
460 */
461 public void setPairReproductionSeed(int pairReproductionSeed) {
462 this.pairReproductionSeed = pairReproductionSeed;
463 }
464
465 /** Getter for property pairDispersalSeed.
466 * @return Value of property pairDispersalSeed.
467 */
468 public int getPairDispersalSeed() {
469 return this.pairDispersalSeed;
470 }
471
472 /** Setter for property pairDispersalSeed.
473 * @param pairDispersalSeed New value of property pairDispersalSeed.
474 */
475 public void setPairDispersalSeed(int pairDispersalSeed) {
476 this.pairDispersalSeed = pairDispersalSeed;
477 }
478
479 /** Getter for property survivalTable.
480 * @return Value of property survivalTable.
481 */
482 public String getAgeSurvivalTable() {
483 return StringUtils.mush(ageSurvivalTable);
484 }
485
486 /** Setter for property survivalTable.
487 * @param table as a String
488 */
489 public void setAgeSurvivalTable(String table) {
490 this.ageSurvivalTable = StringUtils.chop(table);
491 }
492
493 /** Getter for property survivalTable.
494 * @return Value of property survivalTable.
495 */
496 public String getAgeReproductionTable() {
497 return StringUtils.mush(ageReproductionTable);
498 }
499
500 /** Setter for property survivalTable.
501 * @param table as a String
502 */
503 public void setAgeReproductionTable(String table) {
504 this.ageReproductionTable = StringUtils.chop(table);
505
506 }
507
508 /** Getter for property landReproductionTable.
509 * @return Value of property landReproductionTable.
510 */
511 public String getLandReproductionTable() {
512 return StringUtils.mush(this.landReproductionTable);
513 }
514
515 /** Setter for property landReproductionTable.
516 * @param table As a String
517 */
518 public void setLandReproductionTable(String table) {
519 this.landReproductionTable = StringUtils.chop(table);
520 }
521
522 /** Getter for property landSurvivalTable.
523 * @return Value of property landSurvivalTable.
524 */
525 public String getLandSurvivalTable() {
526 return StringUtils.mush(this.landSurvivalTable);
527 }
528
529 /** Setter for property landSurvivalTable.
530 * @param table As a String
531 */
532 public void setLandSurvivalTable(String table) {
533 this.landSurvivalTable = StringUtils.chop(table);
534 }
535
536 /** Getter for property maxAge.
537 * @return Value of property maxAge.
538 */
539 public int getPairMaxAge() {
540 return ageSurvivalTable.length;
541 }
542
543 /** Getter for property landscape.
544 * @return Value of property landscape.
545 */
546 public Landscape getLandscape() {
547 return this.landscape;
548 }
549
550 /** Getter for property habitatSpace.
551 * @return Value of property habitatSpace.
552 */
553 public String getHabitatSpaceFile() {
554 return habitatSpaceFile;
555 }
556
557 /** Setter for property habitatSpace.
558 * @param habitatSpaceFile returns the file used to load the landscape
559 */
560 public void setHabitatSpaceFile(String habitatSpaceFile) {
561 this.habitatSpaceFile = habitatSpaceFile;
562 }
563
564 /** Getter for property iterationSurvivalMean.
565 * @return Value of property iterationSurvivalMean.
566 */
567 public double getIterationSurvivalMean() {
568 return this.iterationSurvivalMean;
569 }
570
571 /** Setter for property iterationSurvivalMean.
572 * @param iterationSurvivalMean New value of property iterationSurvivalMean.
573 */
574 public void setIterationSurvivalMean(double iterationSurvivalMean) {
575 this.iterationSurvivalMean = iterationSurvivalMean;
576 }
577
578 /** Getter for property iterationSurvivalStd.
579 * @return Value of property iterationSurvivalStd.
580 */
581 public double getIterationSurvivalStd() {
582 return this.iterationSurvivalStd;
583 }
584
585 /** Setter for property iterationSurvivalStd.
586 * @param iterationSurvivalStd New value of property iterationSurvivalStd.
587 */
588 public void setIterationSurvivalStd(double iterationSurvivalStd) {
589 this.iterationSurvivalStd = iterationSurvivalStd;
590 }
591
592 /** Getter for property currentIterationSurvival.
593 * @return Value of property currentIterationSurvival.
594 */
595 public double getCurrentIterationSurvival() {
596 return this.currentIterationSurvival;
597 }
598
599 /** Getter for property maxIterations.
600 * @return Value of property maxIterations.
601 */
602 public double getMaxIterations() {
603 return this.maxIterations;
604 }
605
606 /** Setter for property maxIterations.
607 * @param maxIterations New value of property maxIterations.
608 */
609 public void setMaxIterations(double maxIterations) {
610 this.maxIterations = maxIterations;
611 }
612
613 /** Getter for property schedule.
614 * @return Value of property schedule.
615 */
616 public Schedule getSchedule(){
617 return schedule;
618 }
619
620 /** Setter for property schedule.
621 * @param schedule New value of property schedule.
622 */
623 public void setSchedule(Schedule schedule) {
624 this.schedule = schedule;
625 }
626
627 /**
628 * @return
629 */
630 public RunningBasicStatistics getDispersalStatistics() {
631 return dispersalStatistics;
632 }
633
634 /** PairFactor is a place to store instances of the Pair object, this way we don't
635 * need to keep createing and destroying them, which can be an expensive task. It
636 * is probibly important to get the number in the pool relatively close to that of
637 * the pairs in your simulation,this value is currently hard coded in the setup()
638 * method.
639 */
640 public class PairFactory extends org.apache.commons.pool.BasePoolableObjectFactory {
641
642 /** Holds value of property model. */
643 protected CagnModel model;
644
645 /** Constructs a Pair Factory for the current model and landscape.
646 * @param model the model for which this PAir Factory will be used.
647 */
648 public PairFactory(CagnModel model){
649 super();
650 this.model = model;
651 }
652
653 /** Either gets a Pair from the pool or creates a new one.
654 * @throws Exception If anything goes wrong getting or creating the Pair.
655 * @return A Pair.
656 */
657 public Object makeObject() throws java.lang.Exception {
658
659 Pair pair = new Pair(model,landscape);
660 pair.setClutchSize(pairClutchSize);
661 pair.setSearchTime(pairSearchTime);
662 pair.setCurrentAge(0);
663 pair.setSurvivalGenerator(survival_generator);
664 pair.setReproductionGenerator(rep_generator);
665 pair.setDispersalDistance(pairMeanDispersalDistance,disp_generator);
666 pair.setDispersalAngleGenerator(disp_generator);
667 return pair;
668
669 }
670
671 /** Uninitialize an instance to be returned to the pool. Setup the defaults for
672 * when it is used again
673 * @param obj the instance to be passivated
674 * @throws Exception If anything goes wrong
675 */
676 public void passivateObject(Object obj)
677 throws Exception {
678 Pair pair = (Pair)obj;
679 pair.setClutchSize(pairClutchSize);
680 pair.setSearchTime(pairSearchTime);
681 pair.setCurrentAge(0);
682 pair.setStage(Agent.ALIVE);
683 pair.setSurvivalGenerator(survival_generator);
684 pair.setReproductionGenerator(rep_generator);
685 pair.setDispersalDistance(pairMeanDispersalDistance,disp_generator);
686 pair.setDispersalAngleGenerator(disp_generator);
687 }
688 }
689
690
691 /**
692 * @return
693 */
694 public double getIterationDispersalSurvival() {
695 return iterationDispersalSurvival;
696 }
697
698 }