/// <summary> /// Set the neighbouring cell of this cell at the passed index position. /// Setting a neighbour to 'null' sets the neighbour to the boundary. /// </summary> /// <param name="index">The desired position of the neighbour.</param> /// <param name="item">The neighbouring cell.</param> public void SetNeighbour(enumNeighbourPosition index, cCell item) { mvarNeighbours[(int)index] = item; }
/// <summary> /// A reference to one of the six neighbours of this cell. This value is /// indexed by an enumNeighbourPosition type. Before using this method, you /// should call the IsBoundary function with the same index to make sure that /// this neighbour is not the boundary. /// </summary> /// <param name="index">The neighbour position of interest.</param> /// <returns> /// The cell at the passed neighbour position. If the neighbour is the boundary, /// null is returned. /// </returns> public cCell GetNeighbour(enumNeighbourPosition index) { return(mvarNeighbours[(int)index]); }
// ********************* methods ************************************************* /// <summary> /// Determines if the neighbouring cell at the passed index is the boundary. /// </summary> /// <param name="index"> /// The index of the neighbour of interest. This is an enumNeighbourPosition /// type. /// </param> /// <returns>True if the neighbour of interest is the boundary.</returns> public bool IsBoundary(enumNeighbourPosition index) { return(mvarNeighbours[(int)index] == null); }
/// <summary> /// Define movement behaviour for independent (yearling and adult) foxes. /// </summary> /// <param name="CurrentWeek"> /// The current week of the year. An ArgumentOutOfRangeException exception is /// raised if CurrentWeek is not in the range of 1-52. /// </param> /// <returns>True if the fox changes cell.</returns> protected override bool Move(int CurrentWeek) { if (CurrentWeek < 1 || CurrentWeek > 52) { ThrowWeekException("CurrentWeek"); } // see if this is week 0, if it is, reset has moved ///////////////////////////////EER: the next line has been commented to enable >1 movement per year //if (CurrentWeek == 1) HasMoved = false; if (CurrentWeek > 0 || CurrentWeek < 53) { HasMoved = false; //EER } // next, if this animal has moved, leave now //EER: the next line has been commented out to enable >1 movement per year //if (HasMoved) return false; //EER: Do not all Adam & Eve to move, to help grow the population if (this.ID == "0" | this.ID == "1") { //System.Diagnostics.Debug.WriteLine("cFox.cs: Move(): Adam or Eve, ID = " + this.ID + "; don't move"); return(false); } // now load the appropriate movement arrays depending upon what type of animal // you are bool[] MovementArray; double[] MovementDistribution; if (this.AgeClass == enumAgeClass.YoungOfTheYear) { if (this.Gender == enumGender.female) { MovementArray = (this.Background as cFoxBackground).FoxYoungFemaleWeeklyMovement; MovementDistribution = (this.Background as cFoxBackground).FoxYoungFemaleMovementDistribution; } else { MovementArray = (this.Background as cFoxBackground).FoxYoungMaleWeeklyMovement; MovementDistribution = (this.Background as cFoxBackground).FoxYoungMaleMovementDistribution; } } else { if (this.Gender == enumGender.female) { MovementArray = (this.Background as cFoxBackground).FoxJuvAdultFemaleWeeklyMovement; MovementDistribution = (this.Background as cFoxBackground).FoxJuvAdultFemaleMovementDistribution; } else { MovementArray = (this.Background as cFoxBackground).FoxJuvAdultMaleWeeklyMovement; MovementDistribution = (this.Background as cFoxBackground).FoxJuvAdultMaleMovementDistribution; } } // can the animal even move this week? If not, leave now!! if (!MovementArray[CurrentWeek - 1]) { return(false); } // if it can, work out the current odds of moving for the current week double MovementOdds = 0; double OddsDenominator = 0; for (int j = 0; j < 52; j++) { if (MovementArray[j]) { OddsDenominator += 1; if (j <= CurrentWeek) { MovementOdds += 1; } } } // if odds denominator is 0, then no movement is defined, leave now if (OddsDenominator == 0) { // set the HasMoved flag to true and exit as if movement has happened HasMoved = true; return(true); } // calculate current movement odds // EER: this is needed to calculate the odds of moving for the current permissible week, given that there may be // more than one permissible weeks, and for the raccoon model, only 1 movement allowed per year // EER: For ARM, the animal is allowed >1 movement per year, so this code is not needed /* * MovementOdds = MovementOdds / OddsDenominator * 100; * // now determine if the animal will move * if (MovementOdds < 100) { * // if the random number is greater than the movement odds, the animal does not move * double RanValue = this.Background.RandomNum.RealValue(0, 100); * if (RanValue > MovementOdds) return false; * } */ // if we get here, we are going to move!! // generate a random number double MoveRandom = this.Background.RandomNum.RealValue(0, 100); // loop until movement distance is found // EER: This loops, interating i, until the sum of the movement probabilities, defined by array MovementDistribution // are greater than the random number, to randomly define the probability of moving i cells // So, the final i defines the number of cells to move // I think the limit of i should be set at the max allowable cells to move // Dave had this at 26, but I changed it to 49 to align with the ORM ArcGIS interface double sum = 0; int i; for (i = 0; i < 49; i++) { sum += MovementDistribution[i] * 100; //System.Diagnostics.Debug.WriteLine("cFox.cs: Move(): MovementDistribution[" + i + "] = " + MovementDistribution[i]); //System.Diagnostics.Debug.WriteLine("cFox.cs: Move(): sum = " + sum); //System.Diagnostics.Debug.WriteLine("cFox.cs: Move(): MoveRandom = " + MoveRandom); if (sum >= MoveRandom) { break; } } //System.Diagnostics.Debug.WriteLine("cFox.cs: Move(): HERE 5 Move this many cells = " + i); // at this point, i is the dispersal distance // call the calculate path of the MasterCell object belonging to the // background to find a path through the cells. Remember that the path // returned may not be the distance requested because it may stop at // a supercell boundary //EER: string lastCell; lastCell = null; if (i > 0) { // calculate a random direction bias //NOTE: Generating integer value now in range of 0 to 5. For this call we WANT the range 0 to 5 since the values // 0, 1, 2, 3, 4, 5 are all equally probable. D. Ball February 8, 2010 enumNeighbourPosition DirectionBias = (enumNeighbourPosition)this.Background.RandomNum.IntValue(0, 5); cCellList Path = this.Background.Cells.CalculatePath(this.CurrentCell.ID, i, DirectionBias); // move this animal to the last cell in this path if (Path.Count > 0) { this.MoveAnimal(Path[Path.Count - 1]); } } // set the HasMoved flag to true HasMoved = true; return(true); }
/// <summary> /// Define movement behaviour for independent (yearling and adult) raccoons. /// </summary> /// <param name="CurrentWeek"> /// The current week of the year. An ArgumentOutOfRangeException exception is /// raised if CurrentWeek is not in the range of 1-52. /// </param> /// <returns>True if the raccoon changes cell.</returns> protected override bool Move(int CurrentWeek) { if (CurrentWeek < 1 || CurrentWeek > 52) { ThrowWeekException("CurrentWeek"); } // see if this is week 0, if it is, reset has moved if (CurrentWeek == 1) { HasMoved = false; } //if (this.ID == "3683630" && CurrentWeek == 12 && this.Background.Years.CurrentYearNum == 81) //{ // int Stopper = 1; //} // next, if this animal has moved, leave now if (HasMoved) { return(false); } // now load the appropriate movement arrays depending upon what type of animal // you are bool[] MovementArray; double[] MovementDistribution; if (this.AgeClass == enumAgeClass.YoungOfTheYear) { if (this.Gender == enumGender.female) { MovementArray = (this.Background as cRaccoonBackground).RaccoonYoungFemaleWeeklyMovement; MovementDistribution = (this.Background as cRaccoonBackground).RaccoonYoungFemaleMovementDistribution; } else { MovementArray = (this.Background as cRaccoonBackground).RaccoonYoungMaleWeeklyMovement; MovementDistribution = (this.Background as cRaccoonBackground).RaccoonYoungMaleMovementDistribution; } } else { if (this.Gender == enumGender.female) { MovementArray = (this.Background as cRaccoonBackground).RaccoonJuvAdultFemaleWeeklyMovement; MovementDistribution = (this.Background as cRaccoonBackground).RaccoonJuvAdultFemaleMovementDistribution; } else { MovementArray = (this.Background as cRaccoonBackground).RaccoonJuvAdultMaleWeeklyMovement; MovementDistribution = (this.Background as cRaccoonBackground).RaccoonJuvAdultMaleMovementDistribution; } } // can the animal even move this week? If not, leave now!! if (!MovementArray[CurrentWeek - 1]) { return(false); } // if it can, work out the current odds of moving double MovementOdds = 0; double OddsDenominator = 0; for (int j = 0; j < 52; j++) { if (MovementArray[j]) { OddsDenominator += 1; if (j <= CurrentWeek) { MovementOdds += 1; } } } // if odds denominator is 0, then no movement is defined, leave now if (OddsDenominator == 0) { // set the HasMoved flag to true and exit as if movement has happened HasMoved = true; return(true); } // calculate current movement odds MovementOdds = MovementOdds / OddsDenominator * 100; // now detirmine if the animal will move if (MovementOdds < 100) { // if the random number is greater than the movement odds, the animal does not move double RanValue = this.Background.RandomNum.RealValue(0, 100); if (RanValue > MovementOdds) { return(false); } } // if we get here, we are going to move!! // generate a random number double MoveRandom = this.Background.RandomNum.RealValue(0, 100); // loop until movement distance is found double sum = 0; int i; for (i = 0; i < 26; i++) { sum += MovementDistribution[i]; if (sum >= MoveRandom) { break; } } // at this point, i is the dispersal distance // call the calculate path of the MasterCell object belonging to the // background to find a path through the cells. Remember that the path // returned may not be the distance requested because it may stop at // a supercell boundary if (i > 0) { // calculate a random direction bias //NOTE: Generating integer value now in range of 0 to 5. For this call we WANT the range 0 to 5 since the values // 0, 1, 2, 3, 4, 5 are all equally probable. D. Ball February 8, 2010 enumNeighbourPosition DirectionBias = (enumNeighbourPosition)this.Background.RandomNum.IntValue(0, 5); cCellList Path = this.Background.Cells.CalculatePath(this.CurrentCell.ID, i, DirectionBias); // move this animal to the last cell in this path if (Path.Count > 0) { this.MoveAnimal(Path[Path.Count - 1]); } } // set the HasMoved flag to true HasMoved = true; return(true); }
// ************************** Methods ******************************************* /// <summary> /// Calculate a path through a series of cells with a bias in the specified /// direction. Note, the returned path may not be as long as expected for two /// possible reasons; 1) The path encounters the boundary of the region under /// study or 2) The path attempts to cross a supercell boundary and cannot /// overcome the resistances involved to do so. /// </summary> /// <param name="StartCellID"> /// The ID of the cell at the start of the path. If if a cell with the passed ID /// is not in the list, an ArgumentException exception is raised. /// </param> /// <param name="PathLength"> /// The number of cells the path should pass through. /// </param> /// <param name="DirectionBias">The directional bias of the path.</param> /// <returns> /// A cCellList containing the cells within the path in order to the end of /// the path. The starting cell IS NOT included in this list. /// </returns> public cCellList CalculatePath(string StartCellID, int PathLength, enumNeighbourPosition DirectionBias) { cCellList Path = new cCellList(null); cCell CurrentCell = this[StartCellID]; cCell NextCell; int RanNum; enumNeighbourPosition Direction; // if requested path is zero length or less, then do nothing if (PathLength > 0) { // loop for desired path length for (int i = 0; i < PathLength; i++) { // get a Random number from the random number generator //mvarBackground.RandomNum.MinValue = 0; //mvarBackground.RandomNum.MaxValue = 100; RanNum = mvarBackground.RandomNum.IntValue(1, 100); // get a direction for the next cell based on the value of the // random number if (RanNum <= 20) { Direction = DirectionBias - 1; if (Direction < 0) { Direction += 6; } } else if (RanNum <= 80) { Direction = DirectionBias; } else { Direction = DirectionBias + 1; if ((int)Direction > 5) { Direction -= 6; } } // now try to get the neighbour. If this is a boundary cell, we can go // no further and will stop calculating the path. // is this neighbour on the boundary. If it is, break out of the loop // immediately. if (CurrentCell.IsBoundary(Direction)) { break; } // get the neighbouring cell NextCell = CurrentCell.GetNeighbour(Direction); // is the next cell in the same super group as the current cell. // If not see if we can overcome both the exiting and entering // resistances. if (NextCell.SuperCell != CurrentCell.SuperCell) { // the two cells do not share the same supercell. We must check // resistances // check out resistance of current cell. If we do not overcome it, // stop here. if (CurrentCell.SuperCell.OutResistance > 0) { //mvarBackground.RandomNum.MinValue = 0; //mvarBackground.RandomNum.MaxValue = 100; if (Background.RandomNum.IntValue(1, 100) <= CurrentCell.SuperCell.OutResistance) { break; } } // check in resistance of next cell. If we do not overcome it, // stop here if (NextCell.SuperCell.InResistance > 0) { //mvarBackground.RandomNum.MinValue = 0; //mvarBackground.RandomNum.MaxValue = 100; if (Background.RandomNum.IntValue(1, 100) <= NextCell.SuperCell.InResistance) { break; } } } // add the neigbour to our list try { Path.Add(NextCell); } catch { return(Path); } // now make next cell the current cell CurrentCell = NextCell; } } // return the calculted path return(Path); }