diff --git a/src/RScore/.github/workflows/check.yml b/src/RScore/.github/workflows/check.yml
new file mode 100644
index 00000000..2e865878
--- /dev/null
+++ b/src/RScore/.github/workflows/check.yml
@@ -0,0 +1,26 @@
+name: check
+on: push
+
+jobs:
+ check:
+ strategy:
+ matrix:
+ os: [windows-latest, ubuntu-latest, macos-latest]
+ include:
+ - os: windows-latest
+ path_to_exe: ./build/Debug/RScore.exe
+ - os: ubuntu-latest
+ path_to_exe: ./build/RScore
+ - os: macos-latest
+ path_to_exe: ./build/RScore
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: build
+ run: |
+ mkdir build && cd build
+ cmake ../ && cmake --build .
+
+ - name: run
+ run: ${{ matrix.path_to_exe }}
diff --git a/src/RScore/.gitignore b/src/RScore/.gitignore
new file mode 100644
index 00000000..9bd72d21
--- /dev/null
+++ b/src/RScore/.gitignore
@@ -0,0 +1,87 @@
+.gitignore
+#README.md
+
+# CodeLite
+/.build-debug/
+/Debug/
+/Release/
+/RNG_test/
+.codelite/
+compile_commands.json
+Makefile
+.build-release/
+build-Release/
+*.project
+*.workspace
+*.mk
+*.tags
+
+# Hidden source
+/RangeShiftR/src/.*
+
+# Windows files
+/RangeShiftR/src/*.dll
+
+# History files
+.Rhistory
+.Rapp.history
+
+# RStudio files
+.Rproj.user/
+/RangeShiftR/.Rproj.user/
+#/RangeShiftR/RangeShiftR.Rproj
+/RangeShiftR/Read-and-delete-me
+/RangeShiftR/.Rhistory
+#/RangeShiftR/.Rbuildignore
+
+# Session Data files
+.RData
+tags
+
+# User-specific files
+.Ruserdata
+
+# Example code in package build process
+*-Ex.R
+
+# Output files from R CMD build
+*.tar.gz
+/RangeShiftR/src/*.o
+/RangeShiftR/src/RangeShiftR.so
+
+
+# Windows files
+/RangeShiftR/src/*.dll
+
+# Output files from R CMD check
+/*.Rcheck/
+
+# Output from Rcpp compile.attributes()
+#/RangeShiftR/R/RcppExports.R
+#/RangeShiftR/src/RcppExports.cpp
+
+# RStudio files
+.Rproj.user/
+
+# produced vignettes
+vignettes/*.html
+vignettes/*.pdf
+#/RangeShiftR/man/
+
+# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3
+.httr-oauth
+
+# knitr and R markdown default cache directories
+/*_cache/
+/cache/
+
+# Temporary files created by R markdown
+*.utf8.md
+*.knit.md
+
+# compilation files
+*.o
+
+# Visual Studio files
+.vs/
+out/
diff --git a/src/RScore/CMakeLists.txt b/src/RScore/CMakeLists.txt
new file mode 100644
index 00000000..c14a3e3a
--- /dev/null
+++ b/src/RScore/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Config file for compilation with CMake
+
+if (NOT batchmode) # that is, RScore as a standalone
+ cmake_minimum_required(VERSION 3.10)
+ # set the project name and version
+ project(RScore VERSION 2.1.0)
+ # specify the C++ standard
+ set(CMAKE_CXX_STANDARD 17)
+ set(CMAKE_CXX_STANDARD_REQUIRED True)
+ add_executable(RScore Main.cpp Species.cpp Cell.cpp Community.cpp FractalGenerator.cpp Genome.cpp Individual.cpp Landscape.cpp Model.cpp Parameters.cpp Patch.cpp Population.cpp RandomCheck.cpp RSrandom.cpp SubCommunity.cpp Utils.cpp)
+else() # that is, RScore compiled as library within RangeShifter_batch
+ add_library(RScore Species.cpp Cell.cpp Community.cpp FractalGenerator.cpp Genome.cpp Individual.cpp Landscape.cpp Model.cpp Parameters.cpp Patch.cpp Population.cpp RandomCheck.cpp RSrandom.cpp SubCommunity.cpp Utils.cpp)
+endif()
+
+# pass config definitions to compiler
+target_compile_definitions(RScore PRIVATE RSWIN64)
+
+# enable LINUX_CLUSTER macro on Linux + macOS
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ add_compile_definitions("LINUX_CLUSTER")
+endif()
+
+# Debug Mode by default, unless "release" is passed
+if(NOT DEFINED release)
+ add_compile_definitions(RSDEBUG)
+endif()
+
+if(NOT batchmode)
+ target_include_directories(RScore PUBLIC "${PROJECT_BINARY_DIR}")
+endif()
\ No newline at end of file
diff --git a/src/RScore/CONTRIBUTING.md b/src/RScore/CONTRIBUTING.md
new file mode 100644
index 00000000..8055ccd8
--- /dev/null
+++ b/src/RScore/CONTRIBUTING.md
@@ -0,0 +1,81 @@
+# The RangeShifter platform - An eco-evolutionary modelling framework
+
+## How to contribute
+
+Thank you for your interest in contributing to the RangeShifter platform.
+In this document we will give you guidance on how to contribute to the RangeShifter project regarding issues, bug fixing and adding new features.
+
+## Repo structure
+
+![Rangeshifter repo structure](RS_repos.png)
+
+RangeShifter is distributed with three user interfaces, each living in their own repo:
+
+- the RangeShifter GUI (clickable Windows interface)*
+- RangeShifter Batch Mode (command line interface)
+- the RangeShiftR package (R interface)
+
+All three share the same source code for the core simulation (i.e., the actual model), which lives in this repo (RScore). Each of the interfaces keeps a copy of this core code in a subfolder called RScore, kept in sync with the RScore repo via a git subtree (see Git subtree usage section).
+
+⚠️ If you wish to propose a change to one of the interfaces, please do so in the corresponding repo: [RangeShifter batch mode](https://github.com/RangeShifter/RangeShifter_batch_dev), [RangeShiftR package](https://github.com/RangeShifter/RangeShiftR-package-dev).
+
+*The RangeShifter GUI is currently being rewritten, and is not open source yet.
+
+## Roles
+
+#### Maintainers
+
+- [@JetteReeg](https://github.com/JetteReeg): RScore repo and lead in R package
+- [@TheoPannetier](https://github.com/TheoPannetier): RScore repo and lead in batch mode
+
+Maintainers are responsible for coordinating development efforts and ensuring that RangeShifter keeps building continuously.
+
+#### Developers
+
+Regular contributors and members of the [RangeShifter development team](https://github.com/orgs/RangeShifter/people), including maintainers.
+
+#### Contributors
+
+Anyone who whishes to make changes to RangeShifter's code, including regular developers.
+
+## Branching policy
+
+![](branches.png)
+
+*Check out the [Git cheatsheet](https://github.com/RangeShifter/RScore/blob/development-guidelines/git_cheatsheet.md) for a reminder on the main git commands*
+
+This policy applies to RScore and all three RangeShifter interfaces.
+RangeShifter uses the following branching structure:
+
+- `main` is the default branch, where stable releases live. Because it contains the version of RangeShifter that users normally interact with, it must be stable and build at all times.
+Only maintainers should make significant changes to `main`, normally by merging `develop` into `main` to make newly developed features available to users, and marking a release while doing so.
+- `develop` is the development branch containing new, in-development features. It is the reference branch for all developers. Contributors may make small changes directly to `develop` but should ensure that new changes do not break the build. If one happens to break `develop`, it should be their top priority to fix it as this will disrupt the work of all other contributors.
+Larger changes should instead be developed on feature branches.
+- Larger changes should be first developed on feature (e.g. `cmake`, `mutualism`, etc.) or contributor (e.g., `theo`) branches. Contributors are welcome to experiment and break such branches at any time, as this will not impact users or other contributors.
+
+When progress is deemed satisfactory, changes can be brought to `develop`. Please open a pull request on GitHub, and assign at least one maintainer as a reviewer. As a pre-requisite, RangeShifter must build on the branch before merging. Please enter a descriptive title and use the description field to describe what you have changed.
+
+In the meantime, we encourage contributors to work in small and frequent commits, and to merge `develop` into their branch often to update their branch with newest changes.
+
+### Contributing to RangeShifter core code
+
+Any changes regarding the RangeShifter core code should be done in this repository and can afterwards be synced with all interfaces using the git subtree feature (see [Git subtree](https://github.com/RangeShifter/RScore/tree/development-guidelines#usage-git-subtrees) section in the README).
+
+#### Bugs
+
+To report a bug, please [open an issue](https://github.com/RangeShifter/RangeShiftR-package-dev/issues/new), using the Bug Report template.
+Please do check if a related issue has already open on one of the other interfaces ([here](https://github.com/RangeShifter/RangeShifter_batch/issues) for the batch interface or [here](https://github.com/RangeShifter/RangeShiftR-package-dev) for the R package interface).
+To propose a bug fix (thank you!!), please create and work on your own branch or fork, from either `main` or `develop` (preferred), and open a pull request when your fix is ready to be merged into the original branch.
+
+Maintainers will review the pull request, possibly request changes, and eventually integrate the bug fix into RScore, and update the subtrees to bring the fix to all interfaces.
+
+#### New features
+
+Do you have an idea of a new feature in the RangeShifter platform that should be integrated and is of use for other RangeShifter users?
+Please get in touch with the RangeShifter development team (rangeshiftr@uni-potsdam.de) to discuss a collaboration.
+
+⚠️ We advise to contact the developer team as early as possible if you plan on implementing a new feature. This could prevent simultaneous development of the same feature and coordinate potential joint development.
+
+Alternatively, proceed as with the bug fix above: create your own branch or fork _from `develop`_ and work from there, and submit a pull request when your new features are ready to join the core code.
+We recommend that you update your branch regularly to new changes on `develop` (using `git merge develop`) to reduce the risk of merge conflicts or your version getting out-of-touch in the late stages of development.
+We also recommend that you work in small commits, as this makes the code easier to debug, and makes it easier for maintainers to understand your contributions when reviewing a pull request.
diff --git a/src/RScore/Cell.cpp b/src/RScore/Cell.cpp
new file mode 100644
index 00000000..1c0f9378
--- /dev/null
+++ b/src/RScore/Cell.cpp
@@ -0,0 +1,237 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+//---------------------------------------------------------------------------
+
+#include "Cell.h"
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+
+// Cell functions
+
+Cell::Cell(int xx,int yy,intptr patch,int hab)
+{
+x = xx; y = yy;
+pPatch = patch;
+envVal = 1.0; // default - no effect of any gradient
+envDev = eps = 0.0;
+habIxx.push_back(hab);
+#if RSDEBUG
+//DebugGUI(("Cell::Cell(): this=" + Int2Str((int)this)
+// + " x=" + Int2Str(x) + " y=" + Int2Str(y)
+// + " habIndex=" + Int2Str(habIndex)
+//).c_str());
+#endif
+visits = 0;
+smsData = 0;
+}
+
+Cell::Cell(int xx,int yy,intptr patch,float hab)
+{
+x = xx; y = yy;
+pPatch = patch;
+envVal = 1.0; // default - no effect of any gradient
+envDev = eps = 0.0;
+habitats.push_back(hab);
+visits = 0;
+smsData = 0;
+}
+
+Cell::~Cell() {
+#if RSDEBUG
+//DEBUGLOG << "Cell::~Cell(): this = " << this << " smsData = " << smsData << endl;
+#endif
+habIxx.clear();
+habitats.clear();
+if (smsData != 0) {
+ if (smsData->effcosts != 0) delete smsData->effcosts;
+ delete smsData;
+}
+#if RSDEBUG
+//DEBUGLOG << "Cell::~Cell(): deleted" << endl;
+#endif
+}
+
+void Cell::setHabIndex(short hx) {
+#if RSDEBUG
+//DebugGUI(("Cell::setHabIndex(): this=" + Int2Str((int)this)
+// + " x=" + Int2Str(x) + " y=" + Int2Str(y)
+// + " habIx=" + Int2Str(habIx)
+//).c_str());
+#endif
+if (hx < 0) habIxx.push_back(0);
+else habIxx.push_back(hx);
+}
+
+void Cell::changeHabIndex(short ix,short hx) {
+if (ix >= 0 && ix < (short)habIxx.size() && hx >= 0) habIxx[ix] = hx;
+else habIxx[ix] = 0;
+}
+
+int Cell::getHabIndex(int ix) {
+if (ix < 0 || ix >= (int)habIxx.size())
+ // nodata cell OR should not occur, but treat as such
+ return -1;
+else return habIxx[ix];
+}
+int Cell::nHabitats(void) {
+int nh = (int)habIxx.size();
+if ((int)habitats.size() > nh) nh = (int)habitats.size();
+return nh;
+}
+
+void Cell::setHabitat(float q) {
+if (q >= 0.0 && q <= 100.0) habitats.push_back(q);
+else habitats.push_back(0.0);
+}
+
+float Cell::getHabitat(int ix) {
+if (ix < 0 || ix >= (int)habitats.size())
+ // nodata cell OR should not occur, but treat as such
+ return -1.0;
+else return habitats[ix];
+}
+
+void Cell::setPatch(intptr p) {
+pPatch = p;
+}
+intptr Cell::getPatch(void)
+{
+#if RSDEBUG
+//DebugGUI(("Cell::getPatch(): this=" + Int2Str((int)this)
+// + " x=" + Int2Str(x) + " y=" + Int2Str(y)
+// + " habIxx[0]=" + Int2Str(habIxx[0]) + " pPatch=" + Int2Str(pPatch)
+//).c_str());
+#endif
+return pPatch;
+}
+
+locn Cell::getLocn(void) { locn q; q.x = x; q.y = y; return q; }
+
+void Cell::setEnvDev(float d) { envDev = d; }
+
+float Cell::getEnvDev(void) { return envDev; }
+
+void Cell::setEnvVal(float e) {
+if (e >= 0.0) envVal = e;
+}
+
+float Cell::getEnvVal(void) { return envVal; }
+
+void Cell::updateEps(float ac,float randpart) {
+eps = eps*ac + randpart;
+}
+
+float Cell::getEps(void) { return eps; }
+
+// Functions to handle costs for SMS
+
+int Cell::getCost(void) {
+int c;
+if (smsData == 0) c = 0; // costs not yet set up
+else c = smsData->cost;
+return c;
+}
+
+void Cell::setCost(int c) {
+if (smsData == 0) {
+ smsData = new smscosts;
+ smsData->effcosts = 0;
+}
+smsData->cost = c;
+}
+
+// Reset the cost and the effective cost of the cell
+void Cell::resetCost(void) {
+if (smsData != 0) { resetEffCosts(); delete smsData; }
+smsData = 0;
+}
+
+array3x3f Cell::getEffCosts(void) {
+array3x3f a;
+if (smsData == 0 || smsData->effcosts == 0) { // effective costs have not been calculated
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ a.cell[i][j] = -1.0;
+ }
+ }
+}
+else
+ a = *smsData->effcosts;
+return a;
+}
+
+void Cell::setEffCosts(array3x3f a) {
+if (smsData->effcosts == 0) smsData->effcosts = new array3x3f;
+*smsData->effcosts = a;
+}
+
+// Reset the effective cost, but not the cost, of the cell
+void Cell::resetEffCosts(void) {
+if (smsData != 0) {
+ if (smsData->effcosts != 0) {
+ delete smsData->effcosts;
+ smsData->effcosts = 0;
+ }
+}
+}
+
+void Cell::resetVisits(void) { visits = 0; }
+void Cell::incrVisits(void) { visits++; }
+unsigned long int Cell::getVisits(void) { return visits; }
+
+//---------------------------------------------------------------------------
+
+// Initial species distribution cell functions
+
+DistCell::DistCell(int xx,int yy) {
+x = xx; y = yy; initialise = false;
+}
+
+DistCell::~DistCell() {
+
+}
+
+void DistCell::setCell(bool init) {
+initialise = init;
+}
+
+bool DistCell::toInitialise(locn loc) {
+if (loc.x == x && loc.y == y) return initialise;
+else return false;
+}
+
+bool DistCell::selected(void) { return initialise; }
+
+locn DistCell::getLocn(void) {
+locn loc; loc.x = x; loc.y = y; return loc;
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+
+
+
diff --git a/src/RScore/Cell.h b/src/RScore/Cell.h
new file mode 100644
index 00000000..5382a1ef
--- /dev/null
+++ b/src/RScore/Cell.h
@@ -0,0 +1,174 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 Cell
+
+Implements the following classes:
+
+Cell - Landscape cell
+
+DistCell - Initial species distribution cell
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Peer G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 14 January 2021 by Steve Palmer
+
+------------------------------------------------------------------------------*/
+
+#ifndef CellH
+#define CellH
+
+#include
+using namespace std;
+
+#include "Parameters.h"
+
+//---------------------------------------------------------------------------
+
+struct array3x3f { float cell[3][3]; }; // neighbourhood cell array (SMS)
+struct smscosts { int cost; array3x3f *effcosts; }; // cell costs for SMS
+
+// Landscape cell
+
+class Cell{
+public:
+ Cell( // Constructor for habitat codes
+ int, // x co-ordinate
+ int, // y co-ordinate
+ intptr, // pointer (cast as integer) to the Patch to which Cell belongs
+ int // habitat index number
+ );
+ Cell( // Constructor for habitat % cover or habitat quality
+ int, // x co-ordinate
+ int, // y co-ordinate
+ intptr, // pointer (cast as integer) to the Patch to which Cell belongs
+ float // habitat proportion or cell quality score
+ );
+ ~Cell();
+ void setHabIndex(
+ short // habitat index number
+ );
+ void changeHabIndex(
+ short, // landscape change number
+ short // habitat index number
+ );
+ int getHabIndex(
+ int // landscape change number
+ );
+ int nHabitats(void);
+ void setHabitat(
+ float // habitat proportions or cell quality score
+ );
+ float getHabitat( // Get habitat proportion / quality score
+ int // habitat index number / landscape change number
+ );
+ void setPatch(
+ intptr // pointer (cast as integer) to the Patch to which Cell belongs
+ );
+ intptr getPatch(void);
+ locn getLocn(void);
+ void setEnvDev(
+ float // local environmental deviation
+ );
+ float getEnvDev(void);
+ void setEnvVal(
+ float // environmental value
+ );
+ float getEnvVal(void);
+ void updateEps( // Update local environmental stochasticity (epsilon)
+ float, // autocorrelation coefficient
+ float // random adjustment
+ );
+ float getEps(void);
+ void setCost(
+ int // cost value for SMS
+ );
+ int getCost(void);
+ void resetCost(void);
+ array3x3f getEffCosts(void);
+ void setEffCosts(
+ array3x3f // 3 x 3 array of effective costs for neighbouring cells
+ );
+ void resetEffCosts(void); // Reset the effective cost, but not the cost, of the cell
+ void resetVisits(void);
+ void incrVisits(void);
+ unsigned long int getVisits(void);
+
+private:
+ int x,y; // cell co-ordinates
+ intptr pPatch; // pointer (cast as integer) to the Patch to which cell belongs
+ // NOTE: THE FOLLOWING ENVIRONMENTAL VARIABLES COULD BE COMBINED IN A STRUCTURE
+ // AND ACCESSED BY A POINTER ...
+ float envVal; // environmental value, representing one of:
+ // gradient in K, r or extinction probability
+ float envDev; // local environmental deviation (static, in range -1.0 to +1.0)
+ float eps; // local environmental stochasticity (epsilon) (dynamic, from N(0,std))
+ unsigned long int visits; // no. of times square is visited by dispersers
+ smscosts *smsData;
+
+ vector habIxx; // habitat indices (rasterType=0)
+ // NB initially, habitat codes are loaded, then converted to index nos.
+ // once landscape is fully loaded
+ vector habitats; // habitat proportions (rasterType=1) or quality (rasterType=2)
+};
+
+//---------------------------------------------------------------------------
+
+// Initial species distribution cell
+
+class DistCell{
+public:
+ DistCell(
+ int, // x co-ordinate
+ int // y co-ordinate
+ );
+ ~DistCell();
+ void setCell(
+ bool // TRUE if cell is to be initialised, FALSE if not
+ );
+ bool toInitialise(
+ locn // structure holding co-ordinates of cell
+ );
+ bool selected(void);
+ locn getLocn(void);
+
+private:
+ int x,y; // cell co-ordinates
+ bool initialise; // cell is to be initialised
+
+};
+
+#if RSDEBUG
+extern void DebugGUI(string);
+#endif
+
+//---------------------------------------------------------------------------
+
+#endif
diff --git a/src/RScore/Community.cpp b/src/RScore/Community.cpp
new file mode 100644
index 00000000..286dc6a3
--- /dev/null
+++ b/src/RScore/Community.cpp
@@ -0,0 +1,1562 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+ //---------------------------------------------------------------------------
+
+#include "Community.h"
+
+//---------------------------------------------------------------------------
+
+
+ofstream outrange;
+ofstream outoccup, outsuit;
+ofstream outtraitsrows;
+
+//---------------------------------------------------------------------------
+
+Community::Community(Landscape* pLand) {
+ pLandscape = pLand;
+ indIx = 0;
+}
+
+Community::~Community(void) {
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ delete subComms[i];
+ }
+ subComms.clear();
+}
+
+SubCommunity* Community::addSubComm(Patch* pPch, int num) {
+ int nsubcomms = (int)subComms.size();
+ subComms.push_back(new SubCommunity(pPch, num));
+ return subComms[nsubcomms];
+}
+
+void Community::initialise(Species* pSpecies, int year)
+{
+
+ int nsubcomms, npatches, ndistcells, spratio, patchnum, rr = 0;
+ locn distloc;
+ patchData pch;
+ patchLimits limits;
+ intptr ppatch, subcomm;
+ std::vector subcomms;
+ std::vector selected;
+ SubCommunity* pSubComm;
+ Patch* pPatch;
+ Cell* pCell;
+ landParams ppLand = pLandscape->getLandParams();
+ initParams init = paramsInit->getInit();
+
+ nsubcomms = (int)subComms.size();
+
+ spratio = ppLand.spResol / ppLand.resol;
+
+#if RSDEBUG
+ DEBUGLOG << endl << "Community::initialise(): this=" << this
+ << " seedType=" << init.seedType << " freeType=" << init.freeType
+ << " minSeedX=" << init.minSeedX << " minSeedY=" << init.minSeedY
+ << " maxSeedX=" << init.maxSeedX << " maxSeedY=" << init.maxSeedY
+ << " indsFile=" << init.indsFile
+ << " nsubcomms=" << nsubcomms << " spratio=" << spratio
+ << endl;
+#endif
+
+ switch (init.seedType) {
+
+ case 0: // free initialisation
+
+ switch (init.freeType) {
+
+ case 0: // random
+ // determine no. of patches / cells within the specified initialisation limits
+ // and record their corresponding sub-communities in a list
+ // parallel list records which have been selected
+ npatches = pLandscape->patchCount();
+ limits.xMin = init.minSeedX; limits.xMax = init.maxSeedX;
+ limits.yMin = init.minSeedY; limits.yMax = init.maxSeedY;
+ for (int i = 0; i < npatches; i++) {
+ pch = pLandscape->getPatchData(i);
+ if (pch.pPatch->withinLimits(limits)) {
+ if (ppLand.patchModel) {
+ if (pch.pPatch->getPatchNum() != 0) {
+ subcomms.push_back(pch.pPatch->getSubComm());
+ selected.push_back(false);
+ }
+ }
+ else { // cell-based model - is cell(patch) suitable
+ if (pch.pPatch->getK() > 0.0)
+ {
+ subcomms.push_back(pch.pPatch->getSubComm());
+ selected.push_back(false);
+ }
+ }
+ }
+ }
+ // select specified no. of patches/cells at random
+ npatches = (int)subcomms.size();
+ if (init.nSeedPatches > npatches / 2) { // use backwards selection method
+ for (int i = 0; i < npatches; i++) selected[i] = true;
+ for (int i = 0; i < (npatches - init.nSeedPatches); i++) {
+ do {
+ rr = pRandom->IRandom(0, npatches - 1);
+ } while (!selected[rr]);
+ selected[rr] = false;
+ }
+ }
+ else { // use forwards selection method
+ for (int i = 0; i < init.nSeedPatches; i++) {
+ do {
+ rr = pRandom->IRandom(0, npatches - 1);
+ } while (selected[rr]);
+ selected[rr] = true;
+ }
+ }
+ // selected sub-communities for initialisation
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ subComms[i]->setInitial(false);
+ }
+ for (int i = 0; i < npatches; i++) {
+ if (selected[i]) {
+ pSubComm = (SubCommunity*)subcomms[i];
+ pSubComm->setInitial(true);
+ }
+ }
+ break;
+
+ case 1: // all suitable patches/cells
+ npatches = pLandscape->patchCount();
+ limits.xMin = init.minSeedX; limits.xMax = init.maxSeedX;
+ limits.yMin = init.minSeedY; limits.yMax = init.maxSeedY;
+ for (int i = 0; i < npatches; i++) {
+ pch = pLandscape->getPatchData(i);
+ if (pch.pPatch->withinLimits(limits)) {
+ patchnum = pch.pPatch->getPatchNum();
+ if (patchnum != 0) {
+ if (pch.pPatch->getK() > 0.0)
+ { // patch is suitable
+ subcomm = pch.pPatch->getSubComm();
+ if (subcomm == 0) {
+ // create a sub-community in the patch
+ pSubComm = addSubComm(pch.pPatch, patchnum);
+ }
+ else {
+ pSubComm = (SubCommunity*)subcomm;
+ }
+ pSubComm->setInitial(true);
+ }
+ }
+ }
+ }
+
+ break;
+
+ case 2: // manually selected patches/cells
+ break;
+
+ } // end of switch (init.freeType)
+ nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ subComms[i]->initialise(pLandscape, pSpecies);
+ }
+ break;
+
+ case 1: // from species distribution
+ if (ppLand.spDist)
+ {
+ // deselect all existing sub-communities
+ for (int i = 0; i < nsubcomms; i++) {
+ subComms[i]->setInitial(false);
+ }
+ // initialise from loaded species distribution
+ switch (init.spDistType) {
+ case 0: // all presence cells
+ pLandscape->setDistribution(pSpecies, 0); // activate all patches
+ break;
+ case 1: // some randomly selected presence cells
+ pLandscape->setDistribution(pSpecies, init.nSpDistPatches); // activate random patches
+ break;
+ case 2: // manually selected presence cells
+ // cells have already been identified - no further action here
+ break;
+ }
+
+ // THE FOLLOWING WILL HAVE TO BE CHANGED FOR MULTIPLE SPECIES...
+ ndistcells = pLandscape->distCellCount(0);
+ for (int i = 0; i < ndistcells; i++) {
+ distloc = pLandscape->getSelectedDistnCell(0, i);
+ if (distloc.x >= 0) { // distribution cell is selected
+ // process each landscape cell within the distribution cell
+ for (int x = 0; x < spratio; x++) {
+ for (int y = 0; y < spratio; y++) {
+ pCell = pLandscape->findCell(distloc.x * spratio + x, distloc.y * spratio + y);
+ if (pCell != 0) { // not a no-data cell
+ ppatch = pCell->getPatch();
+ if (ppatch != 0) {
+ pPatch = (Patch*)ppatch;
+ if (pPatch->getSeqNum() != 0) { // not the matrix patch
+ subcomm = pPatch->getSubComm();
+ if (subcomm != 0) {
+ pSubComm = (SubCommunity*)subcomm;
+ pSubComm->setInitial(true);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ subComms[i]->initialise(pLandscape, pSpecies);
+ }
+ }
+ else {
+ // WHAT HAPPENS IF INITIAL DISTRIBUTION IS NOT LOADED ??? ....
+ // should not occur - take no action - no initialisation will occur
+ }
+ break;
+
+ case 2: // initial individuals in specified patches/cells
+ if (year < 0) {
+ // initialise matrix sub-community only
+ subComms[0]->initialise(pLandscape, pSpecies);
+ indIx = 0; // reset index for initial individuals
+ }
+ else { // add any initial individuals for the current year
+ initInd iind; iind.year = 0;
+ int ninds = paramsInit->numInitInds();
+ while (indIx < ninds && iind.year <= year) {
+ iind = paramsInit->getInitInd(indIx);
+ while (iind.year == year) {
+ if (ppLand.patchModel) {
+ if (pLandscape->existsPatch(iind.patchID)) {
+ pPatch = pLandscape->findPatch(iind.patchID);
+ if (pPatch->getK() > 0.0)
+ { // patch is suitable
+ subcomm = pPatch->getSubComm();
+ if (subcomm == 0) {
+ // create a sub-community in the patch
+ pSubComm = addSubComm(pPatch, iind.patchID);
+ }
+ else {
+ pSubComm = (SubCommunity*)subcomm;
+ }
+ pSubComm->initialInd(pLandscape, pSpecies, pPatch, pPatch->getRandomCell(), indIx);
+ }
+ }
+ }
+ else { // cell-based model
+ pCell = pLandscape->findCell(iind.x, iind.y);
+ if (pCell != 0) {
+ intptr ppatch = pCell->getPatch();
+ if (ppatch != 0) {
+ pPatch = (Patch*)ppatch;
+ if (pPatch->getK() > 0.0)
+ { // patch is suitable
+ subcomm = pPatch->getSubComm();
+ if (subcomm == 0) {
+ // create a sub-community in the patch
+ pSubComm = addSubComm(pPatch, iind.patchID);
+ }
+ else {
+ pSubComm = (SubCommunity*)subcomm;
+ }
+ pSubComm->initialInd(pLandscape, pSpecies, pPatch, pCell, indIx);
+ }
+ }
+ }
+ }
+ indIx++;
+ if (indIx < ninds) {
+ iind = paramsInit->getInitInd(indIx);
+ }
+ else {
+ iind.year = 99999999;
+ }
+ }
+ }
+ }
+ break;
+
+ case 3: // from file
+ // this condition cannot occur here, as init.seedType will have been changed to 0 or 1
+ // when the initialisation file was read
+ break;
+
+ } // end of switch (init.seedType)
+
+#if RSDEBUG
+ DEBUGLOG << "Community::initialise(): this=" << this
+ << " nsubcomms=" << nsubcomms
+ << endl;
+#endif
+
+}
+
+// Add manually selected patches/cells to the selected set for initialisation
+void Community::addManuallySelected(void) {
+ int npatches;
+ intptr subcomm, patch;
+ locn initloc;
+ Cell* pCell;
+ Patch* pPatch;
+ SubCommunity* pSubComm;
+
+ landParams ppLand = pLandscape->getLandParams();
+
+ npatches = pLandscape->initCellCount(); // no. of patches/cells specified
+#if RSDEBUG
+ DEBUGLOG << "Community::addManuallySelected(): this = " << this
+ << " npatches = " << npatches << endl;
+#endif
+ // identify sub-communities to be initialised
+ if (ppLand.patchModel) {
+ for (int i = 0; i < npatches; i++) {
+ initloc = pLandscape->getInitCell(i); // patch number held in x-coord of list
+ pPatch = pLandscape->findPatch(initloc.x);
+ if (pPatch != 0) {
+ subcomm = pPatch->getSubComm();
+ if (subcomm != 0) {
+ pSubComm = (SubCommunity*)subcomm;
+ pSubComm->setInitial(true);
+ }
+ }
+ }
+ }
+ else { // cell-based model
+ for (int i = 0; i < npatches; i++) {
+ initloc = pLandscape->getInitCell(i);
+ if (initloc.x >= 0 && initloc.x < ppLand.dimX
+ && initloc.y >= 0 && initloc.y < ppLand.dimY) {
+ pCell = pLandscape->findCell(initloc.x, initloc.y);
+ if (pCell != 0) { // not no-data cell
+ patch = pCell->getPatch();
+#if RSDEBUG
+ DEBUGLOG << "Community::initialise(): i = " << i
+ << " x = " << initloc.x << " y = " << initloc.y
+ << " pCell = " << pCell << " patch = " << patch
+ << endl;
+#endif
+ if (patch != 0) {
+ pPatch = (Patch*)patch;
+ subcomm = pPatch->getSubComm();
+#if RSDEBUG
+ DEBUGLOG << "Community::initialise(): i = " << i
+ << " pPatch = " << pPatch << " subcomm = " << subcomm
+ << endl;
+#endif
+ if (subcomm != 0) {
+ pSubComm = (SubCommunity*)subcomm;
+ pSubComm->setInitial(true);
+#if RSDEBUG
+ DEBUGLOG << "Community::initialise(): i = " << i
+ << " pSubComm = " << pSubComm
+ << endl;
+#endif
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void Community::resetPopns(void) {
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ subComms[i]->resetPopns();
+ }
+ // reset the individual ids to start from zero
+ Individual::indCounter = 0;
+}
+
+void Community::localExtinction(int option) {
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ if (subComms[i]->getNum() > 0) { // except in matrix
+ subComms[i]->localExtinction(option);
+ }
+ }
+}
+
+void Community::patchChanges(void) {
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ if (subComms[i]->getNum() > 0) { // except in matrix
+ subComms[i]->patchChange();
+ }
+ }
+}
+
+void Community::reproduction(int yr)
+{
+ float eps = 0.0; // epsilon for environmental stochasticity
+ landParams land = pLandscape->getLandParams();
+ envStochParams env = paramsStoch->getStoch();
+ int nsubcomms = (int)subComms.size();
+#if RSDEBUG
+ DEBUGLOG << "Community::reproduction(): this=" << this
+ << " nsubcomms=" << nsubcomms << endl;
+#endif
+
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ if (env.stoch) {
+ if (!env.local) { // global stochasticty
+ eps = pLandscape->getGlobalStoch(yr);
+ }
+ }
+ subComms[i]->reproduction(land.resol, eps, land.rasterType, land.patchModel);
+ }
+#if RSDEBUG
+ DEBUGLOG << "Community::reproduction(): finished" << endl;
+#endif
+}
+
+void Community::emigration(void)
+{
+ int nsubcomms = (int)subComms.size();
+#if RSDEBUG
+ DEBUGLOG << "Community::emigration(): this=" << this
+ << " nsubcomms=" << nsubcomms << endl;
+#endif
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ subComms[i]->emigration();
+ }
+#if RSDEBUG
+ DEBUGLOG << "Community::emigration(): finished" << endl;
+#endif
+}
+
+#if RS_RCPP // included also SEASONAL
+void Community::dispersal(short landIx, short nextseason)
+#else
+void Community::dispersal(short landIx)
+#endif // SEASONAL || RS_RCPP
+{
+#if RSDEBUG
+ int t0, t1, t2;
+ t0 = time(0);
+#endif
+
+ simParams sim = paramsSim->getSim();
+
+ int nsubcomms = (int)subComms.size();
+ // initiate dispersal - all emigrants leave their natal community and join matrix community
+ SubCommunity* matrix = subComms[0]; // matrix community is always the first
+ for (int i = 0; i < nsubcomms; i++) { // all populations
+ subComms[i]->initiateDispersal(matrix);
+ }
+#if RSDEBUG
+ t1 = time(0);
+ DEBUGLOG << "Community::dispersal(): this=" << this
+ << " nsubcomms=" << nsubcomms << " initiation time=" << t1 - t0 << endl;
+#endif
+
+ // dispersal is undertaken by all individuals now in the matrix patch
+ // (even if not physically in the matrix)
+ int ndispersers = 0;
+ do {
+ for (int i = 0; i < nsubcomms; i++) { // all populations
+ subComms[i]->resetPossSettlers();
+ }
+#if RS_RCPP // included also SEASONAL
+ ndispersers = matrix->transfer(pLandscape, landIx, nextseason);
+#else
+ ndispersers = matrix->transfer(pLandscape, landIx);
+#endif // SEASONAL || RS_RCPP
+ matrix->completeDispersal(pLandscape, sim.outConnect);
+ } while (ndispersers > 0);
+
+#if RSDEBUG
+ DEBUGLOG << "Community::dispersal(): matrix=" << matrix << endl;
+ t2 = time(0);
+ DEBUGLOG << "Community::dispersal(): transfer time=" << t2 - t1 << endl;
+#endif
+
+}
+
+void Community::survival(short part, short option0, short option1)
+{
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all communities (including in matrix)
+ subComms[i]->survival(part, option0, option1);
+ }
+}
+
+void Community::ageIncrement(void) {
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all communities (including in matrix)
+ subComms[i]->ageIncrement();
+ }
+}
+
+// Calculate total no. of individuals of all species
+int Community::totalInds(void) {
+ popStats p;
+ int total = 0;
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all communities (including in matrix)
+ p = subComms[i]->getPopStats();
+ total += p.nInds;
+ }
+ return total;
+}
+
+// Find the population of a given species in a given patch
+Population* Community::findPop(Species* pSp, Patch* pPch) {
+ Population* pPop = 0;
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all communities (including in matrix)
+ pPop = subComms[i]->findPop(pSp, pPch);
+ if (pPop != 0) break;
+ }
+ return pPop;
+}
+
+//---------------------------------------------------------------------------
+void Community::createOccupancy(int nrows, int reps) {
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) {
+ subComms[i]->createOccupancy(nrows);
+ }
+ // Initialise array for occupancy of suitable cells/patches
+ occSuit = new float* [nrows];
+ for (int i = 0; i < nrows; i++)
+ {
+ occSuit[i] = new float[reps];
+ for (int ii = 0; ii < reps; ii++) occSuit[i][ii] = 0.0;
+ }
+}
+
+void Community::updateOccupancy(int row, int rep)
+{
+#if RSDEBUG
+ DEBUGLOG << "Community::updateOccupancy(): row=" << row << endl;
+#endif
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) {
+ subComms[i]->updateOccupancy(row);
+ }
+
+ commStats s = getStats();
+ occSuit[row][rep] = (float)s.occupied / (float)s.suitable;
+
+}
+
+void Community::deleteOccupancy(int nrows) {
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) {
+ subComms[i]->deleteOccupancy();
+ }
+
+ for (int i = 0; i < nrows; i++)
+ delete[] occSuit[i];
+ delete[] occSuit;
+
+}
+
+//---------------------------------------------------------------------------
+// Count no. of sub-communities (suitable patches) and those occupied (non-zero populations)
+// Determine range margins
+commStats Community::getStats(void)
+{
+ commStats s;
+ landParams ppLand = pLandscape->getLandParams();
+ s.ninds = s.nnonjuvs = s.suitable = s.occupied = 0;
+ s.minX = ppLand.maxX; s.minY = ppLand.maxY; s.maxX = s.maxY = 0;
+ float localK;
+ popStats patchPop;
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ patchPop = subComms[i]->getPopStats();
+ s.ninds += patchPop.nInds;
+ s.nnonjuvs += patchPop.nNonJuvs;
+ if (patchPop.pPatch != 0) { // not the matrix patch
+ if (patchPop.pPatch->getPatchNum() != 0) { // not matrix patch
+ localK = patchPop.pPatch->getK();
+ if (localK > 0.0) s.suitable++;
+ if (patchPop.nInds > 0 && patchPop.breeding) {
+ s.occupied++;
+ patchLimits pchlim = patchPop.pPatch->getLimits();
+ if (pchlim.xMin < s.minX) s.minX = pchlim.xMin;
+ if (pchlim.xMax > s.maxX) s.maxX = pchlim.xMax;
+ if (pchlim.yMin < s.minY) s.minY = pchlim.yMin;
+ if (pchlim.yMax > s.maxY) s.maxY = pchlim.yMax;
+ }
+ }
+ }
+ }
+ return s;
+}
+
+//---------------------------------------------------------------------------
+
+// Functions to control production of output files
+
+// Open population file and write header record
+bool Community::outPopHeaders(Species* pSpecies, int option) {
+ return subComms[0]->outPopHeaders(pLandscape, pSpecies, option);
+}
+
+// Write records to population file
+void Community::outPop(int rep, int yr, int gen)
+{
+ // generate output for each sub-community (patch) in the community
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ subComms[i]->outPop(pLandscape, rep, yr, gen);
+ }
+
+}
+
+
+// Write records to individuals file
+void Community::outInds(int rep, int yr, int gen, int landNr) {
+
+ if (landNr >= 0) { // open the file
+ subComms[0]->outInds(pLandscape, rep, yr, gen, landNr);
+ return;
+ }
+ if (landNr == -999) { // close the file
+ subComms[0]->outInds(pLandscape, rep, yr, gen, -999);
+ return;
+ }
+ // generate output for each sub-community (patch) in the community
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ subComms[i]->outInds(pLandscape, rep, yr, gen, landNr);
+ }
+}
+
+// Write records to genetics file
+void Community::outGenetics(int rep, int yr, int gen, int landNr) {
+ //landParams ppLand = pLandscape->getLandParams();
+ if (landNr >= 0) { // open the file
+ subComms[0]->outGenetics(rep, yr, gen, landNr);
+ return;
+ }
+ if (landNr == -999) { // close the file
+ subComms[0]->outGenetics(rep, yr, gen, landNr);
+ return;
+ }
+ // generate output for each sub-community (patch) in the community
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ subComms[i]->outGenetics(rep, yr, gen, landNr);
+ }
+}
+
+// Open range file and write header record
+bool Community::outRangeHeaders(Species* pSpecies, int landNr)
+{
+
+ if (landNr == -999) { // close the file
+ if (outrange.is_open()) outrange.close();
+ outrange.clear();
+ return true;
+ }
+
+ string name;
+ landParams ppLand = pLandscape->getLandParams();
+ envStochParams env = paramsStoch->getStoch();
+ simParams sim = paramsSim->getSim();
+
+ // NEED TO REPLACE CONDITIONAL COLUMNS BASED ON ATTRIBUTES OF ONE SPECIES TO COVER
+ // ATTRIBUTES OF *ALL* SPECIES AS DETECTED AT MODEL LEVEL
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+
+#if RSDEBUG
+ DEBUGLOG << "Community::outRangeHeaders(): simulation=" << sim.simulation
+ << " sim.batchMode=" << sim.batchMode
+ << " landNr=" << landNr << endl;
+#endif
+
+ if (sim.batchMode) {
+ name = paramsSim->getDir(2)
+#if RS_RCPP
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation) + "_Land"
+ + Int2Str(landNr)
+#else
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation) + "_Land"
+ + Int2Str(landNr)
+#endif
+ + "_Range.txt";
+ }
+ else {
+ name = paramsSim->getDir(2) + "Sim" + Int2Str(sim.simulation) + "_Range.txt";
+ }
+ outrange.open(name.c_str());
+ outrange << "Rep\tYear\tRepSeason";
+ if (env.stoch && !env.local) outrange << "\tEpsilon";
+
+ outrange << "\tNInds";
+ if (dem.stageStruct) {
+ for (int i = 1; i < sstruct.nStages; i++) outrange << "\tNInd_stage" << i;
+ outrange << "\tNJuvs";
+ }
+ if (ppLand.patchModel) outrange << "\tNOccupPatches";
+ else outrange << "\tNOccupCells";
+ outrange << "\tOccup/Suit\tmin_X\tmax_X\tmin_Y\tmax_Y";
+
+ if (emig.indVar) {
+ if (emig.sexDep) {
+ if (emig.densDep) {
+ outrange << "\tF_meanD0\tF_stdD0\tM_meanD0\tM_stdD0";
+ outrange << "\tF_meanAlpha\tF_stdAlpha\tM_meanAlpha\tM_stdAlpha";
+ outrange << "\tF_meanBeta\tF_stdBeta\tM_meanBeta\tM_stdBeta";
+ }
+ else {
+ outrange << "\tF_meanEP\tF_stdEP\tM_meanEP\tM_stdEP";
+ }
+ }
+ else {
+ if (emig.densDep) {
+ outrange << "\tmeanD0\tstdD0\tmeanAlpha\tstdAlpha";
+ outrange << "\tmeanBeta\tstdBeta";
+ }
+ else {
+ outrange << "\tmeanEP\tstdEP";
+ }
+ }
+ }
+ if (trfr.indVar) {
+ if (trfr.moveModel) {
+ if (trfr.moveType == 1) {
+ outrange << "\tmeanDP\tstdDP\tmeanGB\tstdGB";
+ outrange << "\tmeanAlphaDB\tstdAlphaDB\tmeanBetaDB\tstdBetaDB";
+ }
+ if (trfr.moveType == 2) {
+ outrange << "\tmeanStepLength\tstdStepLength\tmeanRho\tstdRho";
+ }
+ }
+ else {
+ if (trfr.sexDep) {
+ outrange << "\tF_mean_distI\tF_std_distI\tM_mean_distI\tM_std_distI";
+ if (trfr.twinKern)
+ outrange << "\tF_mean_distII\tF_std_distII\tM_mean_distII\tM_std_distII"
+ << "\tF_meanPfirstKernel\tF_stdPfirstKernel"
+ << "\tM_meanPfirstKernel\tM_stdPfirstKernel";
+ }
+ else {
+ outrange << "\tmean_distI\tstd_distI";
+ if (trfr.twinKern)
+ outrange << "\tmean_distII\tstd_distII\tmeanPfirstKernel\tstdPfirstKernel";
+ }
+ }
+ }
+ if (sett.indVar) {
+ if (sett.sexDep) {
+ outrange << "\tF_meanS0\tF_stdS0\tM_meanS0\tM_stdS0";
+ outrange << "\tF_meanAlphaS\tF_stdAlphaS\tM_meanAlphaS\tM_stdAlphaS";
+ outrange << "\tF_meanBetaS\tF_stdBetaS\tM_meanBetaS\tM_stdBetaS";
+
+ }
+ else {
+ outrange << "\tmeanS0\tstdS0";
+ outrange << "\tmeanAlphaS\tstdAlphaS";
+ outrange << "\tmeanBetaS\tstdBetaS";
+ }
+ }
+ outrange << endl;
+
+#if RSDEBUG
+ DEBUGLOG << "Community::outRangeHeaders(): finished" << endl;
+#endif
+
+ return outrange.is_open();
+}
+
+// Write record to range file
+void Community::outRange(Species* pSpecies, int rep, int yr, int gen)
+{
+#if RSDEBUG
+ DEBUGLOG << "Community::outRange(): rep=" << rep
+ << " yr=" << yr << " gen=" << gen << endl;
+#endif
+
+ landParams ppLand = pLandscape->getLandParams();
+ envStochParams env = paramsStoch->getStoch();
+
+ // NEED TO REPLACE CONDITIONAL COLUMNS BASED ON ATTRIBUTES OF ONE SPECIES TO COVER
+ // ATTRIBUTES OF *ALL* SPECIES AS DETECTED AT MODEL LEVEL
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+
+ outrange << rep << "\t" << yr << "\t" << gen;
+ if (env.stoch && !env.local) // write global environmental stochasticity
+ outrange << "\t" << pLandscape->getGlobalStoch(yr);
+
+ commStats s = getStats();
+
+ if (dem.stageStruct) {
+ outrange << "\t" << s.nnonjuvs;
+ int stagepop;
+ int nsubcomms = (int)subComms.size();
+ // all non-juvenile stages
+ for (int stg = 1; stg < sstruct.nStages; stg++) {
+ stagepop = 0;
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ stagepop += subComms[i]->stagePop(stg);
+ }
+ outrange << "\t" << stagepop;
+ }
+ // juveniles born in current reproductive season
+ stagepop = 0;
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities
+ stagepop += subComms[i]->stagePop(0);
+ }
+ outrange << "\t" << stagepop;
+ }
+ else { // non-structured species
+ outrange << "\t" << s.ninds;
+ }
+
+ float occsuit = 0.0;
+ if (s.suitable > 0) occsuit = (float)s.occupied / (float)s.suitable;
+ outrange << "\t" << s.occupied << "\t" << occsuit;
+ // RANGE MINIMA AND MAXIMA NEED TO BECOME A PROPERTY OF THE SPECIES
+ if (s.ninds > 0) {
+ landOrigin origin = pLandscape->getOrigin();
+ outrange << "\t" << (float)s.minX * (float)ppLand.resol + origin.minEast
+ << "\t" << (float)(s.maxX + 1) * (float)ppLand.resol + origin.minEast
+ << "\t" << (float)s.minY * (float)ppLand.resol + origin.minNorth
+ << "\t" << (float)(s.maxY + 1) * (float)ppLand.resol + origin.minNorth;
+ }
+ else
+ outrange << "\t0\t0\t0\t0";
+
+ if (emig.indVar || trfr.indVar || sett.indVar) { // output trait means
+ traitsums ts;
+ traitsums scts; // sub-community traits
+ traitCanvas tcanv;
+ int ngenes, popsize;
+
+ tcanv.pcanvas[0] = NULL;
+
+ for (int i = 0; i < NSEXES; i++) {
+ ts.ninds[i] = 0;
+ ts.sumD0[i] = ts.ssqD0[i] = 0.0;
+ ts.sumAlpha[i] = ts.ssqAlpha[i] = 0.0; ts.sumBeta[i] = ts.ssqBeta[i] = 0.0;
+ ts.sumDist1[i] = ts.ssqDist1[i] = 0.0; ts.sumDist2[i] = ts.ssqDist2[i] = 0.0;
+ ts.sumProp1[i] = ts.ssqProp1[i] = 0.0;
+ ts.sumDP[i] = ts.ssqDP[i] = 0.0;
+ ts.sumGB[i] = ts.ssqGB[i] = 0.0;
+ ts.sumAlphaDB[i] = ts.ssqAlphaDB[i] = 0.0;
+ ts.sumBetaDB[i] = ts.ssqBetaDB[i] = 0.0;
+ ts.sumStepL[i] = ts.ssqStepL[i] = 0.0; ts.sumRho[i] = ts.ssqRho[i] = 0.0;
+ ts.sumS0[i] = ts.ssqS0[i] = 0.0;
+ ts.sumAlphaS[i] = ts.ssqAlphaS[i] = 0.0; ts.sumBetaS[i] = ts.ssqBetaS[i] = 0.0;
+ }
+
+ int nsubcomms = (int)subComms.size();
+ for (int i = 0; i < nsubcomms; i++) { // all sub-communities (incl. matrix)
+ scts = subComms[i]->outTraits(tcanv, pLandscape, rep, yr, gen, true);
+ for (int j = 0; j < NSEXES; j++) {
+ ts.ninds[j] += scts.ninds[j];
+ ts.sumD0[j] += scts.sumD0[j]; ts.ssqD0[j] += scts.ssqD0[j];
+ ts.sumAlpha[j] += scts.sumAlpha[j]; ts.ssqAlpha[j] += scts.ssqAlpha[j];
+ ts.sumBeta[j] += scts.sumBeta[j]; ts.ssqBeta[j] += scts.ssqBeta[j];
+ ts.sumDist1[j] += scts.sumDist1[j]; ts.ssqDist1[j] += scts.ssqDist1[j];
+ ts.sumDist2[j] += scts.sumDist2[j]; ts.ssqDist2[j] += scts.ssqDist2[j];
+ ts.sumProp1[j] += scts.sumProp1[j]; ts.ssqProp1[j] += scts.ssqProp1[j];
+ ts.sumDP[j] += scts.sumDP[j]; ts.ssqDP[j] += scts.ssqDP[j];
+ ts.sumGB[j] += scts.sumGB[j]; ts.ssqGB[j] += scts.ssqGB[j];
+ ts.sumAlphaDB[j] += scts.sumAlphaDB[j]; ts.ssqAlphaDB[j] += scts.ssqAlphaDB[j];
+ ts.sumBetaDB[j] += scts.sumBetaDB[j]; ts.ssqBetaDB[j] += scts.ssqBetaDB[j];
+ ts.sumStepL[j] += scts.sumStepL[j]; ts.ssqStepL[j] += scts.ssqStepL[j];
+ ts.sumRho[j] += scts.sumRho[j]; ts.ssqRho[j] += scts.ssqRho[j];
+ ts.sumS0[j] += scts.sumS0[j]; ts.ssqS0[j] += scts.ssqS0[j];
+ ts.sumAlphaS[j] += scts.sumAlphaS[j]; ts.ssqAlphaS[j] += scts.ssqAlphaS[j];
+ ts.sumBetaS[j] += scts.sumBetaS[j]; ts.ssqBetaS[j] += scts.ssqBetaS[j];
+ }
+ }
+
+ if (emig.indVar) {
+ if (emig.sexDep) { // must be a sexual species
+ ngenes = 2;
+ }
+ else {
+ if (dem.repType == 0) { // asexual reproduction
+ ngenes = 1;
+ }
+ else { // sexual reproduction
+ ngenes = 1;
+ }
+ }
+ double mnD0[2], mnAlpha[2], mnBeta[2], sdD0[2], sdAlpha[2], sdBeta[2];
+ for (int g = 0; g < ngenes; g++) {
+ mnD0[g] = mnAlpha[g] = mnBeta[g] = sdD0[g] = sdAlpha[g] = sdBeta[g] = 0.0;
+ // individuals may have been counted by sex if there was
+ // sex dependency in another dispersal phase
+ if (ngenes == 2) popsize = ts.ninds[g];
+ else popsize = ts.ninds[0] + ts.ninds[1];
+ if (popsize > 0) {
+ mnD0[g] = ts.sumD0[g] / (double)popsize;
+ mnAlpha[g] = ts.sumAlpha[g] / (double)popsize;
+ mnBeta[g] = ts.sumBeta[g] / (double)popsize;
+ if (popsize > 1) {
+ sdD0[g] = ts.ssqD0[g] / (double)popsize - mnD0[g] * mnD0[g];
+ if (sdD0[g] > 0.0) sdD0[g] = sqrt(sdD0[g]); else sdD0[g] = 0.0;
+ sdAlpha[g] = ts.ssqAlpha[g] / (double)popsize - mnAlpha[g] * mnAlpha[g];
+ if (sdAlpha[g] > 0.0) sdAlpha[g] = sqrt(sdAlpha[g]); else sdAlpha[g] = 0.0;
+ sdBeta[g] = ts.ssqBeta[g] / (double)popsize - mnBeta[g] * mnBeta[g];
+ if (sdBeta[g] > 0.0) sdBeta[g] = sqrt(sdBeta[g]); else sdBeta[g] = 0.0;
+ }
+ else {
+ sdD0[g] = sdAlpha[g] = sdBeta[g] = 0.0;
+ }
+ }
+ }
+ if (emig.sexDep) {
+ outrange << "\t" << mnD0[0] << "\t" << sdD0[0];
+ outrange << "\t" << mnD0[1] << "\t" << sdD0[1];
+ if (emig.densDep) {
+ outrange << "\t" << mnAlpha[0] << "\t" << sdAlpha[0];
+ outrange << "\t" << mnAlpha[1] << "\t" << sdAlpha[1];
+ outrange << "\t" << mnBeta[0] << "\t" << sdBeta[0];
+ outrange << "\t" << mnBeta[1] << "\t" << sdBeta[1];
+ }
+ }
+ else { // sex-independent
+ outrange << "\t" << mnD0[0] << "\t" << sdD0[0];
+ if (emig.densDep) {
+ outrange << "\t" << mnAlpha[0] << "\t" << sdAlpha[0];
+ outrange << "\t" << mnBeta[0] << "\t" << sdBeta[0];
+ }
+ }
+ }
+
+ if (trfr.indVar) {
+ if (trfr.moveModel) {
+ // CURRENTLY INDIVIDUAL VARIATION CANNOT BE SEX-DEPENDENT
+ ngenes = 1;
+ }
+ else {
+ if (trfr.sexDep) { // must be a sexual species
+ ngenes = 2;
+ }
+ else {
+ ngenes = 1;
+ }
+ }
+ double mnDist1[2], mnDist2[2], mnProp1[2], mnStepL[2], mnRho[2];
+ double sdDist1[2], sdDist2[2], sdProp1[2], sdStepL[2], sdRho[2];
+ double mnDP[2], mnGB[2], mnAlphaDB[2], mnBetaDB[2];
+ double sdDP[2], sdGB[2], sdAlphaDB[2], sdBetaDB[2];
+ for (int g = 0; g < ngenes; g++) {
+ mnDist1[g] = mnDist2[g] = mnProp1[g] = mnStepL[g] = mnRho[g] = 0.0;
+ sdDist1[g] = sdDist2[g] = sdProp1[g] = sdStepL[g] = sdRho[g] = 0.0;
+ mnDP[g] = mnGB[g] = mnAlphaDB[g] = mnBetaDB[g] = 0.0;
+ sdDP[g] = sdGB[g] = sdAlphaDB[g] = sdBetaDB[g] = 0.0;
+ // individuals may have been counted by sex if there was
+ // sex dependency in another dispersal phase
+ if (ngenes == 2) popsize = ts.ninds[g];
+ else popsize = ts.ninds[0] + ts.ninds[1];
+ if (popsize > 0) {
+ mnDist1[g] = ts.sumDist1[g] / (double)popsize;
+ mnDist2[g] = ts.sumDist2[g] / (double)popsize;
+ mnProp1[g] = ts.sumProp1[g] / (double)popsize;
+ mnStepL[g] = ts.sumStepL[g] / (double)popsize;
+ mnRho[g] = ts.sumRho[g] / (double)popsize;
+ mnDP[g] = ts.sumDP[g] / (double)popsize;
+ mnGB[g] = ts.sumGB[g] / (double)popsize;
+ mnAlphaDB[g] = ts.sumAlphaDB[g] / (double)popsize;
+ mnBetaDB[g] = ts.sumBetaDB[g] / (double)popsize;
+ if (popsize > 1) {
+ sdDist1[g] = ts.ssqDist1[g] / (double)popsize - mnDist1[g] * mnDist1[g];
+ if (sdDist1[g] > 0.0) sdDist1[g] = sqrt(sdDist1[g]); else sdDist1[g] = 0.0;
+ sdDist2[g] = ts.ssqDist2[g] / (double)popsize - mnDist2[g] * mnDist2[g];
+ if (sdDist2[g] > 0.0) sdDist2[g] = sqrt(sdDist2[g]); else sdDist2[g] = 0.0;
+ sdProp1[g] = ts.ssqProp1[g] / (double)popsize - mnProp1[g] * mnProp1[g];
+ if (sdProp1[g] > 0.0) sdProp1[g] = sqrt(sdProp1[g]); else sdProp1[g] = 0.0;
+ sdStepL[g] = ts.ssqStepL[g] / (double)popsize - mnStepL[g] * mnStepL[g];
+ if (sdStepL[g] > 0.0) sdStepL[g] = sqrt(sdStepL[g]); else sdStepL[g] = 0.0;
+ sdRho[g] = ts.ssqRho[g] / (double)popsize - mnRho[g] * mnRho[g];
+ if (sdRho[g] > 0.0) sdRho[g] = sqrt(sdRho[g]); else sdRho[g] = 0.0;
+ sdDP[g] = ts.ssqDP[g] / (double)popsize - mnDP[g] * mnDP[g];
+ if (sdDP[g] > 0.0) sdDP[g] = sqrt(sdDP[g]); else sdDP[g] = 0.0;
+ sdGB[g] = ts.ssqGB[g] / (double)popsize - mnGB[g] * mnGB[g];
+ if (sdGB[g] > 0.0) sdGB[g] = sqrt(sdGB[g]); else sdGB[g] = 0.0;
+ sdAlphaDB[g] = ts.ssqAlphaDB[g] / (double)popsize - mnAlphaDB[g] * mnAlphaDB[g];
+ if (sdAlphaDB[g] > 0.0) sdAlphaDB[g] = sqrt(sdAlphaDB[g]); else sdAlphaDB[g] = 0.0;
+ sdBetaDB[g] = ts.ssqBetaDB[g] / (double)popsize - mnBetaDB[g] * mnBetaDB[g];
+ if (sdBetaDB[g] > 0.0) sdBetaDB[g] = sqrt(sdBetaDB[g]); else sdBetaDB[g] = 0.0;
+ }
+ }
+ }
+ if (trfr.moveModel) {
+ if (trfr.moveType == 1) {
+ outrange << "\t" << mnDP[0] << "\t" << sdDP[0];
+ outrange << "\t" << mnGB[0] << "\t" << sdGB[0];
+ outrange << "\t" << mnAlphaDB[0] << "\t" << sdAlphaDB[0];
+ outrange << "\t" << mnBetaDB[0] << "\t" << sdBetaDB[0];
+ }
+ if (trfr.moveType == 2) {
+ outrange << "\t" << mnStepL[0] << "\t" << sdStepL[0];
+ outrange << "\t" << mnRho[0] << "\t" << sdRho[0];
+ }
+ }
+ else {
+ if (trfr.sexDep) {
+ outrange << "\t" << mnDist1[0] << "\t" << sdDist1[0];
+ outrange << "\t" << mnDist1[1] << "\t" << sdDist1[1];
+ if (trfr.twinKern)
+ {
+ outrange << "\t" << mnDist2[0] << "\t" << sdDist2[0];
+ outrange << "\t" << mnDist2[1] << "\t" << sdDist2[1];
+ outrange << "\t" << mnProp1[0] << "\t" << sdProp1[0];
+ outrange << "\t" << mnProp1[1] << "\t" << sdProp1[1];
+ }
+ }
+ else { // sex-independent
+ outrange << "\t" << mnDist1[0] << "\t" << sdDist1[0];
+ if (trfr.twinKern)
+ {
+ outrange << "\t" << mnDist2[0] << "\t" << sdDist2[0];
+ outrange << "\t" << mnProp1[0] << "\t" << sdProp1[0];
+ }
+ }
+ }
+ }
+
+ if (sett.indVar) {
+ if (sett.sexDep) { // must be a sexual species
+ ngenes = 2;
+ }
+ else {
+ if (dem.repType == 0) { // asexual reproduction
+ ngenes = 1;
+ }
+ else { // sexual reproduction
+ ngenes = 1;
+ }
+ }
+ // CURRENTLY INDIVIDUAL VARIATION CANNOT BE SEX-DEPENDENT
+ double mnS0[2], mnAlpha[2], mnBeta[2], sdS0[2], sdAlpha[2], sdBeta[2];
+ for (int g = 0; g < ngenes; g++) {
+ mnS0[g] = mnAlpha[g] = mnBeta[g] = sdS0[g] = sdAlpha[g] = sdBeta[g] = 0.0;
+ // individuals may have been counted by sex if there was
+ // sex dependency in another dispersal phase
+ if (ngenes == 2) popsize = ts.ninds[g];
+ else popsize = ts.ninds[0] + ts.ninds[1];
+ if (popsize > 0) {
+ mnS0[g] = ts.sumS0[g] / (double)popsize;
+ mnAlpha[g] = ts.sumAlphaS[g] / (double)popsize;
+ mnBeta[g] = ts.sumBetaS[g] / (double)popsize;
+ if (popsize > 1) {
+ sdS0[g] = ts.ssqS0[g] / (double)popsize - mnS0[g] * mnS0[g];
+ if (sdS0[g] > 0.0) sdS0[g] = sqrt(sdS0[g]); else sdS0[g] = 0.0;
+ sdAlpha[g] = ts.ssqAlphaS[g] / (double)popsize - mnAlpha[g] * mnAlpha[g];
+ if (sdAlpha[g] > 0.0) sdAlpha[g] = sqrt(sdAlpha[g]); else sdAlpha[g] = 0.0;
+ sdBeta[g] = ts.ssqBetaS[g] / (double)popsize - mnBeta[g] * mnBeta[g];
+ if (sdBeta[g] > 0.0) sdBeta[g] = sqrt(sdBeta[g]); else sdBeta[g] = 0.0;
+ }
+ else {
+ sdS0[g] = sdAlpha[g] = sdBeta[g] = 0.0;
+ }
+ }
+ }
+ if (sett.sexDep) {
+ outrange << "\t" << mnS0[0] << "\t" << sdS0[0];
+ outrange << "\t" << mnS0[1] << "\t" << sdS0[1];
+ outrange << "\t" << mnAlpha[0] << "\t" << sdAlpha[0];
+ outrange << "\t" << mnAlpha[1] << "\t" << sdAlpha[1];
+ outrange << "\t" << mnBeta[0] << "\t" << sdBeta[0];
+ outrange << "\t" << mnBeta[1] << "\t" << sdBeta[1];
+ }
+ else {
+ outrange << "\t" << mnS0[0] << "\t" << sdS0[0];
+ outrange << "\t" << mnAlpha[0] << "\t" << sdAlpha[0];
+ outrange << "\t" << mnBeta[0] << "\t" << sdBeta[0];
+ }
+ }
+
+ }
+
+ outrange << endl;
+}
+
+// Open occupancy file, write header record and set up occupancy array
+bool Community::outOccupancyHeaders(int option)
+{
+ if (option == -999) { // close the files
+ if (outsuit.is_open()) outsuit.close();
+ if (outoccup.is_open()) outoccup.close();
+ outsuit.clear(); outoccup.clear();
+ return true;
+ }
+
+ string name, nameI;
+ simParams sim = paramsSim->getSim();
+ landParams ppLand = pLandscape->getLandParams();
+ int outrows = (sim.years / sim.outIntOcc) + 1;
+
+ name = paramsSim->getDir(2);
+ if (sim.batchMode) {
+ name += "Batch" + Int2Str(sim.batchNum) + "_";
+ name += "Sim" + Int2Str(sim.simulation) + "_Land" + Int2Str(ppLand.landNum);
+ }
+ else
+ name += "Sim" + Int2Str(sim.simulation);
+ name += "_Occupancy_Stats.txt";
+ outsuit.open(name.c_str());
+ outsuit << "Year\tMean_OccupSuit\tStd_error" << endl;
+
+ name = paramsSim->getDir(2);
+ if (sim.batchMode) {
+ name += "Batch" + Int2Str(sim.batchNum) + "_";
+ name += "Sim" + Int2Str(sim.simulation) + "_Land" + Int2Str(ppLand.landNum);
+ }
+ else
+ name += "Sim" + Int2Str(sim.simulation);
+ name += "_Occupancy.txt";
+ outoccup.open(name.c_str());
+ if (ppLand.patchModel) {
+ outoccup << "PatchID";
+ }
+ else {
+ outoccup << "X\tY";
+ }
+ for (int i = 0; i < outrows; i++)
+ outoccup << "\t" << "Year_" << i * sim.outIntOcc;
+ outoccup << endl;
+
+ // Initialise cells/patches occupancy array
+ createOccupancy(outrows, sim.reps);
+
+ return outsuit.is_open() && outoccup.is_open();
+}
+
+void Community::outOccupancy(void) {
+ landParams ppLand = pLandscape->getLandParams();
+ simParams sim = paramsSim->getSim();
+ locn loc;
+
+ int nsubcomms = (int)subComms.size();
+ for (int i = 1; i < nsubcomms; i++) { // all except matrix sub-community
+ if (ppLand.patchModel) {
+ outoccup << subComms[i]->getPatch()->getPatchNum();
+ }
+ else {
+ loc = subComms[i]->getLocn();
+ outoccup << loc.x << "\t" << loc.y;
+ }
+ for (int row = 0; row <= (sim.years / sim.outIntOcc); row++)
+ {
+ outoccup << "\t" << (double)subComms[i]->getOccupancy(row) / (double)sim.reps;
+ }
+ outoccup << endl;
+ }
+}
+
+void Community::outOccSuit(bool view) {
+ double sum, ss, mean, sd, se;
+ simParams sim = paramsSim->getSim();
+ for (int i = 0; i < (sim.years / sim.outIntOcc) + 1; i++) {
+ sum = ss = 0.0;
+ for (int rep = 0; rep < sim.reps; rep++) {
+ sum += occSuit[i][rep];
+ ss += occSuit[i][rep] * occSuit[i][rep];
+ }
+ mean = sum / (double)sim.reps;
+ sd = (ss - (sum * sum / (double)sim.reps)) / (double)(sim.reps - 1);
+ if (sd > 0.0) sd = sqrt(sd);
+ else sd = 0.0;
+ se = sd / sqrt((double)(sim.reps));
+ outsuit << i * sim.outIntOcc << "\t" << mean << "\t" << se << endl;
+ if (view) viewOccSuit(i * sim.outIntOcc, mean, se);
+ }
+
+}
+
+// Open traits file and write header record
+bool Community::outTraitsHeaders(Species* pSpecies, int landNr) {
+ return subComms[0]->outTraitsHeaders(pLandscape, pSpecies, landNr);
+}
+
+// Write records to traits file
+/* NOTE: for summary traits by rows, which is permissible for a cell-based landscape
+only, this function relies on the fact that subcommunities are created in the same
+sequence as patches, which is in asecending order of x nested within descending
+order of y
+*/
+void Community::outTraits(traitCanvas tcanv, Species* pSpecies,
+ int rep, int yr, int gen)
+{
+ simParams sim = paramsSim->getSim();
+ simView v = paramsSim->getViews();
+ landParams land = pLandscape->getLandParams();
+ traitsums* ts = 0;
+ traitsums sctraits;
+ if (sim.outTraitsRows && yr >= sim.outStartTraitRow && yr % sim.outIntTraitRow == 0) {
+ // create array of traits means, etc., one for each row
+ ts = new traitsums[land.dimY];
+ for (int y = 0; y < land.dimY; y++) {
+ for (int i = 0; i < NSEXES; i++) {
+ ts[y].ninds[i] = 0;
+ ts[y].sumD0[i] = ts[y].ssqD0[i] = 0.0;
+ ts[y].sumAlpha[i] = ts[y].ssqAlpha[i] = 0.0;
+ ts[y].sumBeta[i] = ts[y].ssqBeta[i] = 0.0;
+ ts[y].sumDist1[i] = ts[y].ssqDist1[i] = 0.0;
+ ts[y].sumDist2[i] = ts[y].ssqDist2[i] = 0.0;
+ ts[y].sumProp1[i] = ts[y].ssqProp1[i] = 0.0;
+ ts[y].sumStepL[i] = ts[y].ssqStepL[i] = 0.0;
+ ts[y].sumRho[i] = ts[y].ssqRho[i] = 0.0;
+ ts[y].sumS0[i] = ts[y].ssqS0[i] = 0.0;
+ ts[y].sumAlphaS[i] = ts[y].ssqAlphaS[i] = 0.0;
+ ts[y].sumBetaS[i] = ts[y].ssqBetaS[i] = 0.0;
+ }
+ }
+ }
+ if (v.viewTraits
+ || ((sim.outTraitsCells && yr >= sim.outStartTraitCell && yr % sim.outIntTraitCell == 0) ||
+ (sim.outTraitsRows && yr >= sim.outStartTraitRow && yr % sim.outIntTraitRow == 0)))
+ {
+ // generate output for each sub-community (patch) in the community
+ int nsubcomms = (int)subComms.size();
+ for (int i = 1; i < nsubcomms; i++) { // // all except matrix sub-community
+ sctraits = subComms[i]->outTraits(tcanv, pLandscape, rep, yr, gen, false);
+ locn loc = subComms[i]->getLocn();
+ int y = loc.y;
+ if (sim.outTraitsRows && yr >= sim.outStartTraitRow && yr % sim.outIntTraitRow == 0)
+ {
+ for (int s = 0; s < NSEXES; s++) {
+ ts[y].ninds[s] += sctraits.ninds[s];
+ ts[y].sumD0[s] += sctraits.sumD0[s]; ts[y].ssqD0[s] += sctraits.ssqD0[s];
+ ts[y].sumAlpha[s] += sctraits.sumAlpha[s]; ts[y].ssqAlpha[s] += sctraits.ssqAlpha[s];
+ ts[y].sumBeta[s] += sctraits.sumBeta[s]; ts[y].ssqBeta[s] += sctraits.ssqBeta[s];
+ ts[y].sumDist1[s] += sctraits.sumDist1[s]; ts[y].ssqDist1[s] += sctraits.ssqDist1[s];
+ ts[y].sumDist2[s] += sctraits.sumDist2[s]; ts[y].ssqDist2[s] += sctraits.ssqDist2[s];
+ ts[y].sumProp1[s] += sctraits.sumProp1[s]; ts[y].ssqProp1[s] += sctraits.ssqProp1[s];
+ ts[y].sumStepL[s] += sctraits.sumStepL[s]; ts[y].ssqStepL[s] += sctraits.ssqStepL[s];
+ ts[y].sumRho[s] += sctraits.sumRho[s]; ts[y].ssqRho[s] += sctraits.ssqRho[s];
+ ts[y].sumS0[s] += sctraits.sumS0[s]; ts[y].ssqS0[s] += sctraits.ssqS0[s];
+ ts[y].sumAlphaS[s] += sctraits.sumAlphaS[s]; ts[y].ssqAlphaS[s] += sctraits.ssqAlphaS[s];
+ ts[y].sumBetaS[s] += sctraits.sumBetaS[s]; ts[y].ssqBetaS[s] += sctraits.ssqBetaS[s];
+ }
+ }
+ }
+ if (nsubcomms > 0 && sim.outTraitsRows
+ && yr >= sim.outStartTraitRow && yr % sim.outIntTraitRow == 0) {
+ for (int y = 0; y < land.dimY; y++) {
+ if ((ts[y].ninds[0] + ts[y].ninds[1]) > 0) {
+ writeTraitsRows(pSpecies, rep, yr, gen, y, ts[y]);
+ }
+ }
+ }
+ }
+ if (ts != 0) { delete[] ts; ts = 0; }
+}
+
+// Write records to trait rows file
+void Community::writeTraitsRows(Species* pSpecies, int rep, int yr, int gen, int y,
+ traitsums ts)
+{
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ double mn, sd;
+
+ // calculate population size in case one phase is sex-dependent and the other is not
+ // (in which case numbers of individuals are recorded by sex)
+ int popsize = ts.ninds[0] + ts.ninds[1];
+ outtraitsrows << rep << "\t" << yr << "\t" << gen
+ << "\t" << y;
+ if ((emig.indVar && emig.sexDep) || (trfr.indVar && trfr.sexDep))
+ outtraitsrows << "\t" << ts.ninds[0] << "\t" << ts.ninds[1];
+ else
+ outtraitsrows << "\t" << popsize;
+
+ if (emig.indVar) {
+ if (emig.sexDep) {
+ if (ts.ninds[0] > 0) mn = ts.sumD0[0] / (double)ts.ninds[0]; else mn = 0.0;
+ if (ts.ninds[0] > 1) sd = ts.ssqD0[0] / (double)ts.ninds[0] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (ts.ninds[1] > 0) mn = ts.sumD0[1] / (double)ts.ninds[1]; else mn = 0.0;
+ if (ts.ninds[1] > 1) sd = ts.ssqD0[1] / (double)ts.ninds[1] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (emig.densDep) {
+ if (ts.ninds[0] > 0) mn = ts.sumAlpha[0] / (double)ts.ninds[0]; else mn = 0.0;
+ if (ts.ninds[0] > 1) sd = ts.ssqAlpha[0] / (double)ts.ninds[0] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (ts.ninds[1] > 0) mn = ts.sumAlpha[1] / (double)ts.ninds[1]; else mn = 0.0;
+ if (ts.ninds[1] > 1) sd = ts.ssqAlpha[1] / (double)ts.ninds[1] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (ts.ninds[0] > 0) mn = ts.sumBeta[0] / (double)ts.ninds[0]; else mn = 0.0;
+ if (ts.ninds[0] > 1) sd = ts.ssqBeta[0] / (double)ts.ninds[0] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (ts.ninds[1] > 0) mn = ts.sumBeta[1] / (double)ts.ninds[1]; else mn = 0.0;
+ if (ts.ninds[1] > 1) sd = ts.ssqBeta[1] / (double)ts.ninds[1] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ }
+ }
+ else { // no sex dependence in emigration
+ if (popsize > 0) mn = ts.sumD0[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqD0[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (emig.densDep) {
+ if (popsize > 0) mn = ts.sumAlpha[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqAlpha[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (popsize > 0) mn = ts.sumBeta[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqBeta[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ }
+ }
+ }
+
+ if (trfr.indVar) {
+ if (trfr.moveModel) {
+ if (trfr.moveType == 2) { // CRW
+ // NB - CURRENTLY CANNOT BE SEX-DEPENDENT...
+ if (popsize > 0) mn = ts.sumStepL[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqStepL[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (popsize > 0) mn = ts.sumRho[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqRho[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ }
+ }
+ else { // dispersal kernel
+ if (trfr.sexDep) {
+ if (ts.ninds[0] > 0) mn = ts.sumDist1[0] / (double)ts.ninds[0]; else mn = 0.0;
+ if (ts.ninds[0] > 1) sd = ts.ssqDist1[0] / (double)ts.ninds[0] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (ts.ninds[1] > 0) mn = ts.sumDist1[1] / (double)ts.ninds[1]; else mn = 0.0;
+ if (ts.ninds[1] > 1) sd = ts.ssqDist1[1] / (double)ts.ninds[1] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (trfr.twinKern)
+ {
+ if (ts.ninds[0] > 0) mn = ts.sumDist2[0] / (double)ts.ninds[0]; else mn = 0.0;
+ if (ts.ninds[0] > 1) sd = ts.ssqDist2[0] / (double)ts.ninds[0] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (ts.ninds[1] > 0) mn = ts.sumDist2[1] / (double)ts.ninds[1]; else mn = 0.0;
+ if (ts.ninds[1] > 1) sd = ts.ssqDist2[1] / (double)ts.ninds[1] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (ts.ninds[0] > 0) mn = ts.sumProp1[0] / (double)ts.ninds[0]; else mn = 0.0;
+ if (ts.ninds[0] > 1) sd = ts.ssqProp1[0] / (double)ts.ninds[0] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (ts.ninds[1] > 0) mn = ts.sumProp1[1] / (double)ts.ninds[1]; else mn = 0.0;
+ if (ts.ninds[1] > 1) sd = ts.ssqProp1[1] / (double)ts.ninds[1] - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ }
+ }
+ else { // sex-independent
+ if (popsize > 0) mn = ts.sumDist1[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqDist1[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (trfr.twinKern)
+ {
+ if (popsize > 0) mn = ts.sumDist2[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqDist2[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (popsize > 0) mn = ts.sumProp1[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqProp1[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ }
+ }
+ }
+ }
+
+ if (sett.indVar) {
+ if (popsize > 0) mn = ts.sumS0[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqS0[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (popsize > 0) mn = ts.sumAlphaS[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqAlphaS[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ if (popsize > 0) mn = ts.sumBetaS[0] / (double)popsize; else mn = 0.0;
+ if (popsize > 1) sd = ts.ssqBetaS[0] / (double)popsize - mn * mn; else sd = 0.0;
+ if (sd > 0.0) sd = sqrt(sd); else sd = 0.0;
+ outtraitsrows << "\t" << mn << "\t" << sd;
+ // }
+ }
+
+ outtraitsrows << endl;
+}
+
+// Open trait rows file and write header record
+bool Community::outTraitsRowsHeaders(Species* pSpecies, int landNr) {
+
+ if (landNr == -999) { // close file
+ if (outtraitsrows.is_open()) outtraitsrows.close();
+ outtraitsrows.clear();
+ return true;
+ }
+
+ string name;
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ simParams sim = paramsSim->getSim();
+
+ string DirOut = paramsSim->getDir(2);
+ if (sim.batchMode) {
+ name = DirOut
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation) + "_Land" + Int2Str(landNr) + "_TraitsXrow.txt";
+ }
+ else {
+ name = DirOut + "Sim" + Int2Str(sim.simulation) + "_TraitsXrow.txt";
+ }
+ outtraitsrows.open(name.c_str());
+
+ outtraitsrows << "Rep\tYear\tRepSeason\ty";
+ if ((emig.indVar && emig.sexDep) || (trfr.indVar && trfr.sexDep))
+ outtraitsrows << "\tN_females\tN_males";
+ else
+ outtraitsrows << "\tN";
+
+ if (emig.indVar) {
+ if (emig.sexDep) {
+ if (emig.densDep) {
+ outtraitsrows << "\tF_meanD0\tF_stdD0\tM_meanD0\tM_stdD0";
+ outtraitsrows << "\tF_meanAlpha\tF_stdAlpha\tM_meanAlpha\tM_stdAlpha";
+ outtraitsrows << "\tF_meanBeta\tF_stdBeta\tM_meanBeta\tM_stdBeta";
+ }
+ else {
+ outtraitsrows << "\tF_meanEP\tF_stdEP\tM_meanEP\tM_stdEP";
+ }
+ }
+ else {
+ if (emig.densDep) {
+ outtraitsrows << "\tmeanD0\tstdD0\tmeanAlpha\tstdAlpha";
+ outtraitsrows << "\tmeanBeta\tstdBeta";
+ }
+ else {
+ outtraitsrows << "\tmeanEP\tstdEP";
+ }
+ }
+ }
+ if (trfr.indVar) {
+ if (trfr.moveModel) {
+ if (trfr.moveType == 2) {
+ outtraitsrows << "\tmeanStepLength\tstdStepLength\tmeanRho\tstdRho";
+ }
+ }
+ else { // dispersal kernel
+ if (trfr.sexDep) {
+ outtraitsrows << "\tF_mean_distI\tF_std_distI\tM_mean_distI\tM_std_distI";
+ if (trfr.twinKern)
+ outtraitsrows << "\tF_mean_distII\tF_std_distII\tM_mean_distII\tM_std_distII"
+ << "\tF_meanPfirstKernel\tF_stdPfirstKernel"
+ << "\tM_meanPfirstKernel\tM_stdPfirstKernel";
+ }
+ else {
+ outtraitsrows << "\tmean_distI\tstd_distI";
+ if (trfr.twinKern)
+ outtraitsrows << "\tmean_distII\tstd_distII\tmeanPfirstKernel\tstdPfirstKernel";
+ }
+ }
+ }
+
+ if (sett.indVar) {
+ outtraitsrows << "\tmeanS0\tstdS0";
+ outtraitsrows << "\tmeanAlphaS\tstdAlphaS";
+ outtraitsrows << "\tmeanBetaS\tstdBetaS";
+ }
+ outtraitsrows << endl;
+
+ return outtraitsrows.is_open();
+
+}
+
+#if RS_RCPP && !R_CMD
+Rcpp::IntegerMatrix Community::addYearToPopList(int rep, int yr) { // TODO: define new simparams to control start and interval of output
+
+ landParams ppLand = pLandscape->getLandParams();
+ Rcpp::IntegerMatrix pop_map_year(ppLand.dimY, ppLand.dimX);
+ intptr patch = 0;
+ Patch* pPatch = 0;
+ intptr subcomm = 0;
+ SubCommunity* pSubComm = 0;
+ popStats pop;
+ pop.nInds = pop.nAdults = pop.nNonJuvs = 0;
+
+ for (int y = 0; y < ppLand.dimY; y++) {
+ for (int x = 0; x < ppLand.dimX; x++) {
+ Cell* pCell = pLandscape->findCell(x, y);
+ if (pCell == 0) { // no-data cell
+ pop_map_year(ppLand.dimY - 1 - y, x) = NA_INTEGER;
+ }
+ else {
+ patch = pCell->getPatch();
+ if (patch == 0) { // matrix cell
+ pop_map_year(ppLand.dimY - 1 - y, x) = 0;
+ }
+ else {
+ pPatch = (Patch*)patch;
+ subcomm = pPatch->getSubComm();
+ if (subcomm == 0) { // check if sub-community exists
+ pop_map_year(ppLand.dimY - 1 - y, x) = 0;
+ }
+ else {
+ pSubComm = (SubCommunity*)subcomm;
+ pop = pSubComm->getPopStats();
+ pop_map_year(ppLand.dimY - 1 - y, x) = pop.nInds; // use indices like this because matrix gets transposed upon casting it into a raster on R-level
+ }
+ }
+ }
+ }
+ }
+ return pop_map_year;
+}
+#endif
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
diff --git a/src/RScore/Community.h b/src/RScore/Community.h
new file mode 100644
index 00000000..c55b3338
--- /dev/null
+++ b/src/RScore/Community.h
@@ -0,0 +1,223 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 Community
+
+Implements the Community class
+
+There is ONLY ONE instance of a Community in an individual replicate simulation.
+It holds a SubCommunity for each Patch in the Landscape (including the matrix),
+and is thus the highest-level entity accessed for most processing concerned with
+simulated populations.
+
+Optionally, the Community maintains a record of the occupancy of suitable cells
+or patches during the course of simulation of multiple replicates.
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Peer G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 25 June 2021 by Anne-Kathleen Malchow
+
+------------------------------------------------------------------------------*/
+
+#ifndef CommunityH
+#define CommunityH
+
+#include
+#include
+using namespace std;
+
+#include "SubCommunity.h"
+#include "Landscape.h"
+#include "Patch.h"
+#include "Cell.h"
+#include "Species.h"
+
+//---------------------------------------------------------------------------
+struct commStats {
+int ninds,nnonjuvs,suitable,occupied;
+int minX,maxX,minY,maxY;
+};
+
+class Community {
+
+public:
+ Community(Landscape*);
+ ~Community(void);
+ SubCommunity* addSubComm(Patch*,int);
+ // functions to manage populations occurring in the community
+ void initialise(
+ Species*, // pointer to Species
+ int // year (relevent only for seedType == 2)
+ );
+ void addManuallySelected(void);
+ void resetPopns(void);
+ void localExtinction(int);
+ void patchChanges(void);
+ void reproduction(
+ int // year
+ );
+ void emigration(void);
+#if RS_RCPP // included also SEASONAL
+ void dispersal(
+ short, // landscape change index
+ short // season / year
+ );
+#else
+ void dispersal(
+ short // landscape change index
+ );
+#endif // SEASONAL || RS_RCPP
+
+ void survival(
+ short, // part: 0 = determine survival & development,
+ // 1 = apply survival changes to the population
+ short, // option0: 0 = stage 0 (juveniles) only )
+ // 1 = all stages ) used by part 0 only
+ // 2 = stage 1 and above (all non-juvs) )
+ short // option1: 0 - development only (when survival is annual)
+ // 1 - development and survival
+ );
+ void ageIncrement(void);
+ int totalInds(void);
+ Population* findPop( // Find the population of a given species in a given patch
+ Species*, // pointer to Species
+ Patch* // pointer to Patch
+ );
+ commStats getStats(void);
+ void createOccupancy(
+ int, // no. of rows = (no. of years / interval) + 1
+ int // no. of replicates
+ );
+ void updateOccupancy(
+ int, // row = (no. of years / interval)
+ int // replicate
+ );
+ void deleteOccupancy(
+ int // no. of rows (as above)
+ );
+
+ bool outRangeHeaders( // Open range file and write header record
+ Species*, // pointer to Species
+ int // Landscape number (-999 to close the file)
+ );
+ void outRange( // Write record to range file
+ Species*, // pointer to Species
+ int, // replicate
+ int, // year
+ int // generation
+ );
+ bool outPopHeaders( // Open population file and write header record
+ Species*, // pointer to Species
+ int // option: -999 to close the file
+ );
+ void outPop( // Write records to population file
+ int, // replicate
+ int, // year
+ int // generation
+ );
+
+ void outInds( // Write records to individuals file
+ int, // replicate
+ int, // year
+ int, // generation
+ int // Landscape number (>= 0 to open the file, -999 to close the file
+ // -1 to write data records)
+ );
+ void outGenetics( // Write records to genetics file
+ int, // replicate
+ int, // year
+ int, // generation
+ int // Landscape number (>= 0 to open the file, -999 to close the file
+ // -1 to write data records)
+ );
+ // Open occupancy file, write header record and set up occupancy array
+ bool outOccupancyHeaders(
+ int // option: -999 to close the file
+ );
+ void outOccupancy(void);
+ void outOccSuit(
+ bool // TRUE if occupancy graph is to be viewed on screen
+ );
+ void viewOccSuit( // Update the occupancy graph on the screen
+ // NULL for the batch version
+ int, // year
+ double, // mean occupancy
+ double // standard error of occupancy
+ );
+ bool outTraitsHeaders( // Open traits file and write header record
+ Species*, // pointer to Species
+ int // Landscape number (-999 to close the file)
+ );
+ bool outTraitsRowsHeaders( // Open trait rows file and write header record
+ Species*, // pointer to Species
+ int // Landscape number (-999 to close the file)
+ );
+ void outTraits( // Write records to traits file
+ traitCanvas,// pointers to canvases for drawing variable traits
+ // see SubCommunity.h
+ // in the batch version, these are replaced by integers set to zero
+ Species*, // pointer to Species
+ int, // replicate
+ int, // year
+ int // generation
+ );
+ void writeTraitsRows( // Write records to trait rows file
+ Species*, // pointer to Species
+ int, // replicate
+ int, // year
+ int, // generation
+ int, // row number (Y cell co-ordinate)
+ traitsums // structure holding sums of trait genes for dispersal (see Population.h)
+ );
+ void draw( // Draw the Community on the landscape map and optionally save the map
+ // NULL for the batch version
+ int, // replicate
+ int, // year
+ int, // generation
+ int // Landscape number
+ );
+#if RS_RCPP && !R_CMD
+ Rcpp::IntegerMatrix addYearToPopList(int,int);
+#endif
+
+private:
+ Landscape *pLandscape;
+ int indIx; // index used to apply initial individuals
+ float **occSuit; // occupancy of suitable cells / patches
+ std::vector subComms;
+
+};
+
+extern paramSim *paramsSim;
+extern paramInit *paramsInit;
+
+
+//---------------------------------------------------------------------------
+#endif
diff --git a/src/RScore/FractalGenerator.cpp b/src/RScore/FractalGenerator.cpp
new file mode 100644
index 00000000..7a5ccc3a
--- /dev/null
+++ b/src/RScore/FractalGenerator.cpp
@@ -0,0 +1,243 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+//---------------------------------------------------------------------------
+
+#include "FractalGenerator.h"
+//---------------------------------------------------------------------------
+
+vector patches;
+
+//----- Landscape creation --------------------------------------------------
+
+land::land(): x_coord(0), y_coord(0), value(0.0), avail(0) {}
+
+bool compare(const land& z, const land& zz) //compares only the values of the cells
+{
+return z.value < zz.value;
+}
+
+vector& fractal_landscape(int X,int Y,double Hurst,double prop,
+ double maxValue,double minValue)
+{
+#if RSDEBUG
+DEBUGLOG << "fractal_landscape(): X=" << X << " Y=" << Y
+ << " Hurst=" << Hurst << " prop=" << prop
+ << " maxValue=" << maxValue << " minValue=" << minValue
+ << endl;
+#endif
+
+int ii, jj, x, y;
+int ix, iy;
+//int x0, y0, size, kx, kx2, ky, ky2;
+int kx,kx2,ky,ky2;
+
+double range; //range to draw random numbers at each iteration
+double nx, ny;
+double i, j;
+int Nx = X;
+int Ny = Y;
+
+double ran[5]; // to store each time the 5 random numbers for the random displacement
+
+int Nno; // number of cells NON suitable as habitat
+
+// exponents used to obtain the landscape dimensions
+double pow2x = log(((double)X-1.0))/log(2.0);
+double pow2y = log(((double)Y-1.0))/log(2.0);
+
+double **arena = new double *[X];
+for(ii = 0; ii < X; ii++) {
+ arena[ii] = new double[Y];
+}
+
+patches.clear();
+// initialise all the landscape with zeroes
+for (jj = 0; jj < X; jj++) {
+ for (ii = 0; ii < Y; ii++) {
+ arena[jj][ii]=0;
+ }
+}
+
+// initialisation of the four corners
+arena[0][0] = 1.0 + pRandom->Random() * (maxValue-1.0);
+arena[0][Y-1] = 1.0 + pRandom->Random() * (maxValue-1.0);
+arena[X-1][0] = 1.0 + pRandom->Random() * (maxValue-1.0);
+arena[X-1][Y-1] = 1.0 + pRandom->Random() * (maxValue-1.0);
+
+/////////////MIDPOINT DISPLACEMENT ALGORITHM//////////////////////////////////
+kx = (Nx-1) / 2;
+kx2 = 2 * kx;
+ky = (Ny-1) / 2;
+ky2 = 2 * ky;
+
+for (ii = 0; ii < 5; ii++) //random displacement
+{
+ ran[ii] = 1.0 + pRandom->Random() * (maxValue-1.0);
+}
+
+//The diamond step:
+arena[kx][ky] = ((arena[0][0] + arena[0][ky2] + arena[kx2][0] + arena[kx2][ky2])/4) + ran[0];
+
+//The square step:
+//left
+arena[0][ky] = ((arena[0][0] +arena[0][ky2] + arena[kx][ky]) / 3) + ran[1];
+//top
+arena[kx][0] = ((arena[0][0] + arena[kx][ky] + arena[kx2][0]) / 3) + ran[2];
+//right
+arena[kx2][ky] = ((arena[kx2][0] + arena[kx][ky] + arena[kx2][ky2]) / 3) + ran[3];
+//bottom
+arena[kx][ky2] = ((arena[0][ky2] + arena[kx][ky] +arena[kx2][ky2]) / 3) + ran[4];
+
+range = maxValue*pow(2,-Hurst);
+
+i = pow2x-1;
+j = pow2y-1;
+
+while (i > 0) {
+ nx = pow(2,i)+1;
+ kx = (int)((nx-1) / 2);
+ kx2 = 2 * kx;
+
+ ny = pow(2,j)+1;
+ ky = (int)((ny-1) / 2);
+ ky2 = 2 * ky;
+
+ ix = 0;
+ while (ix <= (Nx-nx)) {
+ iy = 0;
+ while (iy <= (Ny-ny)) {
+ for (ii = 0; ii < 5; ii++) //random displacement
+ {
+ ran[ii] = (int)(pRandom->Random() * 2.0 * range - range);
+ }
+ //The diamond step:
+
+ arena[ix+kx][iy+ky] = ((arena[ix][iy] + arena[ix][iy+ky2] + arena[ix+ky2][iy]
+ + arena[ix+kx2][iy+ky2])/ 4) + ran[0];
+ if (arena[ix+kx][iy+ky] < 1) arena[ix+kx][iy+ky] = 1;
+
+ //The square step:
+ //left
+ arena[ix][iy+ky] =((arena[ix][iy] +arena[ix][iy+ky2] + arena[ix+kx][iy+ky])/3)
+ + ran[1];
+ if (arena[ix][iy+ky] < 1) arena[ix][iy+ky] = 1;
+ //top
+ arena[ix+kx][iy] =((arena[ix][iy] + arena[ix+kx][iy+ky] + arena[ix+kx2][iy])/3)
+ + ran[2];
+ if (arena[ix+kx][iy] < 1) arena[ix+kx][iy] = 1;
+ //right
+ arena[ix+kx2][iy+ky] = ((arena[ix+kx2][iy] + arena[ix+kx][iy+ky] +
+ arena[ix+kx2][iy+ky2]) / 3) + ran[3];
+ if (arena[ix+kx2][iy+ky] < 1) arena[ix+kx2][iy+ky] = 1;
+ //bottom
+ arena[ix+kx][iy+ky2] = ((arena[ix][iy+ky2] + arena[ix+kx][iy+ky] +
+ arena[ix+kx2][iy+ky2]) / 3) + ran[4];
+ if (arena[ix+kx][iy+ky2] < 1) arena[ix+kx][iy+ky2] = 1;
+
+ iy += ((int)ny-1);
+ }
+ ix += ((int)nx-1);
+ }
+ if (i==j) j--;
+ i--;
+
+ range = range*pow(2,-Hurst); //reduce the random number range
+}
+
+// Now all the cells will be sorted and the Nno cells with the lower carrying
+// capacity will be set as matrix, i.e. with K = 0
+
+land *patch;
+
+for (x = 0; x < X; x++) // put all the cells with their values in a vector
+{
+ for (y = 0; y < Y; y++)
+ {
+ patch = new land;
+ patch->x_coord = x;
+ patch->y_coord = y;
+ patch->value = (float)arena[x][y];
+ patch->avail = 1;
+
+ patches.push_back(*patch);
+
+ delete patch;
+ }
+}
+
+
+sort(patches.begin(),patches.end(),compare); // sorts the vector
+
+Nno = (int)(prop*X*Y);
+for (ii = 0; ii < Nno; ii++)
+{
+ patches[ii].value = 0.0;
+ patches[ii].avail = 0;
+}
+
+double min = (double)patches[Nno].value; // variables for the rescaling
+double max = (double)patches[X*Y-1].value;
+
+double diff = max - min;
+double diffK = maxValue-minValue;
+double new_value;
+
+vector::iterator iter = patches.begin();
+while (iter != patches.end())
+{
+ if (iter->value > 0) // rescale to a range of K between Kmin and Kmax
+ {
+ new_value = maxValue - diffK * (max - (double)iter->value) / diff;
+
+ iter->value = (float)new_value;
+ }
+ else iter->value = 0;
+
+ iter++;
+}
+
+if (arena != NULL) {
+#if RSDEBUG
+//DebugGUI(("fractal_landscape(): arena=" + Int2Str((int)arena)
+// + " X=" + Int2Str(X) + " Y=" + Int2Str(Y)
+// ).c_str());
+#endif
+ for(ii = 0; ii < X; ii++) {
+#if RSDEBUG
+//DebugGUI(("fractal_landscape(): ii=" + Int2Str(ii)
+// + " arena[ii]=" + Int2Str((int)arena[ii])
+// ).c_str());
+#endif
+ delete[] arena[ii];
+ }
+ delete[] arena;
+}
+
+return patches;
+
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
diff --git a/src/RScore/FractalGenerator.h b/src/RScore/FractalGenerator.h
new file mode 100644
index 00000000..24acbc79
--- /dev/null
+++ b/src/RScore/FractalGenerator.h
@@ -0,0 +1,85 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 FractalGenerator
+
+Implements the midpoint displacement algorithm for generating a fractal Landscape,
+following:
+
+Saupe, D. (1988). Algorithms for random fractals. In: The Science of Fractal Images
+(eds. Pietgen, H.O. & Saupe, D.). Springer, New York, pp. 71113.
+
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Peer G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 15 July 2021 by Anne-Kathleen Malchow
+
+------------------------------------------------------------------------------*/
+
+#ifndef FractalGeneratorH
+#define FractalGeneratorH
+
+#include
+#include
+//using namespace std;
+
+#include "Parameters.h"
+
+class land
+{
+ public:
+ land();
+ int x_coord;
+ int y_coord;
+ float value;
+ int avail; // if 0 the patch is not available as habitat, if 1 it is
+ private:
+};
+
+// IMPORTANT NOTE: X AND Y ARE TRANSPOSED, i.e. X IS THE VERTICAL CO-ORDINATE
+// ==========================================================================
+
+vector& fractal_landscape(
+ int, // X dimension (Y of LandScape)
+ int, // Y dimension (X of LandScape)
+ double, // Hurst exponent
+ double, // proportion of NON-suitable habitat
+ double, // maximum quality value
+ double // minimum quality value
+);
+bool compare(const land&, const land&);
+
+extern RSrandom *pRandom;
+#if RSDEBUG
+extern void DebugGUI(string);
+#endif
+
+//---------------------------------------------------------------------------
+#endif
diff --git a/src/RScore/Genome.cpp b/src/RScore/Genome.cpp
new file mode 100644
index 00000000..59a68b1a
--- /dev/null
+++ b/src/RScore/Genome.cpp
@@ -0,0 +1,419 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+#include "Genome.h"
+//---------------------------------------------------------------------------
+
+ofstream outGenetic;
+
+//---------------------------------------------------------------------------
+
+Chromosome::Chromosome(int nloc)
+{
+ if (nloc > 0) nloci = nloc; else nloci = 1;
+ pLoci = new locus[nloci];
+ for (int i = 0; i < nloci; i++) {
+ pLoci[i].allele[0] = pLoci[i].allele[1] = 0;
+ }
+}
+
+Chromosome::~Chromosome() {
+ if (pLoci != 0) {
+ delete[] pLoci; pLoci = NULL;
+ }
+}
+
+short Chromosome::nLoci(void) { return nloci; }
+
+locus Chromosome::alleles(const int loc) { // return allele values at a specified locus
+ locus l; l.allele[0] = l.allele[1] = 0;
+ if (loc >= 0 && loc < nloci) {
+ l.allele[0] = pLoci[loc].allele[0]; l.allele[1] = pLoci[loc].allele[1];
+ }
+ return l;
+}
+
+double Chromosome::additive(const bool diploid) {
+ int sum = 0;
+ for (int i = 0; i < nloci; i++) {
+ sum += pLoci[i].allele[0];
+ if (diploid) sum += pLoci[i].allele[1];
+ }
+ return (double)sum / INTBASE;
+}
+
+double Chromosome::meanvalue(const bool diploid) {
+ int sum = 0;
+ double mean;
+ for (int i = 0; i < nloci; i++) {
+ sum += pLoci[i].allele[0];
+ if (diploid) sum += pLoci[i].allele[1];
+ }
+ mean = (double)sum / (double)nloci;
+ if (diploid) mean /= 2.0;
+ mean /= INTBASE;
+ return mean;
+}
+
+double Chromosome::additive(const short loc, const bool diploid) {
+ int sum = 0;
+ sum += pLoci[loc].allele[0];
+ if (diploid) sum += pLoci[loc].allele[1];
+ return (double)sum / INTBASE;
+}
+
+// Set up chromosome at simulation initialisation
+void Chromosome::initialise(const double mean, const double sd,
+ const bool diploid) {
+ double avalue;
+ double intbase = INTBASE;
+
+ for (int i = 0; i < nloci; i++) {
+ avalue = pRandom->Normal(mean, sd);
+ if (avalue > 0.0)
+ pLoci[i].allele[0] = (int)(avalue * intbase + 0.5);
+ else
+ pLoci[i].allele[0] = (int)(avalue * intbase - 0.5);
+ if (diploid) {
+ avalue = pRandom->Normal(mean, sd);
+ if (avalue > 0.0)
+ pLoci[i].allele[1] = (int)(avalue * intbase + 0.5);
+ else
+ pLoci[i].allele[1] = (int)(avalue * intbase - 0.5);
+ }
+ }
+
+}
+
+// Set up specified locus at simulation initialisation
+void Chromosome::initialise(const short locus, const short posn, const int aval)
+{
+ // note that initialising value is ADDED to current value to allow for pleiotropy
+ pLoci[locus].allele[posn] += aval;
+}
+
+// Inherit from specified parent
+void Chromosome::inherit(const Chromosome* parentChr, const short posn, const short nloc,
+ const double probmutn, const double probcross, const double mutnSD, const bool diploid)
+{
+ // NOTE: At present for diploid genome, presence of crossover is determined at each
+ // locus (except first). However, Roslyn has shown that it is more efficient to sample
+ // crossover locations from geometric distribution if number of loci is large.
+ // HOW LARGE IS 'LARGE' IN THIS CASE?...
+
+ int ix = 0; // indexes maternal and paternal strands
+ if (diploid) ix = pRandom->Bernoulli(0.5); // start index at random
+ for (int i = 0; i < nloc; i++) {
+ if (diploid) {
+ pLoci[i].allele[posn] = parentChr->pLoci[i].allele[ix];
+ if (pRandom->Bernoulli(probcross)) { // crossover occurs
+ if (ix == 0) ix = 1; else ix = 0;
+ }
+ }
+ else
+ pLoci[i].allele[posn] = parentChr->pLoci[i].allele[0];
+ if (pRandom->Bernoulli(probmutn)) { // mutation occurs
+ double intbase = INTBASE;
+#if RSDEBUG
+ int oldval = pLoci[i].allele[posn];
+#endif
+ double mutnvalue = pRandom->Normal(0, mutnSD);
+ if (mutnvalue > 0.0)
+ pLoci[i].allele[posn] += (int)(intbase * mutnvalue + 0.5);
+ else
+ pLoci[i].allele[posn] += (int)(intbase * mutnvalue - 0.5);
+#if RSDEBUG
+ MUTNLOG << mutnvalue << " " << oldval << " " << pLoci[i].allele[posn] << " " << endl;
+#endif
+ }
+ }
+}
+
+
+//---------------------------------------------------------------------------
+
+// NB THIS FUNCTION IS CURRENTLY NOT BEING CALLED TO CONSTRUCT AN INSTANCE OF Genome
+// Genome(int) IS USED INSTEAD
+
+Genome::Genome() {
+ pChromosome = NULL;
+ nChromosomes = 0;
+}
+
+// Set up new genome at initialisation for 1 chromosome per trait
+Genome::Genome(int nchromosomes, int nloci, bool d) {
+
+ diploid = d;
+ if (nchromosomes > 0) nChromosomes = nchromosomes; else nChromosomes = 1;
+ pChromosome = new Chromosome * [nChromosomes];
+ for (int i = 0; i < nChromosomes; i++) {
+ pChromosome[i] = new Chromosome(nloci);
+ }
+
+}
+
+// Set up new genome at initialisation for trait mapping
+Genome::Genome(Species* pSpecies) {
+ int nloci;
+ nChromosomes = pSpecies->getNChromosomes();
+ diploid = pSpecies->isDiploid();
+ pChromosome = new Chromosome * [nChromosomes];
+ for (int i = 0; i < nChromosomes; i++) {
+ nloci = pSpecies->getNLoci(i);
+ pChromosome[i] = new Chromosome(nloci);
+ }
+}
+
+// Inherit genome from parent(s)
+Genome::Genome(Species* pSpecies, Genome* mother, Genome* father)
+{
+ genomeData gen = pSpecies->getGenomeData();
+
+ nChromosomes = mother->nChromosomes;
+ diploid = mother->diploid;
+ pChromosome = new Chromosome * [nChromosomes];
+
+ for (int i = 0; i < nChromosomes; i++) {
+ pChromosome[i] = new Chromosome(mother->pChromosome[i]->nLoci());
+ inherit(mother, 0, i, gen.probMutn, gen.probCrossover, gen.mutationSD);
+ if (diploid) {
+ if (father == 0) { // species is hermaphrodite - inherit again from mother
+ inherit(mother, 1, i, gen.probMutn, gen.probCrossover, gen.mutationSD);
+ }
+ else inherit(father, 1, i, gen.probMutn, gen.probCrossover, gen.mutationSD);
+ }
+ }
+
+}
+
+Genome::~Genome() {
+
+ if (pChromosome == NULL) return;
+
+ for (int i = 0; i < nChromosomes; i++) {
+ delete pChromosome[i];
+ }
+ delete[] pChromosome;
+
+}
+
+//---------------------------------------------------------------------------
+
+void Genome::setDiploid(bool dip) { diploid = dip; }
+bool Genome::isDiploid(void) { return diploid; }
+short Genome::getNChromosomes(void) { return nChromosomes; }
+
+//---------------------------------------------------------------------------
+
+// Inherit from specified parent
+void Genome::inherit(const Genome* parent, const short posn, const short chr,
+ const double probmutn, const double probcross, const double mutnSD)
+{
+ pChromosome[chr]->inherit(parent->pChromosome[chr], posn, parent->pChromosome[chr]->nLoci(),
+ probmutn, probcross, mutnSD, diploid);
+
+}
+
+void Genome::outGenHeaders(const int rep, const int landNr, const bool xtab)
+{
+
+ if (landNr == -999) { // close file
+ if (outGenetic.is_open()) {
+ outGenetic.close(); outGenetic.clear();
+ }
+ return;
+ }
+
+ string name;
+ simParams sim = paramsSim->getSim();
+
+ if (sim.batchMode) {
+ name = paramsSim->getDir(2)
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation)
+ + "_Land" + Int2Str(landNr) + "_Rep" + Int2Str(rep) + "_Genetics.txt";
+ }
+ else {
+ name = paramsSim->getDir(2) + "Sim" + Int2Str(sim.simulation)
+ + "_Rep" + Int2Str(rep) + "_Genetics.txt";
+ }
+ outGenetic.open(name.c_str());
+
+ outGenetic << "Rep\tYear\tSpecies\tIndID";
+ if (xtab) {
+ for (int i = 0; i < nChromosomes; i++) {
+ int nloci = pChromosome[i]->nLoci();
+ for (int j = 0; j < nloci; j++) {
+ outGenetic << "\tChr" << i << "Loc" << j << "Allele0";
+ if (diploid) outGenetic << "\tChr" << i << "Loc" << j << "Allele1";
+ }
+ }
+ outGenetic << endl;
+ }
+ else {
+ outGenetic << "\tChromosome\tLocus\tAllele0";
+ if (diploid) outGenetic << "\tAllele1";
+ outGenetic << endl;
+ }
+
+}
+
+void Genome::outGenetics(const int rep, const int year, const int spnum,
+ const int indID, const bool xtab)
+{
+ locus l;
+ if (xtab) {
+ outGenetic << rep << "\t" << year << "\t" << spnum << "\t" << indID;
+ for (int i = 0; i < nChromosomes; i++) {
+ int nloci = pChromosome[i]->nLoci();
+ for (int j = 0; j < nloci; j++) {
+ l = pChromosome[i]->alleles(j);
+ outGenetic << "\t" << l.allele[0];
+ if (diploid) outGenetic << "\t" << l.allele[1];
+ }
+ }
+ outGenetic << endl;
+ }
+ else {
+ for (int i = 0; i < nChromosomes; i++) {
+ int nloci = pChromosome[i]->nLoci();
+ for (int j = 0; j < nloci; j++) {
+ outGenetic << rep << "\t" << year << "\t" << spnum << "\t"
+ << indID << "\t" << i << "\t" << j;
+ l = pChromosome[i]->alleles(j);
+ outGenetic << "\t" << l.allele[0];
+ if (diploid) outGenetic << "\t" << l.allele[1];
+ outGenetic << endl;
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+
+// Set up new gene at initialisation for 1 chromosome per trait
+void Genome::setGene(const short chr, const short exp,
+ const double traitval, const double alleleSD)
+ // NB PARAMETER exp FOR EXPRESSION TYPE IS NOT CURRENTLY USED...
+{
+ if (chr >= 0 && chr < nChromosomes) {
+ pChromosome[chr]->initialise(traitval, alleleSD, diploid);
+ }
+}
+
+// Set up trait at initialisation for trait mapping
+void Genome::setTrait(Species* pSpecies, const int trait,
+ const double traitval, const double alleleSD)
+{
+ traitAllele allele;
+ int nalleles = pSpecies->getNTraitAlleles(trait);
+ int ntraitmaps = pSpecies->getNTraitMaps();
+
+ int avalue;
+ double intbase = INTBASE;
+ if (trait < ntraitmaps) {
+ for (int i = 0; i < nalleles; i++) {
+ allele = pSpecies->getTraitAllele(trait, i);
+ avalue = (int)(pRandom->Normal(traitval, alleleSD) * intbase);
+ pChromosome[allele.chromo]->initialise(allele.locus, 0, avalue);
+ if (diploid) {
+ avalue = (int)(pRandom->Normal(traitval, alleleSD) * intbase);
+ pChromosome[allele.chromo]->initialise(allele.locus, 1, avalue);
+ }
+ }
+ }
+ else { // insufficient traits were defined
+ // alleles cannot be initialised - all individuals have mean phenotype
+ }
+
+}
+
+// Set up trait at initialisation for trait mapping
+void Genome::setNeutralLoci(Species* pSpecies, const double alleleSD)
+{
+ traitAllele allele;
+ int nneutral = pSpecies->getNNeutralLoci();
+
+ double avalue;
+ double intbase = INTBASE;
+ for (int i = 0; i < nneutral; i++) {
+ allele = pSpecies->getNeutralAllele(i);
+ avalue = pRandom->Normal(0.0, alleleSD);
+ if (avalue > 0.0)
+ pChromosome[allele.chromo]->initialise(allele.locus, 0, (int)(avalue * intbase + 0.5));
+ else
+ pChromosome[allele.chromo]->initialise(allele.locus, 0, (int)(avalue * intbase - 0.5));
+ if (diploid) {
+ avalue = pRandom->Normal(0.0, alleleSD);
+ if (avalue > 0.0)
+ pChromosome[allele.chromo]->initialise(allele.locus, 1, (int)(avalue * intbase + 0.5));
+ else
+ pChromosome[allele.chromo]->initialise(allele.locus, 1, (int)(avalue * intbase - 0.5));
+ }
+ }
+}
+
+// Return the expressed value of a gene when species has one chromosome per trait
+double Genome::express(short chr, short expr, short indsex)
+{
+ double genevalue = 0.0;
+ genevalue = pChromosome[chr]->meanvalue(diploid);
+ return genevalue;
+}
+
+// Return the expressed value of a trait when genetic architecture is defined
+double Genome::express(Species* pSpecies, short traitnum)
+{
+ double genevalue = 0.0;
+
+ traitAllele allele;
+ int nalleles = pSpecies->getNTraitAlleles(traitnum);
+ if (nalleles > 0) {
+ for (int i = 0; i < nalleles; i++) {
+ allele = pSpecies->getTraitAllele(traitnum, i);
+ genevalue += pChromosome[allele.chromo]->additive(allele.locus, diploid);
+ }
+ genevalue /= (double)nalleles;
+ if (diploid) genevalue /= 2.0;
+ }
+ return genevalue;
+}
+
+
+locusOK Genome::getAlleles(short chr, short loc) {
+ locusOK l;
+ l.allele[0] = l.allele[1] = 0; l.ok = false;
+ if (chr >= 0 && chr < nChromosomes) {
+ if (pChromosome[chr] != 0) {
+ if (loc >= 0 && loc < pChromosome[chr]->nLoci()) {
+ locus a = pChromosome[chr]->alleles(loc);
+ l.allele[0] = a.allele[0]; l.allele[1] = a.allele[1]; l.ok = true;
+ }
+ }
+ }
+
+ return l;
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
diff --git a/src/RScore/Genome.h b/src/RScore/Genome.h
new file mode 100644
index 00000000..4f01edec
--- /dev/null
+++ b/src/RScore/Genome.h
@@ -0,0 +1,173 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+#ifndef GenomeH
+#define GenomeH
+
+#include
+#include
+
+#include "Parameters.h"
+#include "Species.h"
+
+#define INTBASE 100.0; // to convert integer alleles into continuous traits
+
+struct locus { short allele[2]; };
+struct locusOK { short allele[2]; bool ok; };
+
+//---------------------------------------------------------------------------
+
+class Chromosome {
+
+public:
+ Chromosome(int);
+ ~Chromosome();
+ short nLoci(void);
+ double additive( // Return trait value on normalised genetic scale
+ const bool // diploid
+ );
+ double meanvalue( // Return trait value on normalised genetic scale
+ const bool // diploid
+ );
+ double additive( // Return trait value on normalised genetic scale
+ const short, // locus
+ const bool // diploid
+ );
+ locus alleles( // Return allele values at a specified locus
+ const int // position of locus on chromosome
+ );
+ void initialise( // Set up chromosome at simulation initialisation
+ const double, // normalised phenotypic trait value
+ const double, // s.d. of allelic variance (genetic scale)
+ const bool // diploid
+ );
+ void initialise( // Set up specified locus at simulation initialisation
+ const short, // locus
+ const short, // position: 0 from mother, 1 from father
+ const int // allele value
+ );
+ void inherit( // Inherit chromosome from specified parent
+ const Chromosome*, // pointer to parent's chromosome
+ const short, // position: 0 from mother, 1 from father
+ const short, // no. of loci
+ const double, // mutation probability
+ const double, // crossover probability
+ const double, // s.d. of mutation magnitude (genetic scale)
+ const bool // diploid
+ );
+
+protected:
+
+private:
+ short nloci;
+ locus* pLoci;
+
+};
+
+//---------------------------------------------------------------------------
+
+class Genome {
+
+public:
+ Genome();
+ Genome(int, int, bool);
+ Genome(Species*);
+ Genome(Species*, Genome*, Genome*);
+ ~Genome();
+ void setGene( // Set up new gene at initialisation for 1 chromosome per trait
+ const short, // chromosome number
+ const short, // expression type (NOT CURRENTLY USED)
+ const double, // normalised trait value
+ const double // s.d. of allelic variance
+ );
+ void setTrait( // Set up trait at initialisation for trait mapping
+ Species*, // pointer to Species
+ const int, // trait number
+ const double, // normalised trait value
+ const double // s.d. of allelic variance
+ );
+ void setNeutralLoci( // Set up neutral loci at initialisation
+ Species*, // pointer to Species
+ const double // s.d. of allelic variance
+ );
+ double express(
+ // Return the expressed value of a gene when species has one chromosome per trait
+ short, // chromosome number
+ short, // expression type (NOT CURRENTLY USED)
+ short // individual's sex (NOT CURRENTLY USED)
+ );
+ double express(
+ // Return the expressed value of a trait when genetic architecture is defined
+ Species*, // pointer to Species
+ short // trait number
+ );
+ locusOK getAlleles( // Get allele values at a specified locus
+ short, // chromosome number
+ short // locus position on chromosome
+ );
+ // SCFP NEW DECLARATIONS
+ void setDiploid(bool);
+ bool isDiploid(void);
+ void inherit( // Inherit from specified parent
+ const Genome*, // pointer to parent's genome
+ const short, // position: 0 from mother, 1 from father
+ const short, // chromasome number
+ const double, // mutation probability
+ const double, // crossover probability
+ const double // s.d. of mutation magnitude (genetic scale)
+ );
+ short getNChromosomes(void);
+ void outGenHeaders(
+ const int, // replicate
+ const int, // landscape number
+ const bool // output as cross table?
+ );
+ void outGenetics(
+ const int, // replicate
+ const int, // year
+ const int, // species number
+ const int, // individual ID
+ const bool // output as cross table?
+ );
+
+
+private:
+ short nChromosomes; // no. of chromosomes
+ bool diploid;
+ Chromosome** pChromosome;
+
+};
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+extern paramSim* paramsSim;
+extern RSrandom* pRandom;
+
+#if RSDEBUG
+extern ofstream DEBUGLOG;
+extern ofstream MUTNLOG;
+extern void DebugGUI(string);
+#endif
+
+//---------------------------------------------------------------------------
+
+#endif
diff --git a/src/RScore/Individual.cpp b/src/RScore/Individual.cpp
new file mode 100644
index 00000000..cb6c5f86
--- /dev/null
+++ b/src/RScore/Individual.cpp
@@ -0,0 +1,1860 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+ //---------------------------------------------------------------------------
+
+#include "Individual.h"
+//---------------------------------------------------------------------------
+
+int Individual::indCounter = 0;
+
+//---------------------------------------------------------------------------
+
+// Individual constructor
+Individual::Individual(Cell* pCell, Patch* pPatch, short stg, short a, short repInt,
+ float probmale, bool movt, short moveType)
+{
+ indId = indCounter;
+ indCounter++; // unique identifier for each individual
+
+ stage = stg;
+ if (probmale <= 0.0) sex = 0;
+ else sex = pRandom->Bernoulli(probmale);
+ age = a;
+ status = 0;
+
+ if (sex == 0 && repInt > 0) { // set no. of fallow seasons for female
+ fallow = pRandom->IRandom(0, repInt);
+ }
+ else fallow = 9999;
+ isDeveloping = false;
+ pPrevCell = pCurrCell = pCell;
+ pNatalPatch = pPatch;
+ if (movt) {
+ locn loc = pCell->getLocn();
+ path = new pathData;
+ path->year = 0; path->total = 0; path->out = 0;
+ path->pSettPatch = 0; path->settleStatus = 0;
+#if RS_RCPP
+ path->pathoutput = 1;
+#endif
+ if (moveType == 1) { // SMS
+ // set up location data for SMS
+ smsData = new smsdata;
+ smsData->dp = smsData->gb = smsData->alphaDB = 1.0;
+ smsData->betaDB = 1;
+ smsData->prev.x = loc.x;
+ smsData->prev.y = loc.y; // previous location
+ smsData->goal.x = loc.x;
+ smsData->goal.y = loc.y; // goal location - initialised for dispersal bias
+ }
+ else smsData = 0;
+ if (moveType == 2) { // CRW
+ // set up continuous co-ordinates etc. for CRW movement
+ crw = new crwParams;
+ crw->xc = ((float)pRandom->Random() * 0.999f) + (float)loc.x;
+ crw->yc = (float)(pRandom->Random() * 0.999f) + (float)loc.y;
+ crw->prevdrn = (float)(pRandom->Random() * 2.0 * PI);
+ crw->stepL = crw->rho = 0.0;
+ }
+ else crw = 0;
+ }
+ else {
+ path = 0; crw = 0; smsData = 0;
+ }
+ emigtraits = 0;
+ kerntraits = 0;
+ setttraits = 0;
+ pGenome = 0;
+}
+
+Individual::~Individual(void) {
+ if (path != 0) delete path;
+ if (crw != 0) delete crw;
+ if (smsData != 0) delete smsData;
+ if (emigtraits != 0) delete emigtraits;
+ if (kerntraits != 0) delete kerntraits;
+ if (setttraits != 0) delete setttraits;
+
+ if (pGenome != 0) delete pGenome;
+
+}
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+
+// Set genes for individual variation from species initialisation parameters
+void Individual::setGenes(Species* pSpecies, int resol) {
+ demogrParams dem = pSpecies->getDemogr();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ genomeData gen = pSpecies->getGenomeData();
+ simParams sim = paramsSim->getSim();
+ int ntraits; // first trait for all/female expression, second for male expression
+
+ if (gen.trait1Chromosome) {
+ pGenome = new Genome(pSpecies->getNChromosomes(), pSpecies->getNLoci(0),
+ pSpecies->isDiploid());
+ }
+ else {
+ pGenome = new Genome(pSpecies);
+ }
+
+ int gposn = 0; // current position on genome
+ int expr = 0; // gene expression type - NOT CURRENTLY USED
+
+ if (emig.indVar) { // set emigration genes
+ int emigposn = gposn;
+ double d0, alpha, beta;
+ emigParams eparams;
+ if (emig.sexDep) { // must be a sexual species
+ ntraits = 2;
+ }
+ else {
+ if (dem.repType == 0) { // asexual reproduction (haploid)
+ ntraits = 1;
+ }
+ else { // sexual reproduction
+ ntraits = 1;
+ }
+ }
+ for (int g = 0; g < ntraits; g++) { // first trait for females/all, second for males
+ eparams = pSpecies->getEmigParams(0, g);
+ d0 = pRandom->Normal(0.0, eparams.d0SD) / eparams.d0Scale;
+ if (emig.densDep) {
+ alpha = pRandom->Normal(0.0, eparams.alphaSD) / eparams.alphaScale;
+ beta = pRandom->Normal(0.0, eparams.betaSD) / eparams.betaScale;
+ }
+ if (gen.trait1Chromosome) {
+ pGenome->setGene(gposn++, expr, d0, gen.alleleSD);
+ if (emig.densDep) {
+ pGenome->setGene(gposn++, expr, alpha, gen.alleleSD);
+ pGenome->setGene(gposn++, expr, beta, gen.alleleSD);
+ }
+ }
+ else {
+ pGenome->setTrait(pSpecies, gposn++, d0, gen.alleleSD);
+ if (emig.densDep) {
+ pGenome->setTrait(pSpecies, gposn++, alpha, gen.alleleSD);
+ pGenome->setTrait(pSpecies, gposn++, beta, gen.alleleSD);
+ }
+ }
+ }
+ // record phenotypic traits
+ if (emig.densDep) {
+ setEmigTraits(pSpecies, emigposn, 3, emig.sexDep);
+ }
+ else {
+ setEmigTraits(pSpecies, emigposn, 1, emig.sexDep);
+ }
+ }
+
+ if (trfr.indVar) { // set transfer genes
+ int trfrposn = gposn;
+ if (trfr.sexDep) { // must be a sexual species
+ ntraits = 2;
+ }
+ else {
+ if (dem.repType == 0) { // asexual reproduction
+ ntraits = 1;
+ }
+ else { // sexual reproduction
+ ntraits = 1;
+ }
+ }
+ if (trfr.moveModel) {
+ if (trfr.moveType == 1) { // set SMS genes
+ double dp, gb, alphaDB, betaDB;
+ trfrSMSParams smsparams = pSpecies->getSMSParams(0, 0); // only traits for females/all
+ trfrSMSTraits smstraits = pSpecies->getSMSTraits();
+ dp = pRandom->Normal(0.0, smsparams.dpSD) / smsparams.dpScale;
+ gb = pRandom->Normal(0.0, smsparams.gbSD) / smsparams.gbScale;
+ if (smstraits.goalType == 2) {
+ alphaDB = pRandom->Normal(0.0, smsparams.alphaDBSD) / smsparams.alphaDBScale;
+ betaDB = pRandom->Normal(0.0, smsparams.betaDBSD) / smsparams.betaDBScale;
+ }
+ if (gen.trait1Chromosome) {
+ pGenome->setGene(gposn++, expr, dp, gen.alleleSD);
+ pGenome->setGene(gposn++, expr, gb, gen.alleleSD);
+ if (smstraits.goalType == 2) {
+ pGenome->setGene(gposn++, expr, alphaDB, gen.alleleSD);
+ pGenome->setGene(gposn++, expr, betaDB, gen.alleleSD);
+ }
+ }
+ else {
+ pGenome->setTrait(pSpecies, gposn++, dp, gen.alleleSD);
+ pGenome->setTrait(pSpecies, gposn++, gb, gen.alleleSD);
+ if (smstraits.goalType == 2) {
+ pGenome->setTrait(pSpecies, gposn++, alphaDB, gen.alleleSD);
+ pGenome->setTrait(pSpecies, gposn++, betaDB, gen.alleleSD);
+ }
+ }
+ // record phenotypic traits
+ if (smstraits.goalType == 2)
+ setSMSTraits(pSpecies, trfrposn, 4, false);
+ else
+ setSMSTraits(pSpecies, trfrposn, 2, false);
+ }
+ if (trfr.moveType == 2) { // set CRW genes
+ double stepL, rho;
+ trfrCRWParams m = pSpecies->getCRWParams(0, 0); // only traits for females/all
+ stepL = pRandom->Normal(0.0, m.stepLgthSD) / m.stepLScale;
+ rho = pRandom->Normal(0.0, m.rhoSD) / m.rhoScale;
+ if (gen.trait1Chromosome) {
+ pGenome->setGene(gposn++, expr, stepL, gen.alleleSD);
+ pGenome->setGene(gposn++, expr, rho, gen.alleleSD);
+ }
+ else {
+ pGenome->setTrait(pSpecies, gposn++, stepL, gen.alleleSD);
+ pGenome->setTrait(pSpecies, gposn++, rho, gen.alleleSD);
+ }
+ // record phenotypic traits
+ setCRWTraits(pSpecies, trfrposn, 2, false);
+ }
+ }
+ else { // set kernel genes
+ double dist1, dist2, prob1;
+ trfrKernParams k;
+ for (int g = 0; g < ntraits; g++) { // first traits for females/all, second for males
+ k = pSpecies->getKernParams(0, g);
+ dist1 = pRandom->Normal(0.0, k.dist1SD) / k.dist1Scale;
+ if (trfr.twinKern)
+ {
+ dist2 = pRandom->Normal(0.0, k.dist2SD) / k.dist2Scale;
+ prob1 = pRandom->Normal(0.0, k.PKern1SD) / k.PKern1Scale;
+ }
+ if (gen.trait1Chromosome) {
+ pGenome->setGene(gposn++, expr, dist1, gen.alleleSD);
+ if (trfr.twinKern)
+ {
+ pGenome->setGene(gposn++, expr, dist2, gen.alleleSD);
+ pGenome->setGene(gposn++, expr, prob1, gen.alleleSD);
+ }
+ }
+ else {
+ pGenome->setTrait(pSpecies, gposn++, dist1, gen.alleleSD);
+ if (trfr.twinKern)
+ {
+ pGenome->setTrait(pSpecies, gposn++, dist2, gen.alleleSD);
+ pGenome->setTrait(pSpecies, gposn++, prob1, gen.alleleSD);
+ }
+ }
+ }
+ // record phenotypic traits
+ if (trfr.twinKern)
+ {
+ setKernTraits(pSpecies, trfrposn, 3, resol, trfr.sexDep);
+ }
+ else {
+ setKernTraits(pSpecies, trfrposn, 1, resol, trfr.sexDep);
+ }
+ }
+ }
+
+ if (sett.indVar) {
+ int settposn = gposn;
+ double s0, alpha, beta;
+ settParams sparams;
+ if (sett.sexDep) { // must be a sexual species
+ ntraits = 2;
+ }
+ else {
+ if (dem.repType == 0) { // asexual reproduction
+ ntraits = 1;
+ }
+ else { // sexual reproduction
+ ntraits = 1;
+ }
+ }
+ for (int g = 0; g < ntraits; g++) { // first trait for females/all, second for males
+ if (sim.batchMode) {
+ sparams = pSpecies->getSettParams(0, g);
+ }
+ else { // individual variability not (yet) implemented as sex-dependent in GUI
+ sparams = pSpecies->getSettParams(0, 0);
+ }
+ s0 = pRandom->Normal(0.0, sparams.s0SD) / sparams.s0Scale;
+ alpha = pRandom->Normal(0.0, sparams.alphaSSD) / sparams.alphaSScale;
+ beta = pRandom->Normal(0.0, sparams.betaSSD) / sparams.betaSScale;
+
+ if (gen.trait1Chromosome) {
+ pGenome->setGene(gposn++, expr, s0, gen.alleleSD);
+ pGenome->setGene(gposn++, expr, alpha, gen.alleleSD);
+ pGenome->setGene(gposn++, expr, beta, gen.alleleSD);
+ }
+ else {
+ pGenome->setTrait(pSpecies, gposn++, s0, gen.alleleSD);
+ pGenome->setTrait(pSpecies, gposn++, alpha, gen.alleleSD);
+ pGenome->setTrait(pSpecies, gposn++, beta, gen.alleleSD);
+ }
+ }
+ // record phenotypic traits
+ setSettTraits(pSpecies, settposn, 3, sett.sexDep);
+ }
+
+ if (!gen.trait1Chromosome) {
+ if (gen.neutralMarkers || pSpecies->getNNeutralLoci() > 0) {
+ pGenome->setNeutralLoci(pSpecies, gen.alleleSD);
+ }
+ }
+}
+
+// Inherit genome from parent(s)
+void Individual::setGenes(Species* pSpecies, Individual* mother, Individual* father,
+ int resol)
+{
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+
+ Genome* pFatherGenome;
+ if (father == 0) pFatherGenome = 0; else pFatherGenome = father->pGenome;
+
+ pGenome = new Genome(pSpecies, mother->pGenome, pFatherGenome);
+
+ if (emig.indVar) {
+ // record emigration traits
+ if (father == 0) { // haploid
+ if (emig.densDep) {
+ setEmigTraits(pSpecies, 0, 3, 0);
+ }
+ else {
+ setEmigTraits(pSpecies, 0, 1, 0);
+ }
+ }
+ else { // diploid
+ if (emig.densDep) {
+ setEmigTraits(pSpecies, 0, 3, emig.sexDep);
+ }
+ else {
+ setEmigTraits(pSpecies, 0, 1, emig.sexDep);
+ }
+ }
+ }
+
+ if (trfr.indVar) {
+ // record movement model traits
+ if (trfr.moveModel) {
+ if (trfr.moveType == 1) { // SMS
+ trfrSMSTraits s = pSpecies->getSMSTraits();
+ if (s.goalType == 2)
+ setSMSTraits(pSpecies, trfr.movtTrait[0], 4, 0);
+ else
+ setSMSTraits(pSpecies, trfr.movtTrait[0], 2, 0);
+ }
+ if (trfr.moveType == 2) { // CRW
+ setCRWTraits(pSpecies, trfr.movtTrait[0], 2, 0);
+ }
+ }
+ else { // kernel
+ if (father == 0) { // haploid
+ if (trfr.twinKern)
+ {
+ setKernTraits(pSpecies, trfr.movtTrait[0], 3, resol, 0);
+ }
+ else {
+ setKernTraits(pSpecies, trfr.movtTrait[0], 1, resol, 0);
+ }
+ }
+ else { // diploid
+ if (trfr.twinKern)
+ {
+ setKernTraits(pSpecies, trfr.movtTrait[0], 3, resol, trfr.sexDep);
+ }
+ else {
+ setKernTraits(pSpecies, trfr.movtTrait[0], 1, resol, trfr.sexDep);
+ }
+ }
+ }
+ }
+
+ if (sett.indVar) {
+ // record settlement traits
+ if (father == 0) { // haploid
+ setSettTraits(pSpecies, sett.settTrait[0], 3, 0);
+ }
+ else { // diploid
+ setSettTraits(pSpecies, sett.settTrait[0], 3, sett.sexDep);
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+
+// Identify whether an individual is a potentially breeding female -
+// if so, return her stage, otherwise return 0
+int Individual::breedingFem(void) {
+ if (sex == 0) {
+ if (status == 0 || status == 4 || status == 5) return stage;
+ else return 0;
+ }
+ else return 0;
+}
+
+int Individual::getId(void) { return indId; }
+
+int Individual::getSex(void) { return sex; }
+
+int Individual::getStatus(void) { return status; }
+
+indStats Individual::getStats(void) {
+ indStats s;
+ s.stage = stage; s.sex = sex; s.age = age; s.status = status; s.fallow = fallow;
+ s.isDeveloping = isDeveloping;
+ return s;
+}
+
+Cell* Individual::getLocn(const short option) {
+ if (option == 0) { // return previous location
+ return pPrevCell;
+ }
+ else { // return current location
+ return pCurrCell;
+ }
+}
+
+Patch* Individual::getNatalPatch(void) { return pNatalPatch; }
+
+void Individual::setYearSteps(int t) {
+ if (path != 0 && t >= 0) {
+ if (t >= 0) path->year = t;
+ else path->year = 666;
+ }
+}
+
+pathSteps Individual::getSteps(void) {
+ pathSteps s;
+ if (path == 0) {
+ s.year = 0; s.total = 0; s.out = 0;
+ }
+ else {
+ s.year = path->year; s.total = path->total; s.out = path->out;
+ }
+ return s;
+}
+
+settlePatch Individual::getSettPatch(void) {
+ settlePatch s;
+ if (path == 0) {
+ s.pSettPatch = 0; s.settleStatus = 0;
+ }
+ else {
+ s.pSettPatch = path->pSettPatch; s.settleStatus = path->settleStatus;
+ }
+ return s;
+}
+
+void Individual::setSettPatch(const settlePatch s) {
+ if (path == 0) {
+ path = new pathData;
+ path->year = 0; path->total = 0; path->out = 0; path->settleStatus = 0;
+#if RS_RCPP
+ path->pathoutput = 1;
+#endif
+ }
+ if (s.settleStatus >= 0 && s.settleStatus <= 2) path->settleStatus = s.settleStatus;
+ path->pSettPatch = s.pSettPatch;
+}
+
+// Set phenotypic emigration traits
+void Individual::setEmigTraits(Species* pSpecies, short emiggenelocn, short nemigtraits,
+ bool sexdep) {
+ emigTraits e; e.d0 = e.alpha = e.beta = 0.0;
+ if (pGenome != 0) {
+ if (pSpecies->has1ChromPerTrait()) {
+ if (sexdep) {
+ if (nemigtraits == 3) { // emigration is density-dependent
+ e.d0 = (float)pGenome->express(emiggenelocn + 3 * sex, 0, 0);
+ e.alpha = (float)pGenome->express(emiggenelocn + 3 * sex + 1, 0, 0);
+ e.beta = (float)pGenome->express(emiggenelocn + 3 * sex + 2, 0, 0);
+ }
+ else {
+ e.d0 = (float)pGenome->express(emiggenelocn + sex, 0, 0);
+ }
+ }
+ else {
+ e.d0 = (float)pGenome->express(emiggenelocn, 0, 0);
+ if (nemigtraits == 3) { // emigration is density-dependent
+ e.alpha = (float)pGenome->express(emiggenelocn + 1, 0, 0);
+ e.beta = (float)pGenome->express(emiggenelocn + 2, 0, 0);
+ }
+ }
+ }
+ else {
+ if (sexdep) {
+ if (nemigtraits == 3) { // emigration is density-dependent
+ e.d0 = (float)pGenome->express(pSpecies, emiggenelocn + 3 * sex);
+ e.alpha = (float)pGenome->express(pSpecies, emiggenelocn + 3 * sex + 1);
+ e.beta = (float)pGenome->express(pSpecies, emiggenelocn + 3 * sex + 2);
+ }
+ else {
+ e.d0 = (float)pGenome->express(pSpecies, emiggenelocn + sex);
+ }
+ }
+ else {
+ e.d0 = (float)pGenome->express(pSpecies, emiggenelocn);
+ if (nemigtraits == 3) { // emigration is density-dependent
+ e.alpha = (float)pGenome->express(pSpecies, emiggenelocn + 1);
+ e.beta = (float)pGenome->express(pSpecies, emiggenelocn + 2);
+ }
+ }
+ }
+ }
+
+ emigParams eparams;
+ if (sexdep) {
+ eparams = pSpecies->getEmigParams(0, sex);
+ }
+ else {
+ eparams = pSpecies->getEmigParams(0, 0);
+ }
+ emigtraits = new emigTraits;
+ emigtraits->d0 = (float)(e.d0 * eparams.d0Scale + eparams.d0Mean);
+ emigtraits->alpha = (float)(e.alpha * eparams.alphaScale + eparams.alphaMean);
+ emigtraits->beta = (float)(e.beta * eparams.betaScale + eparams.betaMean);
+ if (emigtraits->d0 < 0.0) emigtraits->d0 = 0.0;
+ if (emigtraits->d0 > 1.0) emigtraits->d0 = 1.0;
+ return;
+}
+
+// Get phenotypic emigration traits
+emigTraits Individual::getEmigTraits(void) {
+ emigTraits e; e.d0 = e.alpha = e.beta = 0.0;
+ if (emigtraits != 0) {
+ e.d0 = emigtraits->d0;
+ e.alpha = emigtraits->alpha;
+ e.beta = emigtraits->beta;
+ }
+ return e;
+}
+
+// Set phenotypic transfer by kernel traits
+void Individual::setKernTraits(Species* pSpecies, short kerngenelocn, short nkerntraits,
+ int resol, bool sexdep) {
+ trfrKernTraits k; k.meanDist1 = k.meanDist2 = k.probKern1 = 0.0;
+ if (pGenome != 0) {
+ if (pSpecies->has1ChromPerTrait()) {
+ if (sexdep) {
+ if (nkerntraits == 3) { // twin kernel
+ k.meanDist1 = (float)pGenome->express(kerngenelocn + 3 * sex, 0, sex);
+ k.meanDist2 = (float)pGenome->express(kerngenelocn + 3 * sex + 1, 0, sex);
+ k.probKern1 = (float)pGenome->express(kerngenelocn + 3 * sex + 2, 0, sex);
+ }
+ else {
+ k.meanDist1 = (float)pGenome->express(kerngenelocn + sex, 0, sex);
+ }
+ }
+ else {
+ k.meanDist1 = (float)pGenome->express(kerngenelocn, 0, 0);
+ if (nkerntraits == 3) { // twin kernel
+ k.meanDist2 = (float)pGenome->express(kerngenelocn + 1, 0, 0);
+ k.probKern1 = (float)pGenome->express(kerngenelocn + 2, 0, 0);
+ }
+ }
+ }
+ else {
+ if (sexdep) {
+ if (nkerntraits == 3) { // twin kernel
+ k.meanDist1 = (float)pGenome->express(pSpecies, kerngenelocn + 3 * sex);
+ k.meanDist2 = (float)pGenome->express(pSpecies, kerngenelocn + 3 * sex + 1);
+ k.probKern1 = (float)pGenome->express(pSpecies, kerngenelocn + 3 * sex + 2);
+ }
+ else {
+ k.meanDist1 = (float)pGenome->express(pSpecies, kerngenelocn + sex);
+ }
+ }
+ else {
+ k.meanDist1 = (float)pGenome->express(pSpecies, kerngenelocn);
+ if (nkerntraits == 3) { // twin kernel
+ k.meanDist2 = (float)pGenome->express(pSpecies, kerngenelocn + 1);
+ k.probKern1 = (float)pGenome->express(pSpecies, kerngenelocn + 2);
+ }
+ }
+ }
+ }
+
+ trfrKernParams kparams;
+ if (sexdep) {
+ kparams = pSpecies->getKernParams(0, sex);
+ }
+ else {
+ kparams = pSpecies->getKernParams(0, 0);
+ }
+ kerntraits = new trfrKernTraits;
+ kerntraits->meanDist1 = (float)(k.meanDist1 * kparams.dist1Scale + kparams.dist1Mean);
+ kerntraits->meanDist2 = (float)(k.meanDist2 * kparams.dist2Scale + kparams.dist2Mean);
+ kerntraits->probKern1 = (float)(k.probKern1 * kparams.PKern1Scale + kparams.PKern1Mean);
+ if (!pSpecies->useFullKernel()) {
+ // kernel mean(s) may not be less than landscape resolution
+ if (kerntraits->meanDist1 < resol) kerntraits->meanDist1 = (float)resol;
+ if (kerntraits->meanDist2 < resol) kerntraits->meanDist2 = (float)resol;
+ }
+ if (kerntraits->probKern1 < 0.0) kerntraits->probKern1 = 0.0;
+ if (kerntraits->probKern1 > 1.0) kerntraits->probKern1 = 1.0;
+ return;
+}
+
+// Get phenotypic emigration traits
+trfrKernTraits Individual::getKernTraits(void) {
+ trfrKernTraits k; k.meanDist1 = k.meanDist2 = k.probKern1 = 0.0;
+ if (kerntraits != 0) {
+ k.meanDist1 = kerntraits->meanDist1;
+ k.meanDist2 = kerntraits->meanDist2;
+ k.probKern1 = kerntraits->probKern1;
+ }
+ return k;
+}
+
+// Set phenotypic transfer by SMS traits
+void Individual::setSMSTraits(Species* pSpecies, short SMSgenelocn, short nSMStraits,
+ bool sexdep) {
+ trfrSMSTraits s = pSpecies->getSMSTraits();
+ double dp, gb, alphaDB, betaDB;
+ dp = gb = alphaDB = betaDB = 0.0;
+ if (pGenome != 0) {
+ if (pSpecies->has1ChromPerTrait()) {
+ if (sexdep) {
+ dp = pGenome->express(SMSgenelocn, 0, 0);
+ gb = pGenome->express(SMSgenelocn + 1, 0, 0);
+ if (nSMStraits == 4) {
+ alphaDB = pGenome->express(SMSgenelocn + 2, 0, 0);
+ betaDB = pGenome->express(SMSgenelocn + 3, 0, 0);
+ }
+ }
+ else {
+ dp = pGenome->express(SMSgenelocn, 0, 0);
+ gb = pGenome->express(SMSgenelocn + 1, 0, 0);
+ if (nSMStraits == 4) {
+ alphaDB = pGenome->express(SMSgenelocn + 2, 0, 0);
+ betaDB = pGenome->express(SMSgenelocn + 3, 0, 0);
+ }
+ }
+ }
+ else {
+ if (sexdep) {
+ dp = pGenome->express(pSpecies, SMSgenelocn);
+ gb = pGenome->express(pSpecies, SMSgenelocn + 1);
+ if (nSMStraits == 4) {
+ alphaDB = pGenome->express(pSpecies, SMSgenelocn + 2);
+ betaDB = pGenome->express(pSpecies, SMSgenelocn + 3);
+ }
+ }
+ else {
+ dp = pGenome->express(pSpecies, SMSgenelocn);
+ gb = pGenome->express(pSpecies, SMSgenelocn + 1);
+ if (nSMStraits == 4) {
+ alphaDB = pGenome->express(pSpecies, SMSgenelocn + 2);
+ betaDB = pGenome->express(pSpecies, SMSgenelocn + 3);
+ }
+ }
+ }
+ }
+ trfrSMSParams smsparams;
+ if (sexdep) {
+ smsparams = pSpecies->getSMSParams(0, 0);
+ }
+ else {
+ smsparams = pSpecies->getSMSParams(0, 0);
+ }
+ smsData->dp = (float)(dp * smsparams.dpScale + smsparams.dpMean);
+ smsData->gb = (float)(gb * smsparams.gbScale + smsparams.gbMean);
+ if (s.goalType == 2) {
+ smsData->alphaDB = (float)(alphaDB * smsparams.alphaDBScale + smsparams.alphaDBMean);
+ smsData->betaDB = (int)(betaDB * smsparams.betaDBScale + smsparams.betaDBMean + 0.5);
+ }
+ else {
+ smsData->alphaDB = s.alphaDB;
+ smsData->betaDB = s.betaDB;
+ }
+ if (smsData->dp < 1.0) smsData->dp = 1.0;
+ if (smsData->gb < 1.0) smsData->gb = 1.0;
+ if (smsData->alphaDB <= 0.0) smsData->alphaDB = 0.000001f;
+ if (smsData->betaDB < 1) smsData->betaDB = 1;
+ return;
+}
+
+// Get phenotypic transfer by SMS traits
+trfrSMSTraits Individual::getSMSTraits(void) {
+ trfrSMSTraits s; s.dp = s.gb = s.alphaDB = 1.0; s.betaDB = 1;
+ if (smsData != 0) {
+ s.dp = smsData->dp; s.gb = smsData->gb;
+ s.alphaDB = smsData->alphaDB; s.betaDB = smsData->betaDB;
+ }
+ return s;
+}
+
+// Set phenotypic transfer by CRW traits
+void Individual::setCRWTraits(Species* pSpecies, short CRWgenelocn, short nCRWtraits,
+ bool sexdep) {
+ trfrCRWTraits c; c.stepLength = c.rho = 0.0;
+ if (pGenome != 0) {
+ if (pSpecies->has1ChromPerTrait()) {
+ if (sexdep) {
+ c.stepLength = (float)pGenome->express(CRWgenelocn + sex, 0, sex);
+ c.rho = (float)pGenome->express(CRWgenelocn + 2 + sex, 0, sex);
+ }
+ else {
+ c.stepLength = (float)pGenome->express(CRWgenelocn, 0, 0);
+ c.rho = (float)pGenome->express(CRWgenelocn + 1, 0, 0);
+ }
+ }
+ else {
+ if (sexdep) {
+ c.stepLength = (float)pGenome->express(pSpecies, CRWgenelocn + sex);
+ c.rho = (float)pGenome->express(pSpecies, CRWgenelocn + 2 + sex);
+ }
+ else {
+ c.stepLength = (float)pGenome->express(pSpecies, CRWgenelocn);
+ c.rho = (float)pGenome->express(pSpecies, CRWgenelocn + 1);
+ }
+ }
+ }
+
+ trfrCRWParams cparams;
+ if (sexdep) {
+ cparams = pSpecies->getCRWParams(0, sex);
+ }
+ else {
+ cparams = pSpecies->getCRWParams(0, 0);
+ }
+ crw->stepL = (float)(c.stepLength * cparams.stepLScale + cparams.stepLgthMean);
+ crw->rho = (float)(c.rho * cparams.rhoScale + cparams.rhoMean);
+ if (crw->stepL < 1.0) crw->stepL = 1.0;
+ if (crw->rho < 0.0) crw->rho = 0.0;
+ if (crw->rho > 0.999) crw->rho = 0.999f;
+ return;
+}
+
+// Get phenotypic transfer by CRW traits
+trfrCRWTraits Individual::getCRWTraits(void) {
+ trfrCRWTraits c; c.stepLength = c.rho = 0.0;
+ if (crw != 0) {
+ c.stepLength = crw->stepL;
+ c.rho = crw->rho;
+ }
+ return c;
+}
+
+// Set phenotypic settlement traits
+void Individual::setSettTraits(Species* pSpecies, short settgenelocn, short nsetttraits,
+ bool sexdep) {
+ settleTraits s; s.s0 = s.alpha = s.beta = 0.0;
+ if (pGenome != 0) {
+ if (pSpecies->has1ChromPerTrait()) {
+ if (sexdep) {
+ s.s0 = (float)pGenome->express(settgenelocn + 3 * sex, 0, 0);
+ s.alpha = (float)pGenome->express(settgenelocn + 3 * sex + 1, 0, 0);
+ s.beta = (float)pGenome->express(settgenelocn + 3 * sex + 2, 0, 0);
+ }
+ else {
+ s.s0 = (float)pGenome->express(settgenelocn, 0, 0);
+ s.alpha = (float)pGenome->express(settgenelocn + 1, 0, 0);
+ s.beta = (float)pGenome->express(settgenelocn + 2, 0, 0);
+ }
+ }
+ else {
+ if (sexdep) {
+ s.s0 = (float)pGenome->express(pSpecies, settgenelocn + 3 * sex);
+ s.alpha = (float)pGenome->express(pSpecies, settgenelocn + 3 * sex + 1);
+ s.beta = (float)pGenome->express(pSpecies, settgenelocn + 3 * sex + 2);
+ }
+ else {
+ s.s0 = (float)pGenome->express(pSpecies, settgenelocn);
+ s.alpha = (float)pGenome->express(pSpecies, settgenelocn + 1);
+ s.beta = (float)pGenome->express(pSpecies, settgenelocn + 2);
+ }
+
+ }
+ }
+
+ settParams sparams;
+ if (sexdep) {
+ sparams = pSpecies->getSettParams(0, sex);
+ }
+ else {
+ sparams = pSpecies->getSettParams(0, 0);
+ }
+ setttraits = new settleTraits;
+ setttraits->s0 = (float)(s.s0 * sparams.s0Scale + sparams.s0Mean);
+ setttraits->alpha = (float)(s.alpha * sparams.alphaSScale + sparams.alphaSMean);
+ setttraits->beta = (float)(s.beta * sparams.betaSScale + sparams.betaSMean);
+ if (setttraits->s0 < 0.0) setttraits->s0 = 0.0;
+ if (setttraits->s0 > 1.0) setttraits->s0 = 1.0;
+ return;
+}
+
+// Get phenotypic settlement traits
+settleTraits Individual::getSettTraits(void) {
+ settleTraits s; s.s0 = s.alpha = s.beta = 0.0;
+ if (setttraits != 0) {
+ s.s0 = setttraits->s0;
+ s.alpha = setttraits->alpha;
+ s.beta = setttraits->beta;
+ }
+
+ return s;
+}
+
+
+void Individual::setStatus(short s) {
+ if (s >= 0 && s <= 9) status = s;
+ status = s;
+}
+
+void Individual::developing(void) {
+ isDeveloping = true;
+}
+
+void Individual::develop(void) {
+ stage++; isDeveloping = false;
+}
+
+void Individual::ageIncrement(short maxage) {
+ if (status < 6) { // alive
+ age++;
+ if (age > maxage) status = 9; // exceeds max. age - dies
+ else {
+ if (path != 0) path->year = 0; // reset annual step count for movement models
+ if (status == 3) // waiting to continue dispersal
+ status = 1;
+ }
+ }
+}
+
+void Individual::incFallow(void) { fallow++; }
+
+void Individual::resetFallow(void) { fallow = 0; }
+
+//---------------------------------------------------------------------------
+// Move to a specified neighbouring cell
+void Individual::moveto(Cell* newCell) {
+ // check that location is indeed a neighbour of the current cell
+ locn currloc = pCurrCell->getLocn();
+ locn newloc = newCell->getLocn();
+ double d = sqrt(((double)currloc.x - (double)newloc.x) * ((double)currloc.x - (double)newloc.x)
+ + ((double)currloc.y - (double)newloc.y) * ((double)currloc.y - (double)newloc.y));
+ if (d >= 1.0 && d < 1.5) { // ok
+ pCurrCell = newCell;
+ status = 5;
+ }
+}
+
+//---------------------------------------------------------------------------
+// Move to a new cell by sampling a dispersal distance from a single or double
+// negative exponential kernel
+// Returns 1 if still dispersing (including having found a potential patch), otherwise 0
+int Individual::moveKernel(Landscape* pLandscape, Species* pSpecies,
+ const short repType, const bool absorbing)
+{
+
+ intptr patch;
+ int patchNum = 0;
+ int newX = 0, newY = 0;
+ int dispersing = 1;
+ double xrand, yrand, meandist, dist, r1, rndangle, nx, ny;
+ float localK;
+ trfrKernTraits kern;
+ Cell* pCell;
+ Patch* pPatch;
+ locn loc = pCurrCell->getLocn();
+
+ landData land = pLandscape->getLandData();
+
+ bool usefullkernel = pSpecies->useFullKernel();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleRules sett = pSpecies->getSettRules(stage, sex);
+
+ pCell = NULL;
+ pPatch = NULL;
+
+ if (trfr.indVar) { // get individual's kernel parameters
+ kern.meanDist1 = kern.meanDist2 = kern.probKern1 = 0.0;
+ if (pGenome != 0) {
+ kern.meanDist1 = kerntraits->meanDist1;
+ if (trfr.twinKern)
+ {
+ kern.meanDist2 = kerntraits->meanDist2;
+ kern.probKern1 = kerntraits->probKern1;
+ }
+ }
+ }
+ else { // get kernel parameters for the species
+ if (trfr.sexDep) {
+ if (trfr.stgDep) {
+ kern = pSpecies->getKernTraits(stage, sex);
+ }
+ else {
+ kern = pSpecies->getKernTraits(0, sex);
+ }
+ }
+ else {
+ if (trfr.stgDep) {
+ kern = pSpecies->getKernTraits(stage, 0);
+ }
+ else {
+ kern = pSpecies->getKernTraits(0, 0);
+ }
+ }
+ }
+
+ // scale the appropriate kernel mean to the cell size
+ if (trfr.twinKern)
+ {
+ if (pRandom->Bernoulli(kern.probKern1))
+ meandist = kern.meanDist1 / (float)land.resol;
+ else
+ meandist = kern.meanDist2 / (float)land.resol;
+ }
+ else
+ meandist = kern.meanDist1 / (float)land.resol;
+
+ // scaled mean may not be less than 1 unless emigration derives from the kernel
+ // (i.e. the 'use full kernel' option is applied)
+ if (!usefullkernel && meandist < 1.0) meandist = 1.0;
+
+ int loopsteps = 0; // new counter to prevent infinite loop added 14/8/15
+ do {
+ do {
+ do {
+ // randomise the cell within the patch, provided that the individual is still in
+ // its natal cell (i.e. not waiting in the matrix)
+ // this is because, if the patch is very large, the individual is near the centre
+ // and the (single) kernel mean is (not much more than) the cell size, an infinite
+ // loop could otherwise result, as the individual never reaches the patch edge
+ // (in a cell-based model, this has no effect, other than as a processing overhead)
+ if (status == 1) {
+ pCell = pNatalPatch->getRandomCell();
+ if (pCell != 0) {
+ loc = pCell->getLocn();
+ }
+ }
+ // randomise the position of the individual inside the cell
+ xrand = (double)loc.x + pRandom->Random() * 0.999;
+ yrand = (double)loc.y + pRandom->Random() * 0.999;
+
+ r1 = 0.0000001 + pRandom->Random() * (1.0 - 0.0000001);
+ // dist = (-1.0*meandist)*std::log(r1);
+ dist = (-1.0 * meandist) * log(r1); // for LINUX_CLUSTER
+
+ rndangle = pRandom->Random() * 2.0 * PI;
+ nx = xrand + dist * sin(rndangle);
+ ny = yrand + dist * cos(rndangle);
+ if (nx < 0.0) newX = -1; else newX = (int)nx;
+ if (ny < 0.0) newY = -1; else newY = (int)ny;
+#if RSDEBUG
+ if (path != 0) (path->year)++;
+#endif
+ loopsteps++;
+ } while (loopsteps < 1000 &&
+ ((!absorbing && (newX < land.minX || newX > land.maxX
+ || newY < land.minY || newY > land.maxY))
+ || (!usefullkernel && newX == loc.x && newY == loc.y))
+ );
+ if (loopsteps < 1000) {
+ if (newX < land.minX || newX > land.maxX
+ || newY < land.minY || newY > land.maxY) { // beyond absorbing boundary
+ pCell = 0;
+ patch = 0;
+ patchNum = -1;
+ }
+ else {
+ pCell = pLandscape->findCell(newX, newY);
+ if (pCell == 0) { // no-data cell
+ patch = 0;
+ patchNum = -1;
+ }
+ else {
+ patch = pCell->getPatch();
+ if (patch == 0) { // matrix
+ pPatch = 0;
+ patchNum = 0;
+ }
+ else {
+ pPatch = (Patch*)patch;
+ patchNum = pPatch->getPatchNum();
+ }
+ }
+ }
+ }
+ else {
+ patch = 0;
+ patchNum = -1;
+ }
+ } while (!absorbing && patchNum < 0 && loopsteps < 1000); // in a no-data region
+ } while (!usefullkernel && pPatch == pNatalPatch && loopsteps < 1000); // still in the original (natal) patch
+
+ if (loopsteps < 1000) {
+ if (pCell == 0) { // beyond absorbing boundary or in no-data cell
+ pCurrCell = 0;
+ status = 6;
+ dispersing = 0;
+ }
+ else {
+ pCurrCell = pCell;
+ if (pPatch == 0) localK = 0.0; // matrix
+ else localK = pPatch->getK();
+ if (patchNum > 0 && localK > 0.0) { // found a new patch
+ status = 2; // record as potential settler
+ }
+ else {
+ dispersing = 0;
+ // can wait in matrix if population is stage structured ...
+ if (pSpecies->stageStructured()) {
+ // ... and wait option is applied ...
+ if (sett.wait) { // ... it is
+ status = 3; // waiting
+ }
+ else // ... it is not
+ status = 6; // dies (unless there is a suitable neighbouring cell)
+ }
+ else
+ status = 6; // dies (unless there is a suitable neighbouring cell)
+ }
+ }
+ }
+ else {
+ status = 6;
+ dispersing = 0;
+ }
+
+ // apply dispersal-related mortality, which may be distance-dependent
+ dist *= (float)land.resol; // re-scale distance moved to landscape scale
+ if (status < 7) {
+ double dispmort;
+ trfrMortParams mort = pSpecies->getMortParams();
+ if (trfr.distMort) {
+ dispmort = 1.0 / (1.0 + exp(-(dist - mort.mortBeta) * mort.mortAlpha));
+ }
+ else {
+ dispmort = mort.fixedMort;
+ }
+ if (pRandom->Bernoulli(dispmort)) {
+ status = 7; // dies
+ dispersing = 0;
+ }
+ }
+
+ return dispersing;
+}
+
+//---------------------------------------------------------------------------
+// Make a single movement step according to a mechanistic movement model
+// Returns 1 if still dispersing (including having found a potential patch), otherwise 0
+int Individual::moveStep(Landscape* pLandscape, Species* pSpecies,
+ const short landIx, const bool absorbing)
+{
+
+ if (status != 1) return 0; // not currently dispersing
+
+ intptr patch;
+ int patchNum;
+ int newX, newY;
+ locn loc;
+ int dispersing = 1;
+ double xcnew, ycnew;
+ double angle;
+ double mortprob, rho, steplen;
+ movedata move;
+ Patch* pPatch = 0;
+ bool absorbed = false;
+
+ landData land = pLandscape->getLandData();
+ simParams sim = paramsSim->getSim();
+
+ trfrRules trfr = pSpecies->getTrfr();
+ trfrCRWTraits movt = pSpecies->getCRWTraits();
+ settleSteps settsteps = pSpecies->getSteps(stage, sex);
+
+ patch = pCurrCell->getPatch();
+
+ if (patch == 0) { // matrix
+ pPatch = 0;
+ patchNum = 0;
+ }
+ else {
+ pPatch = (Patch*)patch;
+ patchNum = pPatch->getPatchNum();
+ }
+ // apply step-dependent mortality risk ...
+ if (trfr.habMort)
+ { // habitat-dependent
+ int h = pCurrCell->getHabIndex(landIx);
+ if (h < 0) { // no-data cell - should not occur, but if it does, individual dies
+ mortprob = 1.0;
+ }
+ else mortprob = pSpecies->getHabMort(h);
+ }
+ else mortprob = movt.stepMort;
+ // ... unless individual has not yet left natal patch in emigration year
+ if (pPatch == pNatalPatch && path->out == 0 && path->year == path->total) {
+ mortprob = 0.0;
+ }
+ if (pRandom->Bernoulli(mortprob)) { // individual dies
+ status = 7;
+ dispersing = 0;
+ }
+ else { // take a step
+ (path->year)++;
+ (path->total)++;
+ if (patch == 0 || pPatch == 0 || patchNum == 0) { // not in a patch
+ if (path != 0) path->settleStatus = 0; // reset path settlement status
+ (path->out)++;
+ }
+ loc = pCurrCell->getLocn();
+ newX = loc.x; newY = loc.y;
+
+
+ switch (trfr.moveType) {
+
+ case 1: // SMS
+ move = smsMove(pLandscape, pSpecies, landIx, pPatch == pNatalPatch, trfr.indVar, absorbing);
+ if (move.dist < 0.0) {
+ // either INTERNAL ERROR CONDITION - INDIVIDUAL IS IN NO-DATA SQUARE
+ // or individual has crossed absorbing boundary ...
+ // ... individual dies
+ status = 6;
+ dispersing = 0;
+ }
+ else {
+
+ // WOULD IT BE MORE EFFICIENT FOR smsMove TO RETURN A POINTER TO THE NEW CELL? ...
+
+ patch = pCurrCell->getPatch();
+ if (patch == 0) {
+ pPatch = 0;
+ }
+ else {
+ pPatch = (Patch*)patch;
+ }
+ if (sim.saveVisits && pPatch != pNatalPatch) {
+ pCurrCell->incrVisits();
+ }
+ }
+ break;
+
+ case 2: // CRW
+ if (trfr.indVar) {
+ if (crw != 0) {
+ movt.stepLength = crw->stepL;
+ movt.rho = crw->rho;
+ }
+ }
+
+ steplen = movt.stepLength; if (steplen < 0.2 * land.resol) steplen = 0.2 * land.resol;
+ rho = movt.rho; if (rho > 0.99) rho = 0.99;
+ if (pPatch == pNatalPatch) {
+ rho = 0.99; // to promote leaving natal patch
+ path->out = 0;
+ }
+ if (movt.straigtenPath && path->settleStatus > 0) {
+ // individual is in a patch and has already determined whether to settle
+ rho = 0.99; // to promote leaving the patch
+ path->out = 0;
+ }
+ int loopsteps = 0; // new counter to prevent infinite loop added 14/8/15
+ do {
+ do {
+ // new direction
+ if (newX < land.minX || newX > land.maxX || newY < land.minY || newY > land.maxY
+ || pCurrCell == 0) {
+ // individual has tried to go out-of-bounds or into no-data area
+ // allow random move to prevent repeated similar move
+ angle = wrpcauchy(crw->prevdrn, 0.0);
+ }
+ else
+ angle = wrpcauchy(crw->prevdrn, rho);
+ // new continuous cell coordinates
+ xcnew = crw->xc + sin(angle) * steplen / (float)land.resol;
+ ycnew = crw->yc + cos(angle) * steplen / (float)land.resol;
+ if (xcnew < 0.0) newX = -1; else newX = (int)xcnew;
+ if (ycnew < 0.0) newY = -1; else newY = (int)ycnew;
+ loopsteps++;
+ } while (!absorbing && loopsteps < 1000 &&
+ (newX < land.minX || newX > land.maxX || newY < land.minY || newY > land.maxY));
+ if (newX < land.minX || newX > land.maxX || newY < land.minY || newY > land.maxY)
+ pCurrCell = 0;
+ else
+ pCurrCell = pLandscape->findCell(newX, newY);
+ if (pCurrCell == 0) { // no-data cell or beyond absorbing boundary
+ patch = 0;
+ if (absorbing) absorbed = true;
+ }
+ else
+ patch = pCurrCell->getPatch();
+ } while (!absorbing && pCurrCell == 0 && loopsteps < 1000);
+ crw->prevdrn = (float)angle;
+ crw->xc = (float)xcnew; crw->yc = (float)ycnew;
+ if (absorbed) { // beyond absorbing boundary or in no-data square
+ status = 6;
+ dispersing = 0;
+ pCurrCell = 0;
+ }
+ else {
+ if (loopsteps >= 1000) { // unable to make a move
+ // INTERNAL ERROR CONDITION - INDIVIDUAL IS IN NO-DATA SQUARE
+ // NEED TO TAKE SOME FORM OF INFORMATIVE ACTION ...
+ // ... individual dies as it cannot move
+ status = 6;
+ dispersing = 0;
+ // current cell will be invalid (zero), so set back to previous cell
+ pCurrCell = pPrevCell;
+ }
+ }
+ break;
+
+ } // end of switch (trfr.moveType)
+
+ if (patch > 0 // not no-data area or matrix
+ && path->total >= settsteps.minSteps) {
+ pPatch = (Patch*)patch;
+ if (pPatch != pNatalPatch)
+ {
+ // determine whether the new patch is potentially suitable
+ if (pPatch->getK() > 0.0)
+ { // patch is suitable
+ status = 2;
+ }
+ }
+ }
+ if (status != 2 && status != 6) { // suitable patch not found, not already dead
+ if (path->year >= settsteps.maxStepsYr) {
+ status = 3; // waits until next year
+ }
+ if (path->total >= settsteps.maxSteps) {
+ status = 6; // dies
+ dispersing = 0;
+ }
+ }
+ } // end of single movement step
+
+ return dispersing;
+
+}
+
+//---------------------------------------------------------------------------
+
+// Functions to implement the SMS algorithm
+
+// Move to a neighbouring cell according to the SMS algorithm
+movedata Individual::smsMove(Landscape* pLand, Species* pSpecies,
+ const short landIx, const bool natalPatch, const bool indvar, const bool absorbing)
+{
+
+ array3x3d nbr; // to hold weights/costs/probs of moving to neighbouring cells
+ array3x3d goal; // to hold weights for moving towards a goal location
+ array3x3f hab; // to hold weights for habitat (includes percep range)
+ int x2, y2; // x index from 0=W to 2=E, y index from 0=N to 2=S
+ int newX = 0, newY = 0;
+ Cell* pCell;
+ Cell* pNewCell = NULL;
+ double sum_nbrs = 0.0;
+ movedata move;
+ int cellcost, newcellcost;
+ locn current;
+
+ if (pCurrCell == 0)
+ {
+ // x,y is a NODATA square - this should not occur here
+ // return a negative distance to indicate an error
+ move.dist = -69.0; move.cost = 0.0;
+ return move;
+ }
+
+ landData land = pLand->getLandData();
+ trfrSMSTraits movt = pSpecies->getSMSTraits();
+ current = pCurrCell->getLocn();
+
+ //get weights for directional persistence....
+ if ((path->out > 0 && path->out <= (movt.pr + 1))
+ || natalPatch
+ || (movt.straigtenPath && path->settleStatus > 0)) {
+ // inflate directional persistence to promote leaving the patch
+ if (indvar) nbr = getSimDir(current.x, current.y, 10.0f * smsData->dp);
+ else nbr = getSimDir(current.x, current.y, 10.0f * movt.dp);
+ }
+ else {
+ if (indvar) nbr = getSimDir(current.x, current.y, smsData->dp);
+ else nbr = getSimDir(current.x, current.y, movt.dp);
+ }
+ if (natalPatch || path->settleStatus > 0) path->out = 0;
+
+ //get weights for goal bias....
+ double gb;
+ if (movt.goalType == 2) { // dispersal bias
+ int nsteps = 0;
+ if (path->year == path->total) { // first year of dispersal - use no. of steps outside natal patch
+ nsteps = path->out;
+ }
+ else { // use total no. of steps
+ nsteps = path->total;
+ }
+ if (indvar) {
+ double exp_arg = -((double)nsteps - (double)smsData->betaDB) * (-smsData->alphaDB);
+ if (exp_arg > 100.0) exp_arg = 100.0; // to prevent exp() overflow error
+ gb = 1.0 + (smsData->gb - 1.0) / (1.0 + exp(exp_arg));
+ }
+ else {
+ double exp_arg = -((double)nsteps - (double)movt.betaDB) * (-movt.alphaDB);
+ if (exp_arg > 100.0) exp_arg = 100.0; // to prevent exp() overflow error
+ gb = 1.0 + (movt.gb - 1.0) / (1.0 + exp(exp_arg));
+ }
+ }
+ else gb = movt.gb;
+ goal = getGoalBias(current.x, current.y, movt.goalType, (float)gb);
+
+ // get habitat-dependent weights (mean effective costs, given perceptual range)
+ // first check if costs have already been calculated
+
+ hab = pCurrCell->getEffCosts();
+
+ if (hab.cell[0][0] < 0.0) { // costs have not already been calculated
+ hab = getHabMatrix(pLand, pSpecies, current.x, current.y, movt.pr, movt.prMethod,
+ landIx, absorbing);
+ pCurrCell->setEffCosts(hab);
+ }
+ else {
+ // they have already been calculated - no action required
+ }
+
+ // determine weighted effective cost for the 8 neighbours
+ // multiply directional persistence, goal bias and habitat habitat-dependent weights
+ for (y2 = 2; y2 > -1; y2--) {
+ for (x2 = 0; x2 < 3; x2++) {
+ if (x2 == 1 && y2 == 1) nbr.cell[x2][y2] = 0.0;
+ else {
+ if (x2 == 1 || y2 == 1) //not diagonal
+ nbr.cell[x2][y2] = nbr.cell[x2][y2] * goal.cell[x2][y2] * hab.cell[x2][y2];
+ else // diagonal
+ nbr.cell[x2][y2] = (float)SQRT2 * nbr.cell[x2][y2] * goal.cell[x2][y2] * hab.cell[x2][y2];
+ }
+ }
+ }
+
+ // determine reciprocal of effective cost for the 8 neighbours
+ for (y2 = 2; y2 > -1; y2--) {
+ for (x2 = 0; x2 < 3; x2++) {
+ if (nbr.cell[x2][y2] > 0.0) nbr.cell[x2][y2] = 1.0f / nbr.cell[x2][y2];
+ }
+ }
+
+ // set any cells beyond the current landscape limits and any no-data cells
+ // to have zero probability
+ // increment total for re-scaling to sum to unity
+
+ for (y2 = 2; y2 > -1; y2--) {
+ for (x2 = 0; x2 < 3; x2++) {
+ if (!absorbing) {
+ if ((current.y + y2 - 1) < land.minY || (current.y + y2 - 1) > land.maxY
+ || (current.x + x2 - 1) < land.minX || (current.x + x2 - 1) > land.maxX)
+ // cell is beyond current landscape limits
+ nbr.cell[x2][y2] = 0.0;
+ else { // check if no-data cell
+ pCell = pLand->findCell((current.x + x2 - 1), (current.y + y2 - 1));
+ if (pCell == 0) nbr.cell[x2][y2] = 0.0; // no-data cell
+ }
+ }
+
+ sum_nbrs += nbr.cell[x2][y2];
+ }
+ }
+
+ // scale effective costs as probabilities summing to 1
+ if (sum_nbrs > 0.0) { // should always be the case, but safest to check...
+ for (y2 = 2; y2 > -1; y2--) {
+ for (x2 = 0; x2 < 3; x2++) {
+ nbr.cell[x2][y2] = nbr.cell[x2][y2] / (float)sum_nbrs;
+ }
+ }
+ }
+
+ // set up cell selection probabilities
+ double cumulative[9];
+ int j = 0;
+ cumulative[0] = nbr.cell[0][0];
+ for (y2 = 0; y2 < 3; y2++) {
+ for (x2 = 0; x2 < 3; x2++) {
+ if (j != 0) cumulative[j] = cumulative[j - 1] + nbr.cell[x2][y2];
+ j++;
+ }
+ }
+
+ // select direction at random based on cell selection probabilities
+ // landscape boundaries and no-data cells may be reflective or absorbing
+ cellcost = pCurrCell->getCost();
+ int loopsteps = 0; // new counter to prevent infinite loop added 14/8/15
+ do {
+ do {
+ double rnd = pRandom->Random();
+ j = 0;
+ for (y2 = 0; y2 < 3; y2++) {
+ for (x2 = 0; x2 < 3; x2++) {
+ if (rnd < cumulative[j]) {
+ newX = current.x + x2 - 1;
+ newY = current.y + y2 - 1;
+ if (x2 == 1 || y2 == 1) move.dist = (float)(land.resol);
+ else move.dist = (float)(land.resol) * (float)SQRT2;
+ y2 = 999; x2 = 999; //to break out of x2 and y2 loops.
+ }
+ j++;
+ }
+ }
+ loopsteps++;
+ } while (loopsteps < 1000
+ && (!absorbing && (newX < land.minX || newX > land.maxX
+ || newY < land.minY || newY > land.maxY)));
+ if (loopsteps >= 1000) pNewCell = 0;
+ else {
+ if (newX < land.minX || newX > land.maxX
+ || newY < land.minY || newY > land.maxY) {
+ pNewCell = 0;
+ }
+ pNewCell = pLand->findCell(newX, newY);
+ }
+ } while (!absorbing && pNewCell == 0 && loopsteps < 1000); // no-data cell
+ if (loopsteps >= 1000 || pNewCell == 0) {
+ // unable to make a move or crossed absorbing boundary
+ // flag individual to die
+ move.dist = -123.0;
+ if (pNewCell == 0) pCurrCell = pNewCell;
+ }
+ else {
+ newcellcost = pNewCell->getCost();
+ move.cost = move.dist * 0.5f * ((float)cellcost + (float)newcellcost);
+ // make the selected move
+ if ((short)memory.size() == movt.memSize) {
+ memory.pop(); // remove oldest memory element
+ }
+ memory.push(current); // record previous location in memory
+ pCurrCell = pNewCell;
+ }
+ return move;
+}
+
+// Weight neighbouring cells on basis of current movement direction
+array3x3d Individual::getSimDir(const int x, const int y, const float dp)
+{
+
+ array3x3d d;
+ locn prev;
+ double theta;
+ int xx, yy;
+
+ if (memory.empty())
+ { // no previous movement, set matrix to unity
+ for (xx = 0; xx < 3; xx++) {
+ for (yy = 0; yy < 3; yy++) {
+ d.cell[xx][yy] = 1;
+ }
+ }
+ }
+ else { // set up the matrix dependent on relationship of previous location to current
+ d.cell[1][1] = 0;
+ prev = memory.front();
+ if ((x - prev.x) == 0 && (y - prev.y) == 0) {
+ // back to 'square 1' (first memory location) - use previous step drn only
+ prev = memory.back();
+ if ((x - prev.x) == 0 && (y - prev.y) == 0) { // STILL HAVE A PROBLEM!
+ for (xx = 0; xx < 3; xx++) {
+ for (yy = 0; yy < 3; yy++) {
+ d.cell[xx][yy] = 1.0;
+ }
+ }
+ return d;
+ }
+ }
+ else {
+ }
+ theta = atan2(((double)x - (double)prev.x), ((double)y - (double)prev.y));
+ d = calcWeightings(dp, (float)theta);
+
+ }
+ return d;
+}
+
+// Weight neighbouring cells on basis of goal bias
+array3x3d Individual::getGoalBias(const int x, const int y,
+ const int goaltype, const float gb)
+{
+
+ array3x3d d;
+ double theta;
+ int xx, yy;
+
+ if (goaltype == 0) { // no goal set
+ for (xx = 0; xx < 3; xx++) {
+ for (yy = 0; yy < 3; yy++) {
+ d.cell[xx][yy] = 1.0;
+ }
+ }
+ }
+ else {
+ d.cell[1][1] = 0;
+ if ((x - smsData->goal.x) == 0 && (y - smsData->goal.y) == 0) {
+ // at goal, set matrix to unity
+ for (xx = 0; xx < 3; xx++) {
+ for (yy = 0; yy < 3; yy++) {
+ d.cell[xx][yy] = 1.0;
+ }
+ }
+ return d;
+ }
+ if (goaltype == 1) {
+ // TEMPORARY CODE - GOAL TYPE 1 NOT YET IMPLEMENTED, AS WE HAVE NO MEANS OF
+ // CAPTURING THE GOAL LOCATION OF EACH INDIVIDUAL
+ for (xx = 0; xx < 3; xx++) {
+ for (yy = 0; yy < 3; yy++) {
+ d.cell[xx][yy] = 1.0;
+ }
+ }
+ return d;
+ }
+ else // goaltype == 2
+ theta = atan2(((double)x - (double)smsData->goal.x), ((double)y - (double)smsData->goal.y));
+ d = calcWeightings(gb, (float)theta);
+ }
+
+ return d;
+}
+
+// Calculate weightings for neighbouring cells
+array3x3d Individual::calcWeightings(const double base, const double theta) {
+
+ array3x3d d; // 3x3 array indexed from SW corner by xx and yy
+ int dx, dy, xx, yy;
+
+ double i0 = 1.0; // direction of theta - lowest cost bias
+ double i1 = base;
+ double i2 = base * base;
+ double i3 = i2 * base;
+ double i4 = i3 * base; // opposite to theta - highest cost bias
+
+ if (fabs(theta) > 7.0 * PI / 8.0) { dx = 0; dy = -1; }
+ else {
+ if (fabs(theta) > 5.0 * PI / 8.0) { dy = -1; if (theta > 0) dx = 1; else dx = -1; }
+ else {
+ if (fabs(theta) > 3.0 * PI / 8.0) { dy = 0; if (theta > 0) dx = 1; else dx = -1; }
+ else {
+ if (fabs(theta) > PI / 8.0) { dy = 1; if (theta > 0) dx = 1; else dx = -1; }
+ else { dy = 1; dx = 0; }
+ }
+ }
+ }
+ d.cell[1][1] = 0; // central cell has zero weighting
+ d.cell[dx + 1][dy + 1] = (float)i0;
+ d.cell[-dx + 1][-dy + 1] = (float)i4;
+ if (dx == 0 || dy == 0) { // theta points to a cardinal direction
+ d.cell[dy + 1][dx + 1] = (float)i2; d.cell[-dy + 1][-dx + 1] = (float)i2;
+ if (dx == 0) { // theta points N or S
+ xx = dx + 1; if (xx > 1) dx -= 2; yy = dy;
+ d.cell[xx + 1][yy + 1] = (float)i1; d.cell[-xx + 1][yy + 1] = (float)i1;
+ d.cell[xx + 1][-yy + 1] = (float)i3; d.cell[-xx + 1][-yy + 1] = (float)i3;
+ }
+ else { // theta points W or E
+ yy = dy + 1; if (yy > 1) dy -= 2; xx = dx;
+ d.cell[xx + 1][yy + 1] = (float)i1; d.cell[xx + 1][-yy + 1] = (float)i1;
+ d.cell[-xx + 1][yy + 1] = (float)i3; d.cell[-xx + 1][-yy + 1] = (float)i3;
+ }
+ }
+ else { // theta points to an ordinal direction
+ d.cell[dx + 1][-dy + 1] = (float)i2; d.cell[-dx + 1][dy + 1] = (float)i2;
+ xx = dx + 1; if (xx > 1) xx -= 2; d.cell[xx + 1][dy + 1] = (float)i1;
+ yy = dy + 1; if (yy > 1) yy -= 2; d.cell[dx + 1][yy + 1] = (float)i1;
+ d.cell[-xx + 1][-dy + 1] = (float)i3; d.cell[-dx + 1][-yy + 1] = (float)i3;
+ }
+
+ return d;
+}
+
+// Weight neighbouring cells on basis of (habitat) costs
+array3x3f Individual::getHabMatrix(Landscape* pLand, Species* pSpecies,
+ const int x, const int y, const short pr, const short prmethod, const short landIx,
+ const bool absorbing)
+{
+
+ array3x3f w; // array of effective costs to be returned
+ int ncells, x4, y4;
+ double weight, sumweights;
+ // NW and SE corners of effective cost array relative to the current cell (x,y):
+ int xmin = 0, ymin = 0, xmax = 0, ymax = 0;
+ int cost, nodatacost, h;
+ Cell* pCell;
+
+ landData land = pLand->getLandData();
+ if (absorbing) nodatacost = ABSNODATACOST;
+ else nodatacost = NODATACOST;
+
+ for (int x2 = -1; x2 < 2; x2++) { // index of relative move in x direction
+ for (int y2 = -1; y2 < 2; y2++) { // index of relative move in x direction
+
+ w.cell[x2 + 1][y2 + 1] = 0.0; // initialise costs array to zeroes
+
+ // set up corners of perceptual range relative to current cell
+ if (x2 == 0 && y2 == 0) { // current cell - do nothing
+ xmin = 0; ymin = 0; xmax = 0; ymax = 0;
+ }
+ else {
+ if (x2 == 0 || y2 == 0) { // not diagonal (rook move)
+ if (x2 == 0) { // vertical (N-S) move
+ if (pr % 2 == 0) { xmin = -pr / 2; xmax = pr / 2; ymin = y2; ymax = y2 * pr; } // PR even
+ else { xmin = -(pr - 1) / 2; xmax = (pr - 1) / 2; ymin = y2; ymax = y2 * pr; } // PR odd
+ }
+ if (y2 == 0) { // horizontal (E-W) move
+ if (pr % 2 == 0) { xmin = x2; xmax = x2 * pr; ymin = -pr / 2; ymax = pr / 2; } // PR even
+ else { xmin = x2; xmax = x2 * pr; ymin = -(pr - 1) / 2; ymax = (pr - 1) / 2; } // PR odd
+ }
+ }
+ else { // diagonal (bishop move)
+ xmin = x2; xmax = x2 * pr; ymin = y2; ymax = y2 * pr;
+ }
+ }
+ if (xmin > xmax) { int z = xmax; xmax = xmin; xmin = z; } // swap xmin and xmax
+ if (ymin > ymax) { int z = ymax; ymax = ymin; ymin = z; } // swap ymin and ymax
+
+ // calculate effective mean cost of cells in perceptual range
+ ncells = 0; weight = 0.0; sumweights = 0.0;
+ if (x2 != 0 || y2 != 0) { // not central cell (i.e. current cell)
+ for (int x3 = xmin; x3 <= xmax; x3++) {
+ for (int y3 = ymin; y3 <= ymax; y3++) {
+ // if cell is out of bounds, treat landscape as a torus
+ // for purpose of obtaining a cost,
+ if ((x + x3) < 0) x4 = x + x3 + land.maxX + 1;
+ else { if ((x + x3) > land.maxX) x4 = x + x3 - land.maxX - 1; else x4 = x + x3; }
+ if ((y + y3) < 0) y4 = y + y3 + land.maxY + 1;
+ else { if ((y + y3) > land.maxY) y4 = y + y3 - land.maxY - 1; else y4 = y + y3; }
+ if (x4 < 0 || x4 > land.maxX || y4 < 0 || y4 > land.maxY) {
+ // unexpected problem - e.g. due to ridiculously large PR
+ // treat as a no-data cell
+ cost = nodatacost;
+ }
+ else {
+ // add cost of cell to total PR cost
+ pCell = pLand->findCell(x4, y4);
+ if (pCell == 0) { // no-data cell
+ cost = nodatacost;
+ }
+ else {
+ cost = pCell->getCost();
+ if (cost < 0) cost = nodatacost;
+ else {
+ if (cost == 0) { // cost not yet set for the cell
+ h = pCell->getHabIndex(landIx);
+ cost = pSpecies->getHabCost(h);
+ pCell->setCost(cost);
+ }
+ else {
+
+ }
+ }
+ }
+ }
+ if (prmethod == 1) { // arithmetic mean
+ w.cell[x2 + 1][y2 + 1] += cost;
+ ncells++;
+ }
+ if (prmethod == 2) { // harmonic mean
+ if (cost > 0) {
+ w.cell[x2 + 1][y2 + 1] += (1.0f / (float)cost);
+ ncells++;
+ }
+ }
+ if (prmethod == 3) { // arithmetic mean weighted by inverse distance
+ if (cost > 0) {
+ // NB distance is still given by (x3,y3)
+ weight = 1.0f / (double)sqrt((pow((double)x3, 2) + pow((double)y3, 2)));
+ w.cell[x2 + 1][y2 + 1] += (float)(weight * (double)cost);
+ ncells++; sumweights += weight;
+ }
+ }
+ } //end of y3 loop
+ } //end of x3 loop
+ if (ncells > 0) {
+ if (prmethod == 1) w.cell[x2 + 1][y2 + 1] /= ncells; // arithmetic mean
+ if (prmethod == 2) w.cell[x2 + 1][y2 + 1] = ncells / w.cell[x2 + 1][y2 + 1]; // hyperbolic mean
+ if (prmethod == 3 && sumweights > 0)
+ w.cell[x2 + 1][y2 + 1] /= (float)sumweights; // weighted arithmetic mean
+ }
+ }
+ else { // central cell
+ // record cost if not already recorded
+ // has effect of preparing for storing effective costs for the cell
+ pCell = pLand->findCell(x, y);
+ cost = pCell->getCost();
+ if (cost < 0) cost = nodatacost;
+ else {
+ if (cost == 0) { // cost not yet set for the cell
+ h = pCell->getHabIndex(landIx);
+ cost = pSpecies->getHabCost(h);
+ pCell->setCost(cost);
+ }
+ }
+ }
+ }//end of y2 loop
+ }//end of x2 loop
+
+ return w;
+
+}
+
+//---------------------------------------------------------------------------
+// Write records to individuals file
+void Individual::outGenetics(const int rep, const int year, const int spnum,
+ const int landNr, const bool xtab)
+{
+ if (landNr == -1) {
+ if (pGenome != 0) {
+ pGenome->outGenetics(rep, year, spnum, indId, xtab);
+ }
+ }
+ else { // open/close file
+ pGenome->outGenHeaders(rep, landNr, xtab);
+ }
+
+}
+
+#if RS_RCPP
+//---------------------------------------------------------------------------
+// Write records to movement paths file
+void Individual::outMovePath(const int year)
+{
+ locn loc, prev_loc;
+
+ //if (pPatch != pNatalPatch) {
+ loc = pCurrCell->getLocn();
+ // if still dispersing...
+ if (status == 1) {
+ // at first step, record start cell first
+ if (path->total == 1) {
+ prev_loc = pPrevCell->getLocn();
+ outMovePaths << year << "\t" << indId << "\t"
+ << "0\t" << prev_loc.x << "\t" << prev_loc.y << "\t"
+ << "0\t" // status at start cell is 0
+ << endl;
+ }
+ // then record current step
+ outMovePaths << year << "\t" << indId << "\t"
+ << path->total << "\t" << loc.x << "\t" << loc.y << "\t"
+ << status << "\t"
+ << endl;
+ }
+ // if not anymore dispersing...
+ if (status > 1 && status < 10) {
+ prev_loc = pPrevCell->getLocn();
+ // record only if this is the first step as non-disperser
+ if (path->pathoutput) {
+ // if this is also the first step taken at all, record the start cell first
+ if (path->total == 1) {
+ outMovePaths << year << "\t" << indId << "\t"
+ << "0\t" << prev_loc.x << "\t" << prev_loc.y << "\t"
+ << "0\t" // status at start cell is 0
+ << endl;
+ }
+ outMovePaths << year << "\t" << indId << "\t"
+ << path->total << "\t" << loc.x << "\t" << loc.y << "\t"
+ << status << "\t"
+ << endl;
+ // current cell will be invalid (zero), so set back to previous cell
+ //pPrevCell = pCurrCell;
+ path->pathoutput = 0;
+ }
+ }
+}
+#endif
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+
+double wrpcauchy(double location, double rho) {
+ double result;
+
+ if (rho < 0.0 || rho > 1.0) {
+ result = location;
+ }
+
+ if (rho == 0)
+ result = pRandom->Random() * M_2PI;
+ else
+ if (rho == 1) result = location;
+ else {
+ result = fmod(cauchy(location, -log(rho)), M_2PI);
+ }
+ return result;
+}
+
+double cauchy(double location, double scale) {
+ if (scale < 0) return location;
+ return location + scale * tan(PI * pRandom->Random());
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+#if RSDEBUG
+
+
+void testIndividual() {
+
+ Patch* pPatch = new Patch(0, 0);
+ int cell_x = 2;
+ int cell_y = 5;
+ int cell_hab = 2;
+ Cell* pCell = new Cell(cell_x, cell_y, (intptr)pPatch, cell_hab);
+
+ // Create an individual
+ short stg = 0;
+ short age = 0;
+ short repInt = 0;
+ float probmale = 0;
+ bool uses_movt_process = true;
+ short moveType = 1;
+ Individual ind(pCell, pPatch, stg, age, repInt, probmale, uses_movt_process, moveType);
+
+ // An individual can move to a neighbouring cell
+ //ind.moveto();
+
+ // Gets its sex drawn from pmale
+
+ // Can age or develop
+
+ //
+
+ // Reproduces
+ // depending on whether it is sexual or not
+ // depending on the stage
+ // depending on the trait inheritance
+
+
+ // Disperses
+ // Emigrates
+ // Transfers
+ // Settles
+
+ // Survives
+
+ // Develops
+
+}
+#endif // RSDEBUG
+
diff --git a/src/RScore/Individual.h b/src/RScore/Individual.h
new file mode 100644
index 00000000..bdc4ecbd
--- /dev/null
+++ b/src/RScore/Individual.h
@@ -0,0 +1,312 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 Individual
+
+Implements the Individual class
+
+Various optional attributes (genes for traits, movement parameters, etc.) are
+allocated dynamically and accessed by pointers if required.
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Peer G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 26 October 2021 by Steve Palmer
+
+------------------------------------------------------------------------------*/
+
+#ifndef IndividualH
+#define IndividualH
+
+
+#include
+#include
+using namespace std;
+
+#include "Parameters.h"
+#include "Species.h"
+#include "Landscape.h"
+#include "Patch.h"
+#include "Cell.h"
+#include "Genome.h"
+
+#define NODATACOST 100000 // cost to use in place of nodata value for SMS
+#define ABSNODATACOST 100 // cost to use in place of nodata value for SMS
+ // when boundaries are absorbing
+
+//---------------------------------------------------------------------------
+
+struct indStats {
+ short stage; short sex; short age; short status; short fallow;
+ bool isDeveloping;
+};
+struct pathData { // to hold path data common to SMS and CRW models
+ int year, total, out; // nos. of steps
+ Patch* pSettPatch; // pointer to most recent patch tested for settlement
+ short settleStatus; // whether ind may settle in current patch
+ // 0 = not set, 1 = debarred through density dependence rule
+ // 2 = OK to settle subject to finding a mate
+#if RS_RCPP
+ short pathoutput;
+#endif
+};
+struct pathSteps { // nos. of steps for movement model
+ int year, total, out;
+};
+struct settlePatch {
+ Patch* pSettPatch; short settleStatus;
+};
+struct crwParams { // to hold data for CRW movement model
+ float prevdrn; // direction of previous step (UNITS)
+ float xc,yc; // continuous cell co-ordinates
+ float stepL; // phenotypic step length (m)
+ float rho; // phenotypic step correlation coefficient
+};
+struct array3x3d { double cell[3][3]; };
+struct movedata { float dist; float cost; };
+struct smsdata {
+ locn prev; // location of previous cell
+ locn goal; // location of goal
+ float dp; // directional persistence
+ float gb; // goal bias
+ float alphaDB; // dispersal bias decay rate
+ int betaDB; // dispersal bias decay inflection point (no. of steps)
+};
+
+class Individual {
+
+public:
+ static int indCounter; // used to create ID, held by class, not members of class
+ Individual( // Individual constructor
+ Cell*, // pointer to Cell
+ Patch*, // pointer to patch
+ short, // stage
+ short, // age
+ short, // reproduction interval (no. of years/seasons between breeding attempts)
+ float, // probability that sex is male
+ bool, // TRUE for a movement model, FALSE for kernel-based transfer
+ short // movement type: 1 = SMS, 2 = CRW
+ );
+ ~Individual(void);
+ void setGenes( // Set genes for individual variation from species initialisation parameters
+ Species*, // pointer to Species
+ int // Landscape resolution
+ );
+ void setGenes( // Inherit genome from parents
+ Species*, // pointer to Species
+ Individual*, // pointer to mother
+ Individual*, // pointer to father (must be 0 for an asexual Species)
+ int // Landscape resolution
+ );
+ void setEmigTraits( // Set phenotypic emigration traits
+ Species*, // pointer to Species
+ short, // location of emigration genes on genome
+ short, // number of emigration genes
+ bool // TRUE if emigration is sex-dependent
+ );
+ emigTraits getEmigTraits(void); // Get phenotypic emigration traits
+
+ void setKernTraits( // Set phenotypic transfer by kernel traits
+ Species*, // pointer to Species
+ short, // location of kernel genes on genome
+ short, // number of kernel genes
+ int, // Landscape resolution
+ bool // TRUE if transfer is sex-dependent
+ );
+ trfrKernTraits getKernTraits(void); // Get phenotypic transfer by kernel traits
+
+ void setSMSTraits( // Set phenotypic transfer by SMS traits
+ Species*, // pointer to Species
+ short, // location of SMS genes on genome
+ short, // number of SMS genes
+ bool // TRUE if transfer is sex-dependent
+ );
+ trfrSMSTraits getSMSTraits(void); // Get phenotypic transfer by SMS traits
+ void setCRWTraits( // Set phenotypic transfer by CRW traits
+ Species*, // pointer to Species
+ short, // location of CRW genes on genome
+ short, // number of CRW genes
+ bool // TRUE if transfer is sex-dependent
+ );
+ trfrCRWTraits getCRWTraits(void); // Get phenotypic transfer by CRW traits
+
+ void setSettTraits( // Set phenotypic settlement traits
+ Species*, // pointer to Species
+ short, // location of settlement genes on genome
+ short, // number of settlement genes
+ bool // TRUE if settlement is sex-dependent
+ );
+ settleTraits getSettTraits(void); // Get phenotypic settlement traits
+
+ // Identify whether an individual is a potentially breeding female -
+ // if so, return her stage, otherwise return 0
+ int breedingFem(void);
+ int getId(void);
+ int getSex(void);
+ int getStatus(void);
+ indStats getStats(void);
+ Cell* getLocn( // Return location (as pointer to Cell)
+ const short // option: 0 = get natal locn, 1 = get current locn
+ ); //
+ Patch* getNatalPatch(void);
+ void setYearSteps(int);
+ pathSteps getSteps(void);
+ settlePatch getSettPatch(void);
+ void setSettPatch(const settlePatch);
+ void setStatus(short);
+ void developing(void);
+ void develop(void);
+ void ageIncrement( // Age by one year
+ short // maximum age - if exceeded, the Individual dies
+ );
+ void incFallow(void); // Inrement no. of reproductive seasons since last reproduction
+ void resetFallow(void);
+ void moveto( // Move to a specified neighbouring cell
+ Cell* // pointer to the new cell
+ );
+ // Move to a new cell by sampling a dispersal distance from a single or double
+ // negative exponential kernel
+ // Returns 1 if still dispersing (including having found a potential patch), otherwise 0
+ int moveKernel(
+ Landscape*, // pointer to Landscape
+ Species*, // pointer to Species
+ const short, // reproduction type (see Species)
+ const bool // absorbing boundaries?
+ );
+ // Make a single movement step according to a mechanistic movement model
+ // Returns 1 if still dispersing (including having found a potential patch), otherwise 0
+ int moveStep(
+ Landscape*, // pointer to Landscape
+ Species*, // pointer to Species
+ const short, // landscape change index
+ const bool // absorbing boundaries?
+ );
+ movedata smsMove( // Move to a neighbouring cell according to the SMS algorithm
+ Landscape*, // pointer to Landscape
+ Species*, // pointer to Species
+ const short, // landscape change index
+ const bool, // TRUE if still in (or returned to) natal patch
+ const bool, // individual variability?
+ const bool // absorbing boundaries?
+ );
+ array3x3d getSimDir( // Weight neighbouring cells on basis of current movement direction
+ const int, // current x co-ordinate
+ const int, // current y co-ordinate
+ const float // directional persistence value
+ );
+ array3x3d getGoalBias( // Weight neighbouring cells on basis of goal bias
+ const int, // current x co-ordinate
+ const int, // current y co-ordinate
+ const int, // goal type: 0 = none, 1 = towards goal (NOT IMPLEMENTED), 2 = dispersal bias
+ const float // GOAL BIAS VALUE
+ );
+ array3x3d calcWeightings( // Calculate weightings for neighbouring cells
+ const double, // base for power-law (directional persistence or goal bias value)
+ const double // direction in which lowest (unit) weighting is to be applied
+ );
+ array3x3f getHabMatrix( // Weight neighbouring cells on basis of (habitat) costs
+ Landscape*, // pointer to Landscape
+ Species*, // pointer to Species
+ const int, // current x co-ordinate
+ const int, // current y co-ordinate
+ const short, // perceptual range (cells)
+ const short, // perceptual range evaluation method (see Species)
+ const short, // landscape change index
+ const bool // absorbing boundaries?
+ );
+ void outGenetics( // Write records to genetics file
+ const int, // replicate
+ const int, // year
+ const int, // species number
+ const int, // landscape number
+ const bool // output as cross table?
+ );
+#if RS_RCPP
+ void outMovePath( // Write records to movement paths file
+ const int // year
+ );
+#endif
+
+private:
+ int indId;
+ short stage;
+ short sex;
+ short age;
+ short status; // 0 = initial status in natal patch / philopatric recruit
+ // 1 = disperser
+ // 2 = disperser awaiting settlement in possible suitable patch
+ // 3 = waiting between dispersal events
+ // 4 = completed settlement
+ // 5 = completed settlement in a suitable neighbouring cell
+ // 6 = died during transfer by failing to find a suitable patch
+ // (includes exceeding maximum number of steps or crossing
+ // absorbing boundary)
+ // 7 = died during transfer by constant, step-dependent,
+ // habitat-dependent or distance-dependent mortality
+ // 8 = failed to survive annual (demographic) mortality
+ // 9 = exceeded maximum age
+ short fallow; // reproductive seasons since last reproduction
+ bool isDeveloping;
+ Cell *pPrevCell; // pointer to previous Cell
+ Cell *pCurrCell; // pointer to current Cell
+ Patch *pNatalPatch; // pointer to natal Patch
+ emigTraits *emigtraits; // pointer to emigration traits
+ trfrKernTraits *kerntraits; // pointers to transfer by kernel traits
+ pathData *path; // pointer to path data for movement model
+ crwParams *crw; // pointer to CRW traits and data
+ smsdata *smsData; // pointer to variables required for SMS
+ settleTraits *setttraits; // pointer to settlement traits
+ std::queue memory; // memory of last N squares visited for SMS
+
+ Genome *pGenome;
+
+};
+
+
+//---------------------------------------------------------------------------
+
+double cauchy(double location, double scale) ;
+double wrpcauchy (double location, double rho = exp(double(-1)));
+
+extern RSrandom *pRandom;
+
+#if RSDEBUG
+extern ofstream DEBUGLOG;
+#endif
+
+#if RS_RCPP
+extern ofstream outMovePaths;
+#endif
+
+#if RSDEBUG
+void testIndividual();
+#endif
+
+//---------------------------------------------------------------------------
+#endif // IndividualH
diff --git a/src/RScore/LICENSE b/src/RScore/LICENSE
new file mode 100644
index 00000000..94a9ed02
--- /dev/null
+++ b/src/RScore/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/src/RScore/Landscape.cpp b/src/RScore/Landscape.cpp
new file mode 100644
index 00000000..fe1e9d9f
--- /dev/null
+++ b/src/RScore/Landscape.cpp
@@ -0,0 +1,2645 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+ //---------------------------------------------------------------------------
+
+#include "Landscape.h"
+//---------------------------------------------------------------------------
+
+ifstream landscape;
+
+ofstream outConnMat;
+ofstream outvisits;
+#if RS_RCPP
+ofstream outMovePaths;
+#endif // RS_RCPP
+
+//---------------------------------------------------------------------------
+
+// Initial species distribution functions
+
+InitDist::InitDist(Species* pSp)
+{
+ pSpecies = pSp;
+ resol = 0;
+ maxX = 0;
+ maxY = 0;
+ minEast = 0.0;
+ minNorth = 0.0;
+}
+
+InitDist::~InitDist() {
+ int ncells = (int)cells.size();
+ for (int i = 0; i < ncells; i++)
+ if (cells[i] != NULL) delete cells[i];
+ cells.clear();
+}
+
+void InitDist::setDistribution(int nInit) {
+ int rr = 0;
+ int ncells = (int)cells.size();
+ if (nInit == 0) { // set all cells to be initialised
+ for (int i = 0; i < ncells; i++) {
+ cells[i]->setCell(true);
+ }
+ }
+ else { // set specified number of cells at random to be initialised
+ if (nInit > ncells / 2) { // use backwards selection method
+ for (int i = 0; i < ncells; i++) cells[i]->setCell(true);
+ for (int i = 0; i < (ncells - nInit); i++) {
+ do {
+ rr = pRandom->IRandom(0, ncells - 1);
+ } while (!cells[rr]->selected());
+ cells[rr]->setCell(false);
+ }
+ }
+ else { // use forwards selection method
+ for (int i = 0; i < ncells; i++) cells[i]->setCell(false);
+ for (int i = 0; i < nInit; i++) {
+ do {
+ rr = pRandom->IRandom(0, ncells - 1);
+ } while (cells[rr]->selected());
+ cells[rr]->setCell(true);
+ }
+ }
+ }
+}
+
+// Set a specified cell (by position in cells vector)
+void InitDist::setDistCell(int ix, bool init) {
+ cells[ix]->setCell(init);
+}
+
+// Set a specified cell (by co-ordinates)
+void InitDist::setDistCell(locn loc, bool init) {
+ locn cellloc;
+ int ncells = (int)cells.size();
+ for (int i = 0; i < ncells; i++) {
+ cellloc = cells[i]->getLocn();
+ if (cellloc.x == loc.x && cellloc.y == loc.y) {
+ cells[i]->setCell(init);
+ i = ncells;
+ }
+ }
+}
+
+// Specified location is within the initial distribution?
+bool InitDist::inInitialDist(locn loc) {
+ int ncells = (int)cells.size();
+ for (int i = 0; i < ncells; i++) {
+ if (cells[i]->toInitialise(loc)) { // cell is to be initialised
+ return true;
+ }
+ }
+ return false;
+}
+
+int InitDist::cellCount(void) {
+ return (int)cells.size();
+}
+
+// Return the co-ordinates of a specified initial distribution cell
+locn InitDist::getCell(int ix) {
+ locn loc;
+ if (ix >= 0 && ix < (int)cells.size()) {
+ loc = cells[ix]->getLocn();
+ }
+ else {
+ loc.x = loc.y = -666; // indicates invalid index specified
+ }
+ return loc;
+}
+
+// Return the co-ordinates of a specified initial distribution cell if it has been
+// selected - otherwise return negative co-ordinates
+locn InitDist::getSelectedCell(int ix) {
+ locn loc; loc.x = loc.y = -666;
+ if (ix < (int)cells.size()) {
+ if (cells[ix]->selected()) {
+ loc = cells[ix]->getLocn();
+ }
+ }
+ return loc;
+}
+
+locn InitDist::getDimensions(void) {
+ locn d; d.x = maxX; d.y = maxY; return d;
+}
+
+void InitDist::resetDistribution(void) {
+ int ncells = (int)cells.size();
+ for (int i = 0; i < ncells; i++) {
+ cells[i]->setCell(false);
+ }
+}
+
+//---------------------------------------------------------------------------
+
+// Read species initial distribution file
+
+int InitDist::readDistribution(string distfile) {
+#if RS_RCPP
+ wstring header;
+#else
+ string header;
+#endif
+ int p, nodata;
+ int ncols, nrows;
+#if RS_RCPP
+ wifstream dfile; // species distribution file input stream
+#else
+ ifstream dfile; // species distribution file input stream
+#endif
+
+ // open distribution file
+#if !RS_RCPP || RSWIN64
+ dfile.open(distfile.c_str());
+#else
+ dfile.open(distfile, std::ios::binary);
+ if (spdistraster.utf) {
+ // apply BOM-sensitive UTF-16 facet
+ dfile.imbue(std::locale(dfile.getloc(), new std::codecvt_utf16));
+ }
+#endif
+ if (!dfile.is_open()) return 21;
+
+ // read landscape data from header records of distribution file
+ // NB headers of all files have already been compared
+ dfile >> header >> ncols >> header >> nrows >> header >> minEast >> header >> minNorth
+ >> header >> resol >> header >> nodata;
+#if RS_RCPP
+ if (!dfile.good()) {
+ // corrupt file stream
+ StreamErrorR(distfile);
+ dfile.close();
+ dfile.clear();
+ return 144;
+ }
+#endif
+
+ maxX = ncols - 1; maxY = nrows - 1;
+
+ // set up bad integer value to ensure that valid values are read
+ int badvalue = -9; if (nodata == -9) badvalue = -99;
+
+ for (int y = nrows - 1; y >= 0; y--) {
+ for (int x = 0; x < ncols; x++) {
+ p = badvalue;
+#if RS_RCPP
+ if (dfile >> p) {
+#else
+ dfile >> p;
+#endif
+ if (p == nodata || p == 0 || p == 1) { // only valid values
+ if (p == 1) { // species present
+ cells.push_back(new DistCell(x, y));
+ }
+ }
+ else { // error in file
+ dfile.close(); dfile.clear();
+ return 22;
+ }
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR(distfile);
+ dfile.close();
+ dfile.clear();
+ return 144;
+ }
+#endif
+ }
+ }
+#if RS_RCPP
+dfile >> p;
+if (!dfile.eof()) EOFerrorR(distfile);
+#endif
+
+ dfile.close(); dfile.clear();
+ return 0;
+}
+
+
+//---------------------------------------------------------------------------
+
+// Landscape functions
+
+Landscape::Landscape(void) {
+ patchModel = false; spDist = false; generated = false; fractal = false; continuous = false;
+ dynamic = false; habIndexed = false;
+ resol = spResol = landNum = 0;
+ rasterType = 0;
+ nHab = nHabMax = 0;
+ dimX = dimY = 100;
+ minX = minY = 0;
+ maxX = maxY = 99;
+ minPct = maxPct = propSuit = hurst = 0.0;
+ maxCells = 100;
+ gpix = 1.0;
+ pix = (int)gpix;
+ minEast = minNorth = 0.0;
+ cells = 0;
+ connectMatrix = 0;
+ epsGlobal = 0;
+ patchChgMatrix = 0;
+ costsChgMatrix = 0;
+}
+
+Landscape::~Landscape() {
+
+ if (cells != 0) {
+ for (int y = dimY - 1; y >= 0; y--) {
+
+ for (int x = 0; x < dimX; x++) {
+
+ if (cells[y][x] != 0) delete cells[y][x];
+ }
+ if (cells[y] != 0) {
+ delete[] cells[y];
+ }
+ }
+ delete[] cells;
+ cells = 0;
+ }
+ int npatches = (int)patches.size();
+ for (int i = 0; i < npatches; i++)
+ if (patches[i] != NULL) delete patches[i];
+ patches.clear();
+
+ int ndistns = (int)distns.size();
+ for (int i = 0; i < ndistns; i++)
+ if (distns[i] != NULL) delete distns[i];
+ distns.clear();
+
+ int ninitcells = (int)initcells.size();
+ for (int i = 0; i < ninitcells; i++)
+ if (initcells[i] != NULL) delete initcells[i];
+ initcells.clear();
+
+ patchnums.clear();
+ habCodes.clear();
+ colours.clear();
+ landchanges.clear();
+ patchchanges.clear();
+
+ deleteConnectMatrix();
+ deletePatchChgMatrix();
+ if (epsGlobal != 0) delete[] epsGlobal;
+
+}
+
+// Remove all patches and cells
+// Used for replicating artificial landscape without deleting the landscape itself
+void Landscape::resetLand(void) {
+
+ resetLandLimits();
+ int npatches = (int)patches.size();
+ for (int i = 0; i < npatches; i++) if (patches[i] != NULL) delete patches[i];
+ patches.clear();
+
+ if (cells != 0) {
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] != 0) delete cells[y][x];
+ }
+ if (cells[y] != 0) {
+ delete[] cells[y];
+ }
+ }
+ delete[] cells;
+ cells = 0;
+ }
+}
+
+void Landscape::setLandParams(landParams ppp, bool batchMode)
+{
+ generated = ppp.generated; patchModel = ppp.patchModel; spDist = ppp.spDist;
+ dynamic = ppp.dynamic;
+ landNum = ppp.landNum;
+ if (ppp.resol > 0) resol = ppp.resol;
+ if (ppp.spResol > 0 && ppp.spResol % ppp.resol == 0) spResol = ppp.spResol;
+ if ((ppp.rasterType >= 0 && ppp.rasterType <= 2) || ppp.rasterType == 9)
+ rasterType = ppp.rasterType;
+ if (ppp.nHab >= 1) nHab = ppp.nHab;
+ if (ppp.nHabMax >= 1) nHabMax = ppp.nHabMax;
+ if (ppp.dimX > 0) dimX = ppp.dimX;
+ if (ppp.dimY > 0) dimY = ppp.dimY;
+ if (ppp.minX >= 0 && ppp.maxX >= 0 && ppp.minX <= ppp.maxX && ppp.maxX < dimX) {
+ minX = ppp.minX; maxX = ppp.maxX;
+ }
+ else {
+ minX = 0; maxX = dimX - 1;
+ }
+ if (ppp.minY >= 0 && ppp.maxY >= 0 && ppp.minY <= ppp.maxY && ppp.maxY < dimY) {
+ minY = ppp.minY; maxY = ppp.maxY;
+ }
+ else {
+ minY = 0; maxY = dimY - 1;
+ }
+ if (batchMode && rasterType == 0) {
+ // in batch mode, set up sequential habitat codes if not already present
+ if (habCodes.size() == 0) {
+ for (int i = 0; i < nHabMax; i++) {
+ habCodes.push_back(i + 1);
+ }
+ }
+ }
+}
+
+landParams Landscape::getLandParams(void)
+{
+ landParams ppp;
+ ppp.generated = generated; ppp.patchModel = patchModel; ppp.spDist = spDist;
+ ppp.dynamic = dynamic;
+ ppp.landNum = landNum;
+ ppp.resol = resol; ppp.spResol = spResol;
+ ppp.rasterType = rasterType;
+ ppp.nHab = nHab; ppp.nHabMax = nHabMax;
+ ppp.dimX = dimX; ppp.dimY = dimY;
+ ppp.minX = minX; ppp.minY = minY;
+ ppp.maxX = maxX; ppp.maxY = maxY;
+ return ppp;
+}
+
+landData Landscape::getLandData(void) {
+ landData dd;
+ dd.resol = resol;
+ dd.dimX = dimX; dd.dimY = dimY;
+ dd.minX = minX; dd.minY = minY;
+ dd.maxX = maxX; dd.maxY = maxY;
+ return dd;
+}
+
+void Landscape::setGenLandParams(genLandParams ppp)
+{
+ fractal = ppp.fractal;
+ continuous = ppp.continuous;
+ if (ppp.minPct > 0.0 && ppp.minPct < 100.0) minPct = ppp.minPct;
+ if (ppp.maxPct > 0.0 && ppp.maxPct <= 100.0) maxPct = ppp.maxPct;
+ if (ppp.propSuit >= 0.0 && ppp.propSuit <= 1.0) propSuit = ppp.propSuit;
+ if (ppp.hurst > 0.0 && ppp.hurst < 1.0) hurst = ppp.hurst;
+ if (ppp.maxCells > 0) maxCells = ppp.maxCells;
+}
+
+genLandParams Landscape::getGenLandParams(void)
+{
+ genLandParams ppp;
+ ppp.fractal = fractal; ppp.continuous = continuous;
+ ppp.minPct = minPct; ppp.maxPct = maxPct; ppp.propSuit = propSuit; ppp.hurst = hurst;
+ ppp.maxCells = maxCells;
+ return ppp;
+}
+
+void Landscape::setLandLimits(int x0, int y0, int x1, int y1) {
+ if (x0 >= 0 && x1 >= 0 && x0 <= x1 && x1 < dimX
+ && y0 >= 0 && y1 >= 0 && y0 <= y1 && y1 < dimY) {
+ minX = x0; maxX = x1; minY = y0; maxY = y1;
+ }
+}
+
+void Landscape::resetLandLimits(void) {
+ minX = minY = 0; maxX = dimX - 1; maxY = dimY - 1;
+}
+
+//---------------------------------------------------------------------------
+
+void Landscape::setLandPix(landPix p) {
+ if (p.pix > 0) pix = p.pix;
+ if (p.gpix > 0.0) gpix = p.gpix;
+}
+
+landPix Landscape::getLandPix(void) {
+ landPix p;
+ p.pix = pix; p.gpix = gpix;
+ return p;
+}
+
+void Landscape::setOrigin(landOrigin origin) {
+ minEast = origin.minEast; minNorth = origin.minNorth;
+}
+
+landOrigin Landscape::getOrigin(void) {
+ landOrigin origin;
+ origin.minEast = minEast; origin.minNorth = minNorth;
+ return origin;
+}
+
+//---------------------------------------------------------------------------
+
+// Functions to handle habitat codes
+
+bool Landscape::habitatsIndexed(void) { return habIndexed; }
+
+void Landscape::listHabCodes(void) {
+ int nhab = (int)habCodes.size();
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << endl;
+ for (int i = 0; i < nhab; i++) {
+ Rcpp::Rcout << "Habitat code[ " << i << "] = " << habCodes[i] << endl;
+ }
+ Rcpp::Rcout << endl;
+#else
+ cout << endl;
+ for (int i = 0; i < nhab; i++) {
+ cout << "Habitat code[ " << i << "] = " << habCodes[i] << endl;
+ }
+ cout << endl;
+#endif
+}
+
+void Landscape::addHabCode(int hab) {
+ int nhab = (int)habCodes.size();
+ bool addCode = true;
+ for (int i = 0; i < nhab; i++) {
+ if (hab == habCodes[i]) {
+ addCode = false; i = nhab + 1;
+ }
+ }
+ if (addCode) { habCodes.push_back(hab); nHab++; }
+}
+
+// Get the index number of the specified habitat in the habitats vector
+int Landscape::findHabCode(int hab) {
+ int nhab = (int)habCodes.size();
+ for (int i = 0; i < nhab; i++) {
+ if (hab == habCodes[i]) return i;
+ }
+ return -999;
+}
+
+// Get the specified habitat code
+int Landscape::getHabCode(int ixhab) {
+ if (ixhab < (int)habCodes.size()) return habCodes[ixhab];
+ else return -999;
+}
+
+void Landscape::clearHabitats(void) {
+ habCodes.clear();
+ colours.clear();
+}
+
+void Landscape::addColour(rgb c) {
+ colours.push_back(c);
+}
+
+void Landscape::changeColour(int i, rgb col) {
+ int ncolours = (int)colours.size();
+ if (i >= 0 && i < ncolours) {
+ if (col.r >= 0 && col.r <= 255 && col.g >= 0 && col.g <= 255 && col.b >= 0 && col.b <= 255)
+ colours[i] = col;
+ }
+}
+
+rgb Landscape::getColour(int ix) {
+ return colours[ix];
+}
+
+int Landscape::colourCount(void) {
+ return (int)colours.size();
+}
+
+//---------------------------------------------------------------------------
+void Landscape::setCellArray(void) {
+ if (cells != 0) resetLand();
+ cells = new Cell * *[dimY];
+ for (int y = dimY - 1; y >= 0; y--) {
+ cells[y] = new Cell * [dimX];
+ for (int x = 0; x < dimX; x++) {
+ cells[y][x] = 0;
+ }
+ }
+}
+
+void Landscape::addPatchNum(int p) {
+ int npatches = (int)patchnums.size();
+ bool addpatch = true;
+ for (int i = 0; i < npatches; i++) {
+ if (p == patchnums[i]) {
+ addpatch = false; i = npatches + 1;
+ }
+ }
+ if (addpatch) patchnums.push_back(p);
+}
+
+
+//---------------------------------------------------------------------------
+/* Create an artificial landscape (random or fractal), which can be
+either binary (habitat index 0 is the matrix, 1 is suitable habitat)
+or continuous (0 is the matrix, >0 is suitable habitat) */
+void Landscape::generatePatches(void)
+{
+ int x, y, ncells;
+ double p;
+ Patch* pPatch;
+ Cell* pCell;
+
+ vector ArtLandscape;
+
+ setCellArray();
+
+ int patchnum = 0; // initial patch number for cell-based landscape
+ // create patch 0 - the matrix patch (even if there is no matrix)
+ newPatch(patchnum++);
+
+ // as landscape generator returns cells in a random sequence, first set up all cells
+ // in the landscape in the correct sequence, then update them and create patches for
+ // habitat cells
+ for (int yy = dimY - 1; yy >= 0; yy--) {
+ for (int xx = 0; xx < dimX; xx++) {
+ addNewCellToLand(xx, yy, 0);
+ }
+ }
+
+ if (continuous) rasterType = 2;
+ else rasterType = 0;
+ if (fractal) {
+ p = 1.0 - propSuit;
+ // fractal_landscape() requires Max_prop > 1 (but does not check it!)
+ // as in turn it calls runif(1.0,Max_prop)
+ double maxpct;
+ if (maxPct < 1.0) maxpct = 100.0; else maxpct = maxPct;
+
+ ArtLandscape = fractal_landscape(dimY, dimX, hurst, p, maxpct, minPct);
+
+ vector::iterator iter = ArtLandscape.begin();
+ while (iter != ArtLandscape.end()) {
+ x = iter->y_coord; y = iter->x_coord;
+ pCell = findCell(x, y);
+ if (continuous) {
+ if (iter->value > 0.0) { // habitat
+ pPatch = newPatch(patchnum++);
+ addCellToPatch(pCell, pPatch, iter->value);
+ }
+ else { // matrix
+ addCellToPatch(pCell, patches[0], iter->value);
+ }
+ }
+ else { // discrete
+ if (iter->avail == 0) { // matrix
+ addCellToPatch(pCell, patches[0]);
+ }
+ else { // habitat
+ pPatch = newPatch(patchnum++);
+ addCellToPatch(pCell, pPatch);
+ pCell->changeHabIndex(0, 1);
+ }
+ }
+ iter++;
+ }
+ }
+ else { // random landscape
+ int hab = 0;
+ ncells = (int)((float)(dimX) * (float)(dimY)*propSuit + 0.00001); // no. of cells to initialise
+ int i = 0;
+ do {
+ do {
+ x = pRandom->IRandom(0, dimX - 1); y = pRandom->IRandom(0, dimY - 1);
+ pCell = findCell(x, y);
+ hab = pCell->getHabIndex(0);
+ } while (hab > 0);
+ pPatch = newPatch(patchnum++);
+ pCell = findCell(x, y);
+ addCellToPatch(pCell, pPatch);
+ pCell->changeHabIndex(0, 1);
+ if (continuous) {
+ pCell->setHabitat((float)(minPct + pRandom->Random() * (maxPct - minPct)));
+ }
+ i++;
+ } while (i < ncells);
+ // remaining cells need to be added to the matrix patch
+ p = 0.0;
+ x = 0;
+ for (int yy = dimY - 1; yy >= 0; yy--) {
+ for (int xx = 0; xx < dimX; xx++) {
+ pCell = findCell(xx, yy);
+ if (continuous) {
+ if (pCell->getHabitat(0) <= 0.0)
+ {
+ addCellToPatch(pCell, patches[0], (float)p);
+ }
+ }
+ else { // discrete
+ if (pCell->getHabIndex(0) == 0) {
+ addCellToPatch(pCell, patches[0], x);
+ }
+ }
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+
+// Landscape patch-management functions
+
+//---------------------------------------------------------------------------
+/* Create a patch for each suitable cell of a cell-based landscape (all other
+habitat cells are added to the matrix patch) */
+void Landscape::allocatePatches(Species* pSpecies)
+{
+ float habK;
+ Patch* pPatch;
+ Cell* pCell;
+
+ // delete all existing patches
+ int npatches = (int)patches.size();
+ for (int i = 0; i < npatches; i++) {
+ if (patches[i] != NULL) delete patches[i];
+ }
+ patches.clear();
+ // create the matrix patch
+ patches.push_back(new Patch(0, 0));
+ Patch* matrixPatch = patches[0];
+ int patchnum = 1;
+
+ switch (rasterType) {
+
+ case 0: // habitat codes
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] != 0) { // not no-data cell
+ pCell = cells[y][x];
+ habK = 0.0;
+ int nhab = pCell->nHabitats();
+ for (int i = 0; i < nhab; i++) {
+ habK += pSpecies->getHabK(pCell->getHabIndex(i));
+ }
+ if (habK > 0.0) { // cell is suitable - create a patch for it
+ pPatch = newPatch(patchnum++);
+ addCellToPatch(pCell, pPatch);
+ }
+ else { // cell is not suitable - add to the matrix patch
+ addCellToPatch(pCell, matrixPatch);
+ pPatch = 0;
+ }
+ }
+ }
+ }
+ break;
+ case 1: // habitat cover
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] != 0) { // not no-data cell
+ pCell = cells[y][x];
+ habK = 0.0;
+ int nhab = pCell->nHabitats();
+ for (int i = 0; i < nhab; i++)
+ {
+ habK += pSpecies->getHabK(i) * pCell->getHabitat(i) / 100.0f;
+ }
+ if (habK > 0.0) { // cell is suitable - create a patch for it
+ pPatch = newPatch(patchnum++);
+ addCellToPatch(pCell, pPatch);
+ }
+ else { // cell is not suitable - add to the matrix patch
+ addCellToPatch(pCell, matrixPatch);
+ pPatch = 0;
+ }
+ }
+ }
+ }
+ break;
+ case 2: // habitat quality
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+
+ if (cells[y][x] != 0) { // not no-data cell
+ pCell = cells[y][x];
+ habK = 0.0;
+ int nhab = pCell->nHabitats();
+ // for (int i = 0; i < nHab; i++)
+ for (int i = 0; i < nhab; i++)
+ {
+ habK += pSpecies->getHabK(0) * pCell->getHabitat(i) / 100.0f;
+ }
+ if (habK > 0.0) { // cell is suitable (at some time) - create a patch for it
+ pPatch = newPatch(patchnum++);
+ addCellToPatch(pCell, pPatch);
+ }
+ else { // cell is never suitable - add to the matrix patch
+ addCellToPatch(pCell, matrixPatch);
+ pPatch = 0;
+ }
+ }
+ }
+ }
+ break;
+
+ } // end of switch (rasterType)
+}
+
+Patch* Landscape::newPatch(int num)
+{
+ int npatches = (int)patches.size();
+ patches.push_back(new Patch(num, num));
+ return patches[npatches];
+}
+
+Patch* Landscape::newPatch(int seqnum, int num)
+{
+ int npatches = (int)patches.size();
+ patches.push_back(new Patch(seqnum, num));
+ return patches[npatches];
+}
+
+void Landscape::resetPatches(void) {
+ int npatches = (int)patches.size();
+ for (int i = 0; i < npatches; i++) {
+ patches[i]->resetLimits();
+ }
+}
+
+void Landscape::addNewCellToLand(int x, int y, float q) {
+ if (q < 0.0) // no-data cell - no Cell created
+ cells[y][x] = 0;
+ else
+ cells[y][x] = new Cell(x, y, 0, q);
+}
+
+void Landscape::addNewCellToLand(int x, int y, int hab) {
+ if (hab < 0) // no-data cell - no Cell created
+ cells[y][x] = 0;
+ else
+ cells[y][x] = new Cell(x, y, 0, hab);
+}
+
+void Landscape::addNewCellToPatch(Patch* pPatch, int x, int y, float q) {
+ if (q < 0.0) { // no-data cell - no Cell created
+ cells[y][x] = 0;
+ }
+ else { // create the new cell
+ cells[y][x] = new Cell(x, y, (intptr)pPatch, q);
+ if (pPatch != 0) { // not the matrix patch
+ // add the cell to the patch
+ pPatch->addCell(cells[y][x], x, y);
+ }
+ }
+}
+
+void Landscape::addNewCellToPatch(Patch* pPatch, int x, int y, int hab) {
+ if (hab < 0) // no-data cell - no Cell created
+ cells[y][x] = 0;
+ else { // create the new cell
+ cells[y][x] = new Cell(x, y, (intptr)pPatch, hab);
+ if (pPatch != 0) { // not the matrix patch
+ // add the cell to the patch
+ pPatch->addCell(cells[y][x], x, y);
+ }
+ }
+}
+
+void Landscape::addCellToPatch(Cell* pCell, Patch* pPatch) {
+ pCell->setPatch((intptr)pPatch);
+ locn loc = pCell->getLocn();
+ // add the cell to the patch
+ pPatch->addCell(pCell, loc.x, loc.y);
+}
+
+void Landscape::addCellToPatch(Cell* pCell, Patch* pPatch, float q) {
+ pCell->setPatch((intptr)pPatch);
+ // update the habitat type of the cell
+ pCell->setHabitat(q);
+ locn loc = pCell->getLocn();
+ // add the cell to the patch
+ pPatch->addCell(pCell, loc.x, loc.y);
+}
+
+void Landscape::addCellToPatch(Cell* pCell, Patch* pPatch, int hab) {
+ pCell->setPatch((intptr)pPatch);
+ // update the habitat type of the cell
+ pCell->setHabIndex(hab);
+ locn loc = pCell->getLocn();
+ // add the cell to the patch
+ pPatch->addCell(pCell, loc.x, loc.y);
+}
+
+patchData Landscape::getPatchData(int ix) {
+ patchData ppp;
+ ppp.pPatch = patches[ix]; ppp.patchNum = patches[ix]->getPatchNum();
+ ppp.nCells = patches[ix]->getNCells();
+ locn randloc; randloc.x = -666; randloc.y = -666;
+ Cell* pCell = patches[ix]->getRandomCell();
+ if (pCell != 0) {
+ randloc = pCell->getLocn();
+ }
+ ppp.x = randloc.x; ppp.y = randloc.y;
+ return ppp;
+}
+
+bool Landscape::existsPatch(int num) {
+ int npatches = (int)patches.size();
+ for (int i = 0; i < npatches; i++) {
+ if (num == patches[i]->getPatchNum()) return true;
+ }
+ return false;
+}
+
+Patch* Landscape::findPatch(int num) {
+ int npatches = (int)patches.size();
+ for (int i = 0; i < npatches; i++) {
+ if (num == patches[i]->getPatchNum()) return patches[i];
+ }
+ return 0;
+}
+
+void Landscape::resetPatchPopns(void) {
+ int npatches = (int)patches.size();
+ for (int i = 0; i < npatches; i++) {
+ patches[i]->resetPopn();
+ }
+}
+
+void Landscape::updateCarryingCapacity(Species* pSpecies, int yr, short landIx) {
+ envGradParams grad = paramsGrad->getGradient();
+ bool gradK = false;
+ if (grad.gradient && grad.gradType == 1) gradK = true; // gradient in carrying capacity
+ patchLimits landlimits;
+ landlimits.xMin = minX; landlimits.xMax = maxX;
+ landlimits.yMin = minY; landlimits.yMax = maxY;
+ int npatches = (int)patches.size();
+ for (int i = 0; i < npatches; i++) {
+ if (patches[i]->getPatchNum() != 0) { // not matrix patch
+ patches[i]->setCarryingCapacity(pSpecies, landlimits,
+ getGlobalStoch(yr), nHab, rasterType, landIx, gradK);
+ }
+ }
+
+}
+
+Cell* Landscape::findCell(int x, int y) {
+ if (x >= 0 && x < dimX && y >= 0 && y < dimY) return cells[y][x];
+ else return 0;
+}
+
+int Landscape::patchCount(void) {
+ return (int)patches.size();
+}
+
+void Landscape::listPatches(void) {
+ patchLimits p;
+ int npatches = (int)patches.size();
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << endl;
+ for (int i = 0; i < npatches; i++) {
+ p = patches[i]->getLimits();
+ Rcpp::Rcout << "Patch " << patches[i]->getPatchNum()
+ << " xMin = " << p.xMin << " xMax = " << p.xMax
+ << " \tyMin = " << p.yMin << " yMax = " << p.yMax
+ << endl;
+ }
+ Rcpp::Rcout << endl;
+#else
+ cout << endl;
+ for (int i = 0; i < npatches; i++) {
+ p = patches[i]->getLimits();
+ cout << "Patch " << patches[i]->getPatchNum()
+ << " xMin = " << p.xMin << " xMax = " << p.xMax
+ << " \tyMin = " << p.yMin << " yMax = " << p.yMax
+ << endl;
+ }
+ cout << endl;
+#endif
+}
+
+// Check that total cover of any cell does not exceed 100%
+// and identify matrix cells
+int Landscape::checkTotalCover(void) {
+ if (rasterType != 1) return 0; // not appropriate test
+ int nCells = 0;
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] != 0)
+ { // not a no-data cell
+ float sumCover = 0.0;
+ for (int i = 0; i < nHab; i++) {
+ sumCover += cells[y][x]->getHabitat(i);
+ }
+ if (sumCover > 100.00001) nCells++; // decimal part to allow for floating point error
+ if (sumCover <= 0.0) // cell is a matrix cell
+ cells[y][x]->setHabIndex(0);
+ else
+ cells[y][x]->setHabIndex(1);
+ }
+ }
+ }
+ return nCells;
+}
+
+// Convert habitat codes stored on loading habitat codes landscape to
+// sequential sorted index numbers
+void Landscape::updateHabitatIndices(void) {
+ // sort codes
+ sort(habCodes.begin(), habCodes.end());
+ nHab = (int)habCodes.size();
+ // convert codes in landscape
+ int h;
+ int changes = (int)landchanges.size();
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] != 0) { // not a no-data cell
+ for (int c = 0; c <= changes; c++) {
+ h = cells[y][x]->getHabIndex(c);
+
+ if (h >= 0) {
+ h = findHabCode(h);
+
+ cells[y][x]->changeHabIndex(c, h);
+ }
+ }
+ }
+ }
+ }
+ habIndexed = true;
+}
+
+void Landscape::setEnvGradient(Species* pSpecies, bool initial)
+{
+ float dist_from_opt, dev;
+ float habK;
+ double envval;
+ // gradient parameters
+ envGradParams grad = paramsGrad->getGradient();
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ // NB: gradient lies in range 0-1 for all types, and is applied when necessary...
+ // ... implies gradient increment will be dimensionless in range 0-1 (but << 1)
+ if (cells[y][x] != 0) { // not no-data cell
+ habK = 0.0;
+ int nhab = cells[y][x]->nHabitats();
+ for (int i = 0; i < nhab; i++) {
+ switch (rasterType) {
+ case 0:
+ habK += pSpecies->getHabK(cells[y][x]->getHabIndex(i));
+ break;
+ case 1:
+ habK += pSpecies->getHabK(i) * cells[y][x]->getHabitat(i) / 100.0f;
+ break;
+ case 2:
+ habK += pSpecies->getHabK(0) * cells[y][x]->getHabitat(i) / 100.0f;
+ break;
+ }
+ }
+
+ if (habK > 0.0) { // suitable cell
+ if (initial) { // set local environmental deviation
+ cells[y][x]->setEnvDev((float)pRandom->Random() * (2.0f) - 1.0f);
+ }
+ dist_from_opt = (float)(fabs((double)grad.opt_y - (double)y));
+ dev = cells[y][x]->getEnvDev();
+ envval = 1.0 - dist_from_opt * grad.grad_inc + dev * grad.factor;
+ if (envval < 0.000001) envval = 0.0;
+ if (envval > 1.0) envval = 1.0;
+ }
+ else envval = 0.0;
+ cells[y][x]->setEnvVal((float)envval);
+ }
+ }
+ }
+
+}
+
+void Landscape::setGlobalStoch(int nyears) {
+ envStochParams env = paramsStoch->getStoch();
+ if (epsGlobal != 0) delete[] epsGlobal;
+ epsGlobal = new float[nyears];
+ epsGlobal[0] = (float)(pRandom->Normal(0.0, env.std) * sqrt(1.0 - (env.ac * env.ac)));
+ for (int i = 1; i < nyears; i++) {
+ epsGlobal[i] = (float)(env.ac * epsGlobal[i - 1] + pRandom->Normal(0.0, env.std) * sqrt(1.0 - (env.ac * env.ac)));
+ }
+}
+
+float Landscape::getGlobalStoch(int yr) {
+ if (epsGlobal != 0 && yr >= 0) {
+ return epsGlobal[yr];
+ }
+ else return 0.0;
+}
+
+void Landscape::updateLocalStoch(void) {
+ envStochParams env = paramsStoch->getStoch();
+ float randpart;
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] != 0) { // not a no-data cell
+ randpart = (float)(pRandom->Normal(0.0, env.std) * sqrt(1.0 - (env.ac * env.ac)));
+ cells[y][x]->updateEps((float)env.ac, randpart);
+ }
+ }
+ }
+
+}
+
+void Landscape::resetCosts(void) {
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] != 0) { // not a no-data cell
+ cells[y][x]->resetCost();
+ }
+ }
+ }
+}
+
+void Landscape::resetEffCosts(void) {
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] != 0) { // not a no-data cell
+ cells[y][x]->resetEffCosts();
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+
+// Dynamic landscape functions
+
+void Landscape::setDynamicLand(bool dyn) { dynamic = dyn; }
+
+void Landscape::addLandChange(landChange c) {
+ landchanges.push_back(c);
+}
+
+int Landscape::numLandChanges(void) { return (int)landchanges.size(); }
+
+landChange Landscape::getLandChange(short ix) {
+ landChange c; c.chgnum = c.chgyear = 0;
+ c.habfile = c.pchfile = c.costfile = "none";
+ int nchanges = (int)landchanges.size();
+ if (ix < nchanges) c = landchanges[ix];
+ return c;
+}
+
+void Landscape::deleteLandChanges(void) {
+ while (landchanges.size() > 0) landchanges.pop_back();
+ landchanges.clear();
+}
+
+#if RS_RCPP && !R_CMD
+int Landscape::readLandChange(int filenum, bool costs, wifstream& hfile, wifstream& pfile, wifstream& cfile, int habnodata, int pchnodata, int costnodata)
+#else
+int Landscape::readLandChange(int filenum, bool costs)
+#endif
+{
+
+#if RSDEBUG
+ DEBUGLOG << "Landscape::readLandChange(): filenum=" << filenum << " costs=" << int(costs)
+ << endl;
+#endif
+
+#if RS_RCPP
+ wstring header;
+#else
+ string header;
+ int ncols, nrows, habnodata, costnodata, pchnodata;
+ costnodata = 0;
+ pchnodata = 0;
+#endif
+ int h = 0, p = 0, c = 0, pchseq = 0;
+ float hfloat, pfloat, cfloat;
+ simParams sim = paramsSim->getSim();
+
+ if (filenum < 0) return 19;
+ if (patchModel) pchseq = patchCount();
+
+#if !RS_RCPP
+ ifstream hfile; // habitat file input stream
+ ifstream pfile; // patch file input stream
+ ifstream cfile; // costs file input stream
+#endif
+
+#if !RS_RCPP || R_CMD
+ // open habitat file and optionally also patch and costs files
+ hfile.open(landchanges[filenum].habfile.c_str());
+ if (!hfile.is_open()) return 30;
+ if (patchModel) {
+ pfile.open(landchanges[filenum].pchfile.c_str());
+ if (!pfile.is_open()) {
+ hfile.close(); hfile.clear();
+ return 31;
+ }
+ }
+ if (costs) {
+ cfile.open(landchanges[filenum].costfile.c_str());
+ if (!cfile.is_open()) {
+ hfile.close(); hfile.clear();
+ if (pfile.is_open()) {
+ pfile.close(); pfile.clear();
+ }
+ return 32;
+ }
+ }
+
+ // read header records of habitat (and patch) file(s)
+ // NB headers of all files have already been compared
+ hfile >> header >> ncols >> header >> nrows >> header >> hfloat >> header >> hfloat
+ >> header >> hfloat >> header >> habnodata;
+ if (patchModel) {
+ for (int i = 0; i < 5; i++) pfile >> header >> pfloat;
+ pfile >> header >> pchnodata;
+ }
+ if (costs) {
+ for (int i = 0; i < 5; i++) cfile >> header >> cfloat;
+ cfile >> header >> costnodata;
+ }
+#endif
+
+ // set up bad float values to ensure that valid values are read
+ float badhfloat = -9.0; if (habnodata == -9) badhfloat = -99.0;
+ float badpfloat = -9.0; if (pchnodata == -9) badpfloat = -99.0;
+ float badcfloat = -9.0; if (costnodata == -9) badcfloat = -99.0;
+
+ switch (rasterType) {
+
+ case 0: // raster with habitat codes - 100% habitat each cell
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ hfloat = badhfloat;
+#if RS_RCPP
+ if (hfile >> hfloat) {
+#else
+ hfile >> hfloat;
+#endif
+ h = (int)hfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR("habitatchgfile");
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 171;
+ }
+#endif
+ if (patchModel) {
+ pfloat = badpfloat;
+#if RS_RCPP
+ if (pfile >> pfloat) {
+#else
+ pfile >> pfloat;
+#endif
+ p = (int)pfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR("patchchgfile");
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 172;
+ }
+#endif
+ }
+ if (costs) {
+ cfloat = badcfloat;
+#if RS_RCPP
+ if (cfile >> cfloat) {
+#else
+ cfile >> cfloat;
+#endif
+ c = (int)cfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR("costchgfile");
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 173;
+ }
+#endif
+ }
+ if (cells[y][x] != 0) { // not a no data cell (in initial landscape)
+ if (h == habnodata) { // invalid no data cell in change map
+ hfile.close(); hfile.clear();
+ return 36;
+ }
+ else {
+ if (h < 0 || (sim.batchMode && (h < 1 || h > nHabMax))) {
+ // invalid habitat code
+ hfile.close(); hfile.clear();
+ if (patchModel) { pfile.close(); pfile.clear(); }
+ return 33;
+ }
+ else {
+ addHabCode(h);
+ cells[y][x]->setHabIndex(h);
+ }
+ }
+ if (patchModel) {
+ if (p < 0 || p == pchnodata) { // invalid patch code
+#if RS_RCPP && !R_CMD
+ if (p == pchnodata) Rcpp::Rcout << "Found patch NA in valid habitat cell." << std::endl;
+ else Rcpp::Rcout << "Found negative patch ID in valid habitat cell." << std::endl;
+#endif
+ hfile.close(); hfile.clear();
+ pfile.close(); pfile.clear();
+ return 34;
+ }
+ else {
+ patchChgMatrix[y][x][2] = p;
+ if (p > 0 && !existsPatch(p)) {
+ addPatchNum(p);
+ newPatch(pchseq++, p);
+ }
+ }
+ }
+ if (costs) {
+ if (c < 1) { // invalid cost
+ hfile.close(); hfile.clear();
+ if (pfile.is_open()) {
+ pfile.close(); pfile.clear();
+ }
+ return 38;
+ }
+ else {
+ costsChgMatrix[y][x][2] = c;
+ }
+ }
+ }
+ }
+ }
+#if RS_RCPP
+ hfile >> hfloat;
+ if (!hfile.eof()) EOFerrorR("habitatchgfile");
+ if (patchModel)
+ {
+ pfile >> pfloat;
+ if (!pfile.eof()) EOFerrorR("patchchgfile");
+ }
+ if (costs)
+ {
+ cfile >> cfloat;
+ if (!cfile.eof()) EOFerrorR("costchgfile");
+ }
+#endif
+ break;
+
+ case 2: // habitat quality
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ hfloat = badhfloat;
+#if RS_RCPP
+ if (hfile >> hfloat) {
+#else
+ hfile >> hfloat;
+#endif
+ h = (int)hfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR("habitatchgfile");
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 172;
+ }
+#endif
+ if (patchModel) {
+ pfloat = badpfloat;
+#if RS_RCPP
+ if (pfile >> pfloat) {
+#else
+ pfile >> pfloat;
+#endif
+ p = (int)pfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR("patchchgfile");
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 175;
+ }
+#endif
+ }
+ if (costs) {
+ cfloat = badcfloat;
+#if RS_RCPP
+ if (cfile >> cfloat) {
+#else
+ cfile >> cfloat;
+#endif
+ c = (int)cfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR("costchgfile");
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 173;
+ }
+#endif
+ }
+ if (cells[y][x] != 0) { // not a no data cell (in initial landscape)
+ if (h == habnodata) { // invalid no data cell in change map
+ hfile.close(); hfile.clear();
+ if (patchModel) { pfile.close(); pfile.clear(); }
+ return 36;
+ }
+ else {
+ if (hfloat < 0.0 || hfloat > 100.0) { // invalid quality score
+ hfile.close(); hfile.clear();
+ if (patchModel) { pfile.close(); pfile.clear(); }
+ return 37;
+ }
+ else {
+ cells[y][x]->setHabitat(hfloat);
+ }
+ }
+ if (patchModel) {
+ if (p < 0 || p == pchnodata) { // invalid patch code
+#if RS_RCPP && !R_CMD
+ if (p == pchnodata) Rcpp::Rcout << "Found patch NA in valid habitat cell." << std::endl;
+ else Rcpp::Rcout << "Found negative patch ID in valid habitat cell." << std::endl;
+#endif
+ hfile.close(); hfile.clear();
+ pfile.close(); pfile.clear();
+ return 34;
+ }
+ else {
+ patchChgMatrix[y][x][2] = p;
+ if (p > 0 && !existsPatch(p)) {
+ addPatchNum(p);
+ newPatch(pchseq++, p);
+ }
+ }
+ }
+ if (costs) {
+ if (c < 1) { // invalid cost
+ hfile.close(); hfile.clear();
+ if (pfile.is_open()) {
+ pfile.close(); pfile.clear();
+ }
+ return 38;
+ }
+ else {
+ costsChgMatrix[y][x][2] = c;
+ }
+ }
+ }
+ }
+ }
+#if RS_RCPP
+ hfile >> hfloat;
+ if (!hfile.eof()) EOFerrorR("habitatchgfile");
+ if (patchModel)
+ {
+ pfile >> pfloat;
+ if (!pfile.eof()) EOFerrorR("patchchgfile");
+ }
+ if (costs)
+ {
+ cfile >> cfloat;
+ if (!cfile.eof()) EOFerrorR("costchgfile");
+ }
+#endif
+ break;
+
+default:
+ break;
+ }
+
+ if (hfile.is_open()) { hfile.close(); hfile.clear(); }
+ if (pfile.is_open()) { pfile.close(); pfile.clear(); }
+ if (cfile.is_open()) { cfile.close(); cfile.clear(); }
+ return 0;
+
+}
+
+// Create & initialise patch change matrix
+void Landscape::createPatchChgMatrix(void)
+{
+ intptr patch;
+ Patch* pPatch;
+ Cell* pCell;
+ if (patchChgMatrix != 0) deletePatchChgMatrix();
+ patchChgMatrix = new int** [dimY];
+ for (int y = dimY - 1; y >= 0; y--) {
+ patchChgMatrix[y] = new int* [dimX];
+ for (int x = 0; x < dimX; x++) {
+ patchChgMatrix[y][x] = new int[3];
+ pCell = findCell(x, y);
+ if (pCell == 0) { // no-data cell
+ patchChgMatrix[y][x][0] = patchChgMatrix[y][x][1] = 0;
+ }
+ else {
+ // record initial patch number
+ patch = pCell->getPatch();
+ if (patch == 0) { // matrix cell
+ patchChgMatrix[y][x][0] = patchChgMatrix[y][x][1] = 0;
+ }
+ else {
+ pPatch = (Patch*)patch;
+ patchChgMatrix[y][x][0] = patchChgMatrix[y][x][1] = pPatch->getPatchNum();
+ }
+ }
+ patchChgMatrix[y][x][2] = 0;
+ }
+ }
+}
+
+void Landscape::recordPatchChanges(int landIx) {
+ if (patchChgMatrix == 0) return; // should not occur
+ patchChange chg;
+
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (landIx == 0) { // reset to original landscape
+ if (patchChgMatrix[y][x][0] != patchChgMatrix[y][x][2]) {
+ // record change of patch for current cell
+ chg.chgnum = 666666; chg.x = x; chg.y = y;
+ chg.oldpatch = patchChgMatrix[y][x][2];
+ chg.newpatch = patchChgMatrix[y][x][0];
+ patchchanges.push_back(chg);
+ }
+ }
+ else { // any other change
+ if (patchChgMatrix[y][x][2] != patchChgMatrix[y][x][1]) {
+ // record change of patch for current cell
+ chg.chgnum = landIx; chg.x = x; chg.y = y;
+ chg.oldpatch = patchChgMatrix[y][x][1];
+ chg.newpatch = patchChgMatrix[y][x][2];
+ patchchanges.push_back(chg);
+ }
+ }
+ // reset cell for next landscape change
+ patchChgMatrix[y][x][1] = patchChgMatrix[y][x][2];
+ }
+ }
+
+}
+
+int Landscape::numPatchChanges(void) { return (int)patchchanges.size(); }
+
+patchChange Landscape::getPatchChange(int i) {
+ patchChange c; c.chgnum = 99999999; c.x = c.y = c.oldpatch = c.newpatch = -1;
+ if (i >= 0 && i < (int)patchchanges.size()) c = patchchanges[i];
+ return c;
+}
+
+void Landscape::deletePatchChgMatrix(void) {
+ if (patchChgMatrix != 0) {
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ delete[] patchChgMatrix[y][x];
+ }
+ delete[] patchChgMatrix[y];
+ }
+ }
+ patchChgMatrix = 0;
+}
+
+// Create & initialise costs change matrix
+void Landscape::createCostsChgMatrix(void)
+{
+ Cell* pCell;
+ if (costsChgMatrix != 0) deleteCostsChgMatrix();
+ costsChgMatrix = new int** [dimY];
+ for (int y = dimY - 1; y >= 0; y--) {
+ costsChgMatrix[y] = new int* [dimX];
+ for (int x = 0; x < dimX; x++) {
+ costsChgMatrix[y][x] = new int[3];
+ pCell = findCell(x, y);
+ if (pCell == 0) { // no-data cell
+ costsChgMatrix[y][x][0] = costsChgMatrix[y][x][1] = 0;
+ }
+ else {
+ // record initial cost
+ costsChgMatrix[y][x][0] = costsChgMatrix[y][x][1] = pCell->getCost();
+ }
+ costsChgMatrix[y][x][2] = 0;
+ }
+ }
+}
+
+void Landscape::recordCostChanges(int landIx) {
+#if RSDEBUG
+ DEBUGLOG << "Landscape::recordCostChanges(): landIx=" << landIx << endl;
+#endif
+ if (costsChgMatrix == 0) return; // should not occur
+ costChange chg;
+
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (landIx == 0) { // reset to original landscape
+ if (costsChgMatrix[y][x][0] != costsChgMatrix[y][x][2]) {
+ // record change of cost for current cell
+ chg.chgnum = 666666; chg.x = x; chg.y = y;
+ chg.oldcost = costsChgMatrix[y][x][2];
+ chg.newcost = costsChgMatrix[y][x][0];
+ costschanges.push_back(chg);
+ }
+ }
+ else { // any other change
+ if (costsChgMatrix[y][x][2] != costsChgMatrix[y][x][1]) {
+ // record change of cost for current cell
+ chg.chgnum = landIx; chg.x = x; chg.y = y;
+ chg.oldcost = costsChgMatrix[y][x][1];
+ chg.newcost = costsChgMatrix[y][x][2];
+ costschanges.push_back(chg);
+ }
+ }
+ // reset cell for next landscape change
+ costsChgMatrix[y][x][1] = costsChgMatrix[y][x][2];
+ }
+ }
+
+}
+
+int Landscape::numCostChanges(void) { return (int)costschanges.size(); }
+
+costChange Landscape::getCostChange(int i) {
+ costChange c; c.chgnum = 99999999; c.x = c.y = c.oldcost = c.newcost = -1;
+ if (i >= 0 && i < (int)costschanges.size()) c = costschanges[i];
+ return c;
+}
+
+void Landscape::deleteCostsChgMatrix(void) {
+ if (costsChgMatrix != 0) {
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ delete[] costsChgMatrix[y][x];
+ }
+ delete[] costsChgMatrix[y];
+ }
+ }
+ costsChgMatrix = 0;
+}
+
+//---------------------------------------------------------------------------
+
+// Species distribution functions
+
+int Landscape::newDistribution(Species* pSpecies, string distname) {
+ int readcode;
+ int ndistns = (int)distns.size();
+ distns.push_back(new InitDist(pSpecies));
+ readcode = distns[ndistns]->readDistribution(distname);
+ if (readcode != 0) { // error encountered
+ // delete the distribution created above
+ delete distns[ndistns];
+ distns.pop_back();
+ }
+ return readcode;
+}
+
+void Landscape::setDistribution(Species* pSpecies, int nInit) {
+ // WILL NEED TO SELECT DISTRIBUTION FOR CORRECT SPECIES ...
+ // ... CURRENTLY IT IS THE ONLY ONE
+ distns[0]->setDistribution(nInit);
+}
+
+// Specified cell match one of the distribution cells to be initialised?
+bool Landscape::inInitialDist(Species* pSpecies, locn loc) {
+ // convert landscape co-ordinates to distribution co-ordinates
+ locn initloc;
+ initloc.x = loc.x * resol / spResol;
+ initloc.y = loc.y * resol / spResol;
+ // WILL HAVE TO GET CORRECT SPECIES WHEN THERE ARE MULTIPLE SPECIES ...
+ bool initialise = distns[0]->inInitialDist(initloc);
+ return initialise;
+}
+
+void Landscape::deleteDistribution(Species* pSpecies) {
+ // WILL NEED TO SELECT DISTRIBUTION FOR CORRECT SPECIES ...
+ // ... CURRENTLY IT IS THE ONLY ONE ...
+ // ... FOR MULTIPLE SPECIES IT MAY BE BETTER TO USE A DYNAMIC ARRAY FOR
+ // SPECIES DISTRIBUTIONS INDEXED BY SPECIES NUMBER, RATHER THAN A VECTOR
+ if (distns[0] != 0) delete distns[0]; distns.clear();
+}
+
+// Return no. of initial distributions
+int Landscape::distnCount(void) {
+ return (int)distns.size();
+}
+
+int Landscape::distCellCount(int dist) {
+ return distns[dist]->cellCount();
+}
+
+// Set a cell in a specified initial distribution (by position in cells vector)
+void Landscape::setDistnCell(int dist, int ix, bool init) {
+ distns[dist]->setDistCell(ix, init);
+}
+
+// Set a cell in a specified initial distribution (by given co-ordinates)
+void Landscape::setDistnCell(int dist, locn loc, bool init) {
+ distns[dist]->setDistCell(loc, init);
+}
+
+// Get the co-ordinates of a specified cell in a specified initial distribution
+locn Landscape::getDistnCell(int dist, int ix) {
+ return distns[dist]->getCell(ix);
+}
+
+// Get the co-ordinates of a specified cell in a specified initial distribution
+// Returns negative co-ordinates if the cell is not selected
+locn Landscape::getSelectedDistnCell(int dist, int ix) {
+ return distns[dist]->getSelectedCell(ix);
+}
+
+// Get the dimensions of a specified initial distribution
+locn Landscape::getDistnDimensions(int dist) {
+ return distns[dist]->getDimensions();
+}
+
+// Reset the distribution for a given species so that all cells are deselected
+void Landscape::resetDistribution(Species* pSp) {
+ // CURRENTLY WORKS FOR FIRST SPECIES ONLY ...
+ distns[0]->resetDistribution();
+}
+
+//---------------------------------------------------------------------------
+
+// Initialisation cell functions
+
+int Landscape::initCellCount(void) {
+ return (int)initcells.size();
+}
+
+void Landscape::addInitCell(int x, int y) {
+ initcells.push_back(new DistCell(x, y));
+}
+
+locn Landscape::getInitCell(int ix) {
+ return initcells[ix]->getLocn();
+}
+
+void Landscape::clearInitCells(void) {
+ int ncells = (int)initcells.size();
+ for (int i = 0; i < ncells; i++) {
+ delete initcells[i];
+ }
+ initcells.clear();
+}
+
+//---------------------------------------------------------------------------
+
+// Read landscape file(s)
+// Returns error code or zero if read correctly
+
+int Landscape::readLandscape(int fileNum, string habfile, string pchfile, string costfile)
+{
+ // fileNum == 0 for (first) habitat file and optional patch file
+ // fileNum > 0 for subsequent habitat files under the %cover option
+
+#if RS_RCPP
+ wstring header;
+#else
+ string header;
+#endif
+ int h, seq, p, habnodata;
+ int pchnodata = 0;
+ int ncols, nrows;
+ float hfloat, pfloat;
+ Patch* pPatch;
+ simParams sim = paramsSim->getSim();
+
+ if (fileNum < 0) return 19;
+
+#if RS_RCPP
+ wifstream hfile; // habitat file input stream
+ wifstream pfile; // patch file input stream
+#else
+ ifstream hfile; // habitat file input stream
+ ifstream pfile; // patch file input stream
+#endif
+ initParams init = paramsInit->getInit();
+
+ // open habitat file and optionally also patch file
+#if !RS_RCPP || RSWIN64
+ hfile.open(habfile.c_str());
+#else
+ hfile.open(habfile, std::ios::binary);
+ if (landraster.utf) {
+ // apply BOM-sensitive UTF-16 facet
+ hfile.imbue(std::locale(hfile.getloc(), new std::codecvt_utf16));
+ }
+#endif
+ if (!hfile.is_open()) return 11;
+ if (fileNum == 0) {
+ if (patchModel) {
+#if !RS_RCPP || RSWIN64
+ pfile.open(pchfile.c_str());
+#else
+ pfile.open(pchfile, std::ios::binary);
+ if (patchraster.utf) {
+ // apply BOM-sensitive UTF-16 facet
+ pfile.imbue(std::locale(pfile.getloc(), new std::codecvt_utf16));
+ }
+#endif
+ if (!pfile.is_open()) {
+ hfile.close(); hfile.clear();
+ return 12;
+ }
+ }
+ }
+
+ // read landscape data from header records of habitat file
+ // NB headers of all files have already been compared
+ hfile >> header >> ncols >> header >> nrows >> header >> minEast >> header >> minNorth
+ >> header >> resol >> header >> habnodata;
+
+#if RS_RCPP
+ if (!hfile.good()) {
+ // corrupt file stream
+ StreamErrorR(habfile);
+ hfile.close();
+ hfile.clear();
+ if (patchModel) {
+ pfile.close();
+ pfile.clear();
+ }
+ return 131;
+ }
+#endif
+
+ dimX = ncols; dimY = nrows; minX = maxY = 0; maxX = dimX - 1; maxY = dimY - 1;
+ if (fileNum == 0) {
+ // set initialisation limits to landscape limits
+ init.minSeedX = init.minSeedY = 0;
+ init.maxSeedX = maxX; init.maxSeedY = maxY;
+ paramsInit->setInit(init);
+ }
+
+ if (fileNum == 0) {
+ if (patchModel) {
+ for (int i = 0; i < 5; i++) pfile >> header >> pfloat;
+ pfile >> header >> pchnodata;
+ }
+#if RS_RCPP
+ if (!pfile.good()) {
+ // corrupt file stream
+ StreamErrorR(pchfile);
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 135;
+ }
+#endif
+ setCellArray();
+ }
+
+
+ // set up bad float values to ensure that valid values are read
+ float badhfloat = -9.0; if (habnodata == -9) badhfloat = -99.0;
+ float badpfloat = -9.0; if (pchnodata == -9) badpfloat = -99.0;
+
+ seq = 0; // initial sequential patch landscape
+ p = 0; // initial patch number for cell-based landscape
+ // create patch 0 - the matrix patch (even if there is no matrix)
+ if (fileNum == 0) newPatch(seq++, p++);
+
+ switch (rasterType) {
+
+ case 0: // raster with habitat codes - 100% habitat each cell
+ if (fileNum > 0) return 19; // error condition - should not occur
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ hfloat = badhfloat;
+#if RS_RCPP
+ if (hfile >> hfloat) {
+#else
+ hfile >> hfloat;
+#endif
+ h = (int)hfloat;
+ if (patchModel) {
+ pfloat = badpfloat;
+#if RS_RCPP
+ if (pfile >> pfloat) {
+#else
+ pfile >> pfloat;
+#endif
+ p = (int)pfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR(pchfile);
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 132;
+ }
+#endif
+ }
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR(habfile);
+ hfile.close();
+ hfile.clear();
+ if (patchModel) {
+ pfile.close();
+ pfile.clear();
+ }
+ return 135;
+ }
+#endif
+ if (h == habnodata)
+ addNewCellToLand(x, y, -1); // add cell only to landscape
+ else {
+
+ // THERE IS AN ANOMALY HERE - CURRENTLY HABITAT 0 IS OK FOR GUI VERSION BUT
+ // NOT ALLOWED FOR BATCH VERSION (HABITATS MUST BE 1...n)
+ // SHOULD WE MAKE THE TWO VERSIONS AGREE? ...
+
+ if (h < 0 || (sim.batchMode && (h < 1 || h > nHabMax))) {
+ // invalid habitat code
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "Found invalid habitat code." << std::endl;
+#endif
+ hfile.close(); hfile.clear();
+ if (patchModel) {
+ pfile.close(); pfile.clear();
+ }
+ return 13;
+ }
+ else {
+ addHabCode(h);
+ if (patchModel) {
+ if (p < 0 || p == pchnodata) { // invalid patch code
+#if RS_RCPP && !R_CMD
+ if (p == pchnodata) Rcpp::Rcout << "Found patch NA in valid habitat cell." << std::endl;
+ else Rcpp::Rcout << "Found negative patch ID in valid habitat cell." << std::endl;
+#endif
+ hfile.close(); hfile.clear();
+ pfile.close(); pfile.clear();
+ return 14;
+ }
+ if (p == 0) { // cell is in the matrix
+ addNewCellToPatch(0, x, y, h);
+ }
+ else {
+ if (existsPatch(p)) {
+ pPatch = findPatch(p);
+ addNewCellToPatch(pPatch, x, y, h);
+ // addNewCellToPatch(findPatch(p),x,y,h);
+ }
+ else {
+ pPatch = newPatch(seq++, p);
+ addNewCellToPatch(pPatch, x, y, h);
+ }
+ }
+ }
+ else { // cell-based model
+ // add cell to landscape (patches created later)
+ addNewCellToLand(x, y, h);
+ }
+ }
+ }
+ }
+ }
+#if RS_RCPP
+hfile >> hfloat;
+if (!hfile.eof()) EOFerrorR(habfile);
+if (patchModel)
+{
+ pfile >> pfloat;
+ if (!pfile.eof()) EOFerrorR(pchfile);
+}
+#endif
+break;
+
+case 1: // multiple % cover
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ hfloat = badhfloat;
+#if RS_RCPP
+ if (hfile >> hfloat) {
+#else
+ hfile >> hfloat;
+#endif
+ h = (int)hfloat;
+ if (fileNum == 0) { // first habitat cover layer
+ if (patchModel) {
+ pfloat = badpfloat;
+#if RS_RCPP
+ if (pfile >> pfloat) {
+#else
+ pfile >> pfloat;
+#endif
+ p = (int)pfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR(pchfile);
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 135;
+ }
+#endif
+ } //end if patchmodel
+ if (h == habnodata) {
+ addNewCellToLand(x, y, -1); // add cell only to landscape
+ }
+ else {
+ if (hfloat < 0.0 || hfloat > 100.0) { // invalid cover score
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "Found invalid habitat cover score." << std::endl;
+#endif
+ hfile.close(); hfile.clear();
+ if (patchModel) {
+ pfile.close(); pfile.clear();
+ }
+ return 17;
+ }
+ else {
+ if (patchModel) {
+ if (p < 0 || p == pchnodata) { // invalid patch code
+#if RS_RCPP && !R_CMD
+ if (p == pchnodata) Rcpp::Rcout << "Found patch NA in valid habitat cell." << std::endl;
+ else Rcpp::Rcout << "Found negative patch ID in valid habitat cell." << std::endl;
+#endif
+ hfile.close(); hfile.clear();
+ pfile.close(); pfile.clear();
+ return 14;
+ }
+ if (p == 0) { // cell is in the matrix
+ addNewCellToPatch(0, x, y, hfloat);
+ }
+ else {
+ if (existsPatch(p)) {
+ pPatch = findPatch(p);
+ addNewCellToPatch(pPatch, x, y, hfloat);
+ // addNewCellToPatch(findPatch(p),x,y,hfloat);
+ }
+ else {
+ pPatch = newPatch(seq++, p);
+ addNewCellToPatch(pPatch, x, y, hfloat);
+ }
+ }
+ }
+ else { // cell-based model
+ // add cell to landscape (patches created later)
+ addNewCellToLand(x, y, hfloat);
+ }
+ }
+ }
+ }
+else { // additional habitat cover layers
+ if (h != habnodata) {
+ if (hfloat < 0.0 || hfloat > 100.0) { // invalid cover score
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "Found invalid habitat cover score." << std::endl;
+#endif
+ hfile.close(); hfile.clear();
+ if (patchModel) {
+ pfile.close(); pfile.clear();
+ }
+ return 17;
+ }
+ else {
+ cells[y][x]->setHabitat(hfloat);
+ }
+ } // end of h != habnodata
+}
+#if RS_RCPP
+ }
+else { // couldn't read from hfile
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR(habfile);
+ hfile.close();
+ hfile.clear();
+ if (patchModel) {
+ pfile.close();
+ pfile.clear();
+ }
+ return 133;
+}
+#endif
+
+ }
+ }
+ habIndexed = true; // habitats are already numbered 1...n in correct order
+#if RS_RCPP
+ hfile >> hfloat;
+ if (!hfile.eof()) EOFerrorR(habfile);
+ if (patchModel)
+ {
+ pfile >> pfloat;
+ if (!pfile.eof()) EOFerrorR(pchfile);
+ }
+#endif
+ break;
+
+case 2: // habitat quality
+ if (fileNum > 0) return 19; // error condition - should not occur
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ hfloat = badhfloat;
+#if RS_RCPP
+ if (hfile >> hfloat) {
+#else
+ hfile >> hfloat;
+#endif
+ h = (int)hfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR(habfile);
+ hfile.close();
+ hfile.clear();
+ if (patchModel) {
+ pfile.close();
+ pfile.clear();
+ }
+ return 134;
+ }
+#endif
+ if (patchModel) {
+ pfloat = badpfloat;
+#if RS_RCPP
+ if (pfile >> pfloat) {
+#else
+ pfile >> pfloat;
+#endif
+ p = (int)pfloat;
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR(pchfile);
+ hfile.close();
+ hfile.clear();
+ pfile.close();
+ pfile.clear();
+ return 135;
+ }
+#endif
+ }
+ if (h == habnodata) {
+ addNewCellToLand(x, y, -1); // add cell only to landscape
+ }
+ else {
+ if (hfloat < 0.0 || hfloat > 100.0) { // invalid quality score
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "Found invalid habitat quality score." << std::endl;
+#endif
+ hfile.close(); hfile.clear();
+ if (patchModel) {
+ pfile.close(); pfile.clear();
+ }
+ return 17;
+ }
+ else {
+ if (patchModel) {
+ if (p < 0 || p == pchnodata) { // invalid patch code
+#if RS_RCPP && !R_CMD
+ if (p == pchnodata) Rcpp::Rcout << "Found patch NA in valid habitat cell." << std::endl;
+ else Rcpp::Rcout << "Found negative patch ID in valid habitat cell." << std::endl;
+#endif
+ hfile.close(); hfile.clear();
+ pfile.close(); pfile.clear();
+ return 14;
+ }
+ if (p == 0) { // cell is in the matrix
+ addNewCellToPatch(0, x, y, hfloat);
+ }
+ else {
+ if (existsPatch(p)) {
+ pPatch = findPatch(p);
+ addNewCellToPatch(pPatch, x, y, hfloat);
+ // addNewCellToPatch(findPatch(p),x,y,hfloat);
+ }
+ else {
+ addPatchNum(p);
+ pPatch = newPatch(seq++, p);
+ addNewCellToPatch(pPatch, x, y, hfloat);
+ }
+ }
+ }
+ else { // cell-based model
+ // add cell to landscape (patches created later)
+ addNewCellToLand(x, y, hfloat);
+ }
+ }
+ }
+ }
+ }
+#if RS_RCPP
+ hfile >> hfloat;
+ if (!hfile.eof()) EOFerrorR(habfile);
+ if (patchModel)
+ {
+ pfile >> pfloat;
+ if (!pfile.eof()) EOFerrorR(pchfile);
+ }
+#endif
+ break;
+
+default:
+ break;
+ } // end switch(rasterType)
+
+ if (hfile.is_open()) { hfile.close(); hfile.clear(); }
+ if (pfile.is_open()) { pfile.close(); pfile.clear(); }
+
+ if (sim.batchMode) {
+ if (costfile != "NULL") {
+ int retcode = readCosts(costfile);
+ if (retcode < 0) return 54;
+ }
+ }
+
+ return 0;
+
+}
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+
+int Landscape::readCosts(string fname)
+{
+
+#if RS_RCPP
+ wifstream costs; // cost map file input stream
+#else
+ ifstream costs; // cost map file input stream
+#endif
+
+ //int hc,maxYcost,maxXcost,NODATACost,hab;
+ int hc, maxYcost, maxXcost, NODATACost;
+ float minLongCost, minLatCost; int resolCost;
+ float fcost;
+#if RS_RCPP
+ wstring header;
+#else
+ string header;
+#endif
+ Cell* pCell;
+#if !RS_RCPP
+ simView v = paramsSim->getViews();
+#endif
+
+ int maxcost = 0;
+
+ // open cost file
+#if !RS_RCPP || RSWIN64
+ costs.open(fname.c_str());
+#else
+ costs.open(fname, std::ios::binary);
+ if (costsraster.utf) {
+ // apply BOM-sensitive UTF-16 facet
+ costs.imbue(std::locale(costs.getloc(), new std::codecvt_utf16));
+ }
+#endif
+ // read headers and check that they correspond to the landscape ones
+ costs >> header;
+#if RS_RCPP
+ if (!costs.good()) {
+ // corrupt file stream
+ StreamErrorR(fname);
+ costs.close();
+ costs.clear();
+ return -181;
+ }
+ if (header != L"ncols" && header != L"NCOLS") {
+#else
+ if (header != "ncols" && header != "NCOLS") {
+#endif
+
+// MessageDlg("The selected file is not a raster.",
+// MessageDlg("Header problem in import_CostsLand()",
+// mtError, TMsgDlgButtons() << mbRetry,0);
+ costs.close(); costs.clear();
+ return -1;
+}
+double tmpresolCost;
+costs >> maxXcost >> header >> maxYcost >> header >> minLongCost;
+costs >> header >> minLatCost >> header >> tmpresolCost >> header >> NODATACost;
+resolCost = (int) tmpresolCost;
+
+
+#if !RS_RCPP
+ MemoLine("Loading costs map. Please wait...");
+#endif
+
+ for (int y = maxYcost - 1; y > -1; y--) {
+ for (int x = 0; x < maxXcost; x++) {
+#if RS_RCPP
+ if (costs >> fcost) {
+#else
+ costs >> fcost;
+#endif
+ hc = (int)fcost; // read as float and convert to int
+#if RS_RCPP
+ }
+ else {
+ // corrupt file stream
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "At (x,y) = " << x << "," << y << " :" << std::endl;
+#endif
+ StreamErrorR(fname);
+ costs.close();
+ costs.clear();
+ return -181;
+ }
+#endif
+ if (hc < 1 && hc != NODATACost) {
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "Cost map my only contain values of 1 or higher, but found " << fcost << "." << endl;
+#endif
+ // error - zero / negative cost not allowed
+ costs.close(); costs.clear();
+ return -999;
+ }
+ pCell = findCell(x, y);
+ if (pCell != 0) { // not no-data cell
+ pCell->setCost(hc);
+ if (hc > maxcost) maxcost = hc;
+ }
+ }
+ }
+#if RS_RCPP
+costs >> fcost;
+if (costs.eof()) {
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "Costs map loaded." << endl;
+#endif
+}
+else EOFerrorR(fname);
+#else
+MemoLine("Costs map loaded.");
+#endif
+
+costs.close(); costs.clear();
+
+return maxcost;
+
+}
+
+//---------------------------------------------------------------------------
+
+rasterdata CheckRasterFile(string fname)
+{
+ rasterdata r;
+ string header;
+ int inint;
+ ifstream infile;
+
+ r.ok = true;
+ r.errors = r.ncols = r.nrows = r.cellsize = 0;
+ r.xllcorner = r.yllcorner = 0.0;
+
+ infile.open(fname.c_str());
+ if (infile.is_open()) {
+ infile >> header >> r.ncols;
+#if RSDEBUG
+ DebugGUI(("CheckRasterFile(): header=" + header + " r.ncols=" + Int2Str(r.ncols)
+ ).c_str());
+#endif
+ if (header != "ncols" && header != "NCOLS") r.errors++;
+ infile >> header >> r.nrows;
+#if RSDEBUG
+ DebugGUI(("CheckRasterFile(): header=" + header + " r.nrows=" + Int2Str(r.nrows)
+ ).c_str());
+#endif
+ if (header != "nrows" && header != "NROWS") r.errors++;
+ infile >> header >> r.xllcorner;
+#if RSDEBUG
+ DebugGUI(("CheckRasterFile(): header=" + header + " r.xllcorner=" + Float2Str(r.xllcorner)
+ ).c_str());
+#endif
+ if (header != "xllcorner" && header != "XLLCORNER") r.errors++;
+ infile >> header >> r.yllcorner;
+#if RSDEBUG
+ DebugGUI(("CheckRasterFile(): header=" + header + " r.yllcorner=" + Float2Str(r.yllcorner)
+ ).c_str());
+#endif
+ if (header != "yllcorner" && header != "YLLCORNER") r.errors++;
+ infile >> header >> r.cellsize;
+#if RSDEBUG
+ DebugGUI(("CheckRasterFile(): header=" + header + " r.cellsize=" + Int2Str(r.cellsize)
+ ).c_str());
+#endif
+ if (header != "cellsize" && header != "CELLSIZE") r.errors++;
+ infile >> header >> inint;
+#if RSDEBUG
+ DebugGUI(("CheckRasterFile(): header=" + header + " inint=" + Int2Str(inint)
+ ).c_str());
+#endif
+ if (header != "NODATA_value" && header != "NODATA_VALUE") r.errors++;
+ infile.close();
+ infile.clear();
+ if (r.errors > 0) r.ok = false;
+ }
+ else {
+ r.ok = false; r.errors = -111;
+ }
+ infile.clear();
+
+ return r;
+}
+
+//---------------------------------------------------------------------------
+
+// Patch connectivity functions
+
+// Create & initialise connectivity matrix
+void Landscape::createConnectMatrix(void)
+{
+ if (connectMatrix != 0) deleteConnectMatrix();
+ int npatches = (int)patches.size();
+#if RSDEBUG
+ //DEBUGLOG << "Landscape::createConnectMatrix(): npatches=" << npatches << endl;
+#endif
+ connectMatrix = new int* [npatches];
+ for (int i = 0; i < npatches; i++) {
+ connectMatrix[i] = new int[npatches];
+ for (int j = 0; j < npatches; j++) connectMatrix[i][j] = 0;
+ }
+}
+
+// Re-initialise connectivity matrix
+void Landscape::resetConnectMatrix(void)
+{
+ if (connectMatrix != 0) {
+ int npatches = (int)patches.size();
+ for (int i = 0; i < npatches; i++) {
+ for (int j = 0; j < npatches; j++) connectMatrix[i][j] = 0;
+ }
+ }
+}
+
+// Increment connectivity count between two specified patches
+void Landscape::incrConnectMatrix(int p0, int p1) {
+ int npatches = (int)patches.size();
+ if (connectMatrix == 0 || p0 < 0 || p0 >= npatches || p1 < 0 || p1 >= npatches) return;
+ connectMatrix[p0][p1]++;
+}
+
+// Delete connectivity matrix
+void Landscape::deleteConnectMatrix(void)
+{
+ if (connectMatrix != 0) {
+ int npatches = (int)patches.size();
+ for (int j = 0; j < npatches; j++) {
+ if (connectMatrix[j] != 0)
+ delete connectMatrix[j];
+ }
+ delete[] connectMatrix;
+ connectMatrix = 0;
+ }
+}
+
+// Write connectivity file headers
+bool Landscape::outConnectHeaders(int option)
+{
+ if (option == -999) { // close the file
+ if (outConnMat.is_open()) outConnMat.close();
+ outConnMat.clear();
+ return true;
+ }
+
+ simParams sim = paramsSim->getSim();
+
+ string name = paramsSim->getDir(2);
+ if (sim.batchMode) {
+ name += "Batch" + Int2Str(sim.batchNum) + "_";
+ name += "Sim" + Int2Str(sim.simulation) + "_Land" + Int2Str(landNum);
+ }
+ else
+ name += "Sim" + Int2Str(sim.simulation);
+ name += "_Connect.txt";
+ outConnMat.open(name.c_str());
+
+ outConnMat << "Rep\tYear\tStartPatch\tEndPatch\tNinds" << endl;
+
+ return outConnMat.is_open();
+}
+
+#if RS_RCPP
+// Write movement paths file headers
+void Landscape::outPathsHeaders(int rep, int option)
+{
+ if (option == -999) { // close the file
+ if (outMovePaths.is_open()) outMovePaths.close();
+ outMovePaths.clear();
+ }
+ if (option == 0) { // open the file and write header
+
+ simParams sim = paramsSim->getSim();
+ string name = paramsSim->getDir(2);
+ if (sim.batchMode) {
+ name += "Batch" + Int2Str(sim.batchNum)
+ + "_Sim" + Int2Str(sim.simulation)
+ + "_Land" + Int2Str(landNum)
+ + "_Rep" + Int2Str(rep);
+ }
+ else {
+ name += "Sim" + Int2Str(sim.simulation)
+ + "_Rep" + Int2Str(rep);
+ }
+ name += "_MovePaths.txt";
+
+ outMovePaths.open(name.c_str());
+ if (outMovePaths.is_open()) {
+ outMovePaths << "Year\tIndID\tStep\tx\ty\tStatus" << endl;
+ }
+ else {
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): UNABLE TO OPEN MOVEMENT PATHS FILE" << endl;
+#endif
+ outMovePaths.clear();
+ }
+ }
+}
+#endif
+
+void Landscape::outConnect(int rep, int yr)
+{
+ int patchnum0, patchnum1;
+ int npatches = (int)patches.size();
+ int* emigrants = new int[npatches]; // 1D array to hold emigrants from each patch
+ int* immigrants = new int[npatches]; // 1D array to hold immigrants to each patch
+
+ for (int i = 0; i < npatches; i++) {
+ emigrants[i] = immigrants[i] = 0;
+ }
+
+ for (int i = 0; i < npatches; i++) {
+ patchnum0 = patches[i]->getPatchNum();
+ if (patchnum0 != 0) {
+ for (int j = 0; j < npatches; j++) {
+ patchnum1 = patches[j]->getPatchNum();
+ if (patchnum1 != 0) {
+ emigrants[i] += connectMatrix[i][j];
+ immigrants[j] += connectMatrix[i][j];
+ if (connectMatrix[i][j] > 0) {
+ outConnMat << rep << "\t" << yr
+ << "\t" << patchnum0 << "\t" << patchnum1
+ << "\t" << connectMatrix[i][j] << endl;
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < npatches; i++) {
+ patchnum0 = patches[i]->getPatchNum();
+ if (patchnum0 != 0) {
+ if (patches[i]->getK() > 0.0)
+ { // suitable patch
+ outConnMat << rep << "\t" << yr
+ << "\t" << patchnum0 << "\t-999\t" << emigrants[i] << endl;
+ outConnMat << rep << "\t" << yr
+ << "\t-999\t" << patchnum0 << "\t" << immigrants[i] << endl;
+ }
+ }
+ }
+
+ delete[] emigrants;
+ delete[] immigrants;
+
+}
+
+//---------------------------------------------------------------------------
+
+void Landscape::resetVisits(void) {
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] != 0) { // not a no-data cell
+ cells[y][x]->resetVisits();
+ }
+ }
+ }
+}
+
+// Save SMS path visits map to raster text file
+void Landscape::outVisits(int rep, int landNr) {
+
+ string name;
+ simParams sim = paramsSim->getSim();
+
+ if (sim.batchMode) {
+ name = paramsSim->getDir(3)
+#if RS_RCPP
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation)
+ + "_Land" + Int2Str(landNr) + "_Rep" + Int2Str(rep)
+#else
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation)
+ + "_land" + Int2Str(landNr) + "_rep" + Int2Str(rep)
+#endif
+ + "_Visits.txt";
+ }
+ else {
+ name = paramsSim->getDir(3)
+ + "Sim" + Int2Str(sim.simulation)
+ + "_land" + Int2Str(landNr) + "_rep" + Int2Str(rep)
+ + "_Visits.txt";
+ }
+ outvisits.open(name.c_str());
+
+ outvisits << "ncols " << dimX << endl;
+ outvisits << "nrows " << dimY << endl;
+ outvisits << "xllcorner " << minEast << endl;
+ outvisits << "yllcorner " << minNorth << endl;
+ outvisits << "cellsize " << resol << endl;
+ outvisits << "NODATA_value -9" << endl;
+
+ for (int y = dimY - 1; y >= 0; y--) {
+ for (int x = 0; x < dimX; x++) {
+ if (cells[y][x] == 0) { // no-data cell
+ outvisits << "-9 ";
+ }
+ else {
+ outvisits << cells[y][x]->getVisits() << " ";
+ }
+ }
+ outvisits << endl;
+ }
+
+ outvisits.close(); outvisits.clear();
+}
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
diff --git a/src/RScore/Landscape.h b/src/RScore/Landscape.h
new file mode 100644
index 00000000..2a414cc1
--- /dev/null
+++ b/src/RScore/Landscape.h
@@ -0,0 +1,562 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 Landscape
+
+Implements the following classes:
+
+InitDist - Initial species distribution
+
+Landscape - Landscape grid
+
+The Landscape is a rectangular array of Cells which are grouped together in
+Patches. As far as the user is aware, the Landscape is either patch-based or
+cell-based (having no Patches), but internally Patches are always present (they
+each comprise only one Cell for a cell-based model). The grain of the Landscape
+may be any positive integer, and is nominally in metres.
+
+The Landscape is either input from one or more text files in ArcGIS raster export
+format, or it is generated artificially as a random or fractal binary array (in
+which case, it must be cell-based). An input 'real' Landscape may hold within each
+Cell either discrete habitat classes, or percent cover of habitat classes, or a
+continuous quality index (1 to 100%).
+
+The Landscape may be dynamic, in which case the user specifies a set of changes
+to be applied at certain years during each simulation. The changes may be to
+habitat only, patches only (if a patch-based model) or habitats and patches.
+Although the changes must be supplied as entire habitat / patch files (which
+must match the original Landscape in terms of cell size and extent), internally
+they are recorded as lists of dynamic habitat and patch changes.
+
+The initial species distribution is a rectangular array if distribution cells
+(DistCell) covering the same spatial extent at the Landscape. Its grain may be
+either that of the Landscape or an integer multiple of it.
+
+The Landscape can record a list (in the vector initcells) of Cells or Patches
+to be intialised, which are specified by the user in FormSeeding. This option is
+available in the GUI version only.
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Peer G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 2 December 2021 by Steve Palmer
+------------------------------------------------------------------------------*/
+
+#ifndef LandscapeH
+#define LandscapeH
+
+#include
+#include
+#include
+
+using namespace std;
+
+#include "Parameters.h"
+#include "Patch.h"
+#include "Cell.h"
+#include "Species.h"
+#include "FractalGenerator.h"
+#if RS_RCPP
+#include
+#if !RSWIN64
+#include
+#endif
+#include
+#endif
+
+//---------------------------------------------------------------------------
+
+// Initial species distribution
+
+class InitDist{
+public:
+ InitDist(Species*);
+ ~InitDist();
+ int readDistribution(
+ string // name of species distribution file
+ );
+ void setDistribution(
+ int // no. of distribution cells to be initialised (0 for all cells)
+ );
+ void setDistCell( // Set a specified cell (by position in cells vector)
+ int, // index no. of DistCell in cells vector
+ bool // value to be set
+ );
+ void setDistCell( // Set a specified cell (by co-ordinates)
+ locn, // structure holding x (column) and y (row) co-ordinates
+ bool
+ );
+ bool inInitialDist( // Specified location is within the initial distribution?
+ locn // structure holding x (column) and y (row) co-ordinates
+ );
+ int cellCount(void);
+ locn getCell( // Return the co-ordinates of a specified initial distribution cell
+ int // index no. of DistCell in cells vector
+ );
+ locn getSelectedCell( // Return the co-ordinates of a specified initial distribution
+ // cell if it has been selected
+ // otherwise return negative co-ordinates
+ int // index no. of DistCell in cells vector
+ );
+ locn getDimensions(void);
+ void resetDistribution(void);
+
+private:
+ Species *pSpecies; // pointer to species
+ int resol; // species distribution cell size (m)
+ int maxX, maxY; // dimensions
+ double minEast; // ) real world min co-ordinates
+ double minNorth; // ) read from raster file
+
+ // list of cells in the initial distribution
+ // cells MUST be loaded in the sequence ascending x within descending y
+ std::vector cells;
+
+};
+
+//---------------------------------------------------------------------------
+
+struct landParams {
+ bool patchModel; bool spDist; bool generated;
+ bool dynamic;
+ int landNum; int resol; int spResol; int nHab; int nHabMax;
+ int dimX,dimY,minX,minY,maxX,maxY;
+ short rasterType;
+};
+struct landData {
+ int resol; int dimX,dimY,minX,minY,maxX,maxY;
+};
+struct genLandParams {
+ bool fractal; bool continuous;
+ float minPct,maxPct; float propSuit; float hurst; int maxCells;
+};
+struct landPix {
+ int pix; float gpix;
+};
+struct landOrigin {
+ double minEast; double minNorth;
+};
+struct rasterHdr {
+ bool ok;
+ int errors,ncols,nrows,cellsize;
+ double xllcorner,yllcorner;
+};
+struct rasterdata {
+ bool ok;
+ int errors,ncols,nrows,cellsize;
+ double xllcorner,yllcorner;
+#if RS_RCPP
+ bool utf;
+#endif
+};
+struct patchData {
+ Patch *pPatch; int patchNum,nCells; int x,y;
+};
+struct landChange {
+ int chgnum,chgyear; string habfile,pchfile,costfile;
+};
+struct patchChange {
+ int chgnum, x, y, oldpatch, newpatch;
+};
+struct costChange {
+ int chgnum,x,y,oldcost,newcost;
+};
+
+class Landscape{
+public:
+ Landscape();
+ ~Landscape();
+ void resetLand(void);
+
+ // functions to set and return parameter values
+
+ void setLandParams(
+ landParams, // structure holding landscape parameters
+ bool // batch mode
+ );
+ landParams getLandParams(void);
+ landData getLandData(void);
+ void setGenLandParams(genLandParams);
+ genLandParams getGenLandParams(void);
+ void setLandLimits(
+ int, // minimum available X
+ int, // minimum available Y
+ int, // maximum available X
+ int // maximum available Y
+ );
+ void resetLandLimits(void);
+ void setLandPix(landPix);
+
+ landPix getLandPix(void);
+ void setOrigin(landOrigin);
+ landOrigin getOrigin(void);
+
+ // functions to handle habitat codes
+
+ bool habitatsIndexed(void);
+ void listHabCodes(void);
+ void addHabCode(int);
+ int findHabCode(int);
+ int getHabCode(int);
+ void clearHabitats(void);
+ void addColour(rgb);
+ void changeColour(int,rgb);
+ rgb getColour(int);
+ int colourCount(void);
+
+ // functions to handle patches and cells
+
+ void setCellArray(void);
+ void addPatchNum(int);
+ void generatePatches(void); // create an artificial landscape
+ void allocatePatches(Species*); // create patches for a cell-based landscape
+ Patch* newPatch(
+ int // patch sequential no. (id no. is set to equal sequential no.)
+ );
+ Patch* newPatch(
+ int, // patch sequential no.
+ int // patch id no.
+ );
+ void resetPatches(void);
+ void addNewCellToLand(
+ int, // x co-ordinate
+ int, // y co-ordinate
+ float // habitat quality value
+ );
+ void addNewCellToLand(
+ int, // x co-ordinate
+ int, // y co-ordinate
+ int // habitat class no.
+ );
+ void addCellToPatch(
+ Cell*, // pointer to Cell
+ Patch* // pointer to Patch
+ );
+ void addCellToPatch(
+ Cell*, // pointer to Cell
+ Patch*, // pointer to Patch
+ float // habitat quality value
+ );
+ void addCellToPatch(
+ Cell*, // pointer to Cell
+ Patch*, // pointer to Patch
+ int // habitat class no.
+ );
+ void addNewCellToPatch(
+ Patch*, // pointer to Patch
+ int, // x co-ordinate
+ int, // y co-ordinate
+ int // habitat class no.
+ );
+ void addNewCellToPatch(
+ Patch*, // pointer to Patch
+ int, // x co-ordinate
+ int, // y co-ordinate
+ float // habitat quality value
+ );
+ patchData getPatchData(
+ int // index no. of Patch in patches vector
+ );
+ bool existsPatch(
+ int // Patch id no.
+ );
+ Patch* findPatch(
+ int // Patch id no.
+ );
+ int checkTotalCover(void);
+ void resetPatchPopns(void);
+ void updateCarryingCapacity(
+ Species*, // pointer to Species
+ int, // year
+ short // landscape change index (always zero if not dynamic)
+ );
+ Cell* findCell(
+ int, // x co-ordinate
+ int // y co-ordinate
+ );
+ int patchCount(void);
+ void updateHabitatIndices(void);
+ void setEnvGradient(
+ Species*, // pointer to Species
+ bool // TRUE for initial instance that gradient is set
+ );
+ void setGlobalStoch(
+ int // no. of years
+ );
+ float getGlobalStoch(
+ int // year
+ );
+ void updateLocalStoch(void);
+ void resetCosts(void);
+ void resetEffCosts(void);
+
+ // functions to handle dynamic changes
+
+ void setDynamicLand(bool);
+ void addLandChange(
+ landChange // structure holding landscape change data
+ );
+ int numLandChanges(void);
+ landChange getLandChange(
+ short // change number
+ );
+ void deleteLandChanges(void);
+#if RS_RCPP && !R_CMD
+ int readLandChange(
+ int, // change file number
+ bool, // change SMS costs?
+ wifstream&, // habitat file stream
+ wifstream&, // patch file stream
+ wifstream&, // cost file stream
+ int, // habnodata
+ int, // pchnodata
+ int // costnodata
+ );
+#else
+ int readLandChange(
+ int, // change file number
+ bool // change SMS costs?
+ );
+#endif
+ void createPatchChgMatrix(void);
+ void recordPatchChanges(int);
+ void deletePatchChgMatrix(void);
+ int numPatchChanges(void);
+ patchChange getPatchChange(
+ int // patch change number
+ );
+ void createCostsChgMatrix(void);
+ void recordCostChanges(int);
+ void deleteCostsChgMatrix(void);
+ int numCostChanges(void);
+ costChange getCostChange(
+ int // cost change number
+ );
+
+ // functions to handle species distributions
+
+ int newDistribution(
+ Species*, // pointer to Species
+ string // name of initial distribution file
+ );
+ void setDistribution(
+ Species*, // pointer to Species
+ int // no. of distribution squares to initialise
+ );
+ bool inInitialDist( // Specified cell matches one of the distn cells to be initialised?
+ Species*, // pointer to Species
+ locn // structure holding co-ordinates of Cell
+ );
+ void deleteDistribution(
+ Species* // pointer to Species
+ );
+ int distnCount(void); // Return no. of initial distributions in the Landscape
+ int distCellCount( // Return no. of distribution cells in an initial distribution
+ int // index no. of InitDist in distns vector
+ );
+ locn getDistnCell( // Get co-ordinates of a specified cell in a specified initial distn
+ int, // index no. of InitDist in distns vector
+ int // index no. of DistCell in cells vector
+ );
+ locn getSelectedDistnCell( // Get co-ordinates of a specified cell in a specified initial distn
+ // Returns negative co-ordinates if the cell is not selected
+ int, // index no. of InitDist in distns vector
+ int // index no. of DistCell in cells vector
+ );
+ locn getDistnDimensions( // Get the dimensions of a specified initial distribution
+ int // index no. of InitDist in distns vector
+ );
+ void setDistnCell( // Set a cell in a specified init distn (by posn in cells vector)
+ int, // index no. of InitDist in distns vector
+ int, // index no. of DistCell in cells vector
+ bool // value to be set
+ );
+ void setDistnCell( // Set a cell in a specified init distn (by given co-ordinates)
+ int, // index no. of InitDist in distns vector
+ locn, // structure holding co-ordinates of DistCell
+ bool // value to be set
+ );
+ void resetDistribution(
+ Species* // pointer to Species
+ );
+
+ // functions to handle initialisation cells
+
+ int initCellCount(void);
+ void addInitCell( // Create a new DistCell and add to the initcells vector
+ int, // x co-ordinate
+ int // y co-ordinate
+ );
+ locn getInitCell(
+ int // index no. of DistCell in initcells vector
+ );
+ void clearInitCells(void);
+
+ // functions to handle connectivity matrix
+
+ void createConnectMatrix(void);
+ void resetConnectMatrix(void);
+ void incrConnectMatrix(
+ int, // sequential no. of origin Patch
+ int // sequential no. of settlement Patch
+ );
+ void deleteConnectMatrix(void);
+ bool outConnectHeaders( // Write connectivity file headers
+ int // option - set to -999 to close the connectivity file
+ );
+#if RS_RCPP
+ void outPathsHeaders(int, int);
+#endif
+ void outConnect(
+ int, // replicate no.
+ int // year
+ );
+
+ // functions to handle input and output
+
+ int readLandscape(
+ int, // fileNum == 0 for (first) habitat file and optional patch file
+ // fileNum > 0 for subsequent habitat files under the %cover option
+ string, // habitat file name
+ string, // patch file name
+ string // cost file name (may be NULL)
+ );
+ void listPatches(void);
+ int readCosts(
+ string // costs file name
+ );
+ // the following four functions are implemented for the GUI version only
+ // in the batch version, they are defined, but empty
+ void setLandMap(void);
+ void drawLandscape(
+ int, // replicate no.
+ int, // landscape index number (always 0 if landscape is not dynamic)
+ int // landscape no.
+ );
+ void drawGradient(void); // Draw environmental gradient map
+ void drawGlobalStoch( // Draw environmental stochasticity time-series
+ int // no. of years
+ );
+
+ void resetVisits(void);
+ void outVisits(int,int); // save SMS path visits map to raster text file
+
+private:
+ bool generated; // artificially generated?
+ bool patchModel; //
+ bool spDist; // initial species distribution loaded
+ bool fractal; //
+ bool continuous; //
+ bool dynamic; // landscape changes during simulation
+ bool habIndexed; // habitat codes have been converted to index numbers
+ short rasterType; // 0 = habitat codes 1 = % cover 2 = quality 9 = artificial landscape
+ int landNum; // landscape number
+ int resol; // cell size (m)
+ int spResol; // species distribution cell size (m)
+ int nHab; // no. of habitats
+ int nHabMax; // max. no. of habitats (used for batch input only)
+ int dimX,dimY; // dimensions
+ int minX,minY; // minimum available X and Y co-ordinates
+ int maxX,maxY; // maximum available X and Y co-ordinates
+ float minPct,maxPct; // min and max percentage of habitat in a cell
+ float propSuit; // proportion of suitable cells
+ float hurst; // Hurst exponent
+ int maxCells; // max. cells per patch (artificial landscapes)
+ int pix; // image display ratio
+ float gpix; // image display ratio for gradient map
+ double minEast; // ) real world min co-ordinates
+ double minNorth; // ) read from habitat raster
+
+ // list of cells in the landscape
+ // cells MUST be loaded in the sequence ascending x within descending y
+ Cell ***cells;
+
+ // list of patches in the landscape - can be in any sequence
+ std::vector patches;
+
+ // list of patch numbers in the landscape
+ std::vector patchnums;
+
+ // list of habitat codes
+ std::vector habCodes;
+
+ // list of colours for habitat codes
+ std::vector colours;
+
+ // list of dynamic landscape changes
+ std::vector landchanges;
+ std::vector patchchanges;
+ std::vector costschanges;
+
+ // list of initial individual species distributions
+ std::vector distns;
+
+ // list of cells to be initialised for ALL species
+ std::vector initcells;
+
+ // patch connectivity matrix
+ // indexed by [start patch seq num][end patch seq num]
+ int **connectMatrix;
+
+ // global environmental stochasticity (epsilon)
+ float *epsGlobal; // pointer to time-series
+
+ // patch and costs change matrices (temporary - used when reading dynamic landscape)
+ // indexed by [descending y][x][period]
+ // where there are three periods, 0=original 1=previous 2=current
+ int ***patchChgMatrix;
+ int ***costsChgMatrix;
+
+};
+
+// NOTE: the following function is not a behaviour of Landscape, as it is run by the
+// batch routine to check raster files before any Landscape has been initiated
+rasterdata CheckRasterFile(string);
+
+extern paramGrad *paramsGrad;
+extern paramStoch *paramsStoch;
+extern paramInit *paramsInit;
+extern paramSim *paramsSim;
+extern RSrandom *pRandom;
+
+#if RSDEBUG
+extern ofstream DEBUGLOG;
+extern void DebugGUI(string);
+#endif
+
+extern void MemoLine(string);
+
+#if RS_RCPP
+extern rasterdata landraster,patchraster,spdistraster,costsraster;
+extern void EOFerrorR(string);
+extern void StreamErrorR(string);
+#endif
+
+//---------------------------------------------------------------------------
+#endif
diff --git a/src/RScore/Main.cpp b/src/RScore/Main.cpp
new file mode 100644
index 00000000..42f783b8
--- /dev/null
+++ b/src/RScore/Main.cpp
@@ -0,0 +1,95 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+#if LINUX_CLUSTER || R_CMD
+#include
+#else
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include "Individual.h"
+#include "Community.h"
+#include "RSrandom.h"
+#include "Utils.h"
+#include "Parameters.h"
+#include "Landscape.h"
+#include "Species.h"
+#include "SubCommunity.h"
+
+using namespace std;
+
+void run_unit_tests() {
+ cout << "******* Unit test output *******" << endl;
+ testRSrandom();
+ testIndividual();
+ cout << endl << "************************" << endl;
+}
+
+// Global vars
+string habmapname, patchmapname, distnmapname;
+string costmapname, genfilename;
+string landFile;
+paramGrad* paramsGrad;
+paramStoch* paramsStoch;
+paramInit* paramsInit;
+paramSim* paramsSim;
+RSrandom* pRandom;
+ofstream DEBUGLOG;
+ofstream MUTNLOG;
+vector hfnames;
+Species* pSpecies;
+Community* pComm;
+void DebugGUI(string msg) {
+ // nothing
+}
+void MemoLine(string msg) {
+ /// nothing
+}
+traitCanvas SetupTraitCanvas(void) {
+ traitCanvas tcanv;
+ for (int i = 0; i < NTRAITS; i++) { tcanv.pcanvas[i] = 0; }
+ return tcanv;
+}
+void Landscape::setLandMap(void) { }
+void Landscape::drawLandscape(int rep, int yr, int landnum) { }
+void Community::viewOccSuit(int year, double mn, double se) { }
+void Community::draw(int rep, int yr, int gen, int landNum) { }
+
+#if LINUX_CLUSTER || RS_RCPP
+int main(int argc, char* argv[])
+#else
+int _tmain(int argc, _TCHAR* argv[])
+#endif
+{
+#ifdef NDEBUG
+ cout << "This code is only for running tests and not meant to run in release." << endl;
+ return 1;
+# else
+ assert(0.1 > 0.0); // assert does run correctly
+ run_unit_tests();
+ cout << "All tests have completed." << endl;
+ return 0; // if tests succeed, we are happy
+# endif // NDEBUG
+}
diff --git a/src/RScore/Model.cpp b/src/RScore/Model.cpp
new file mode 100644
index 00000000..fc4fac94
--- /dev/null
+++ b/src/RScore/Model.cpp
@@ -0,0 +1,2093 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+ //---------------------------------------------------------------------------
+
+#include "Model.h"
+
+ofstream outPar;
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+#if RS_RCPP && !R_CMD
+Rcpp::List RunModel(Landscape* pLandscape, int seqsim)
+#else
+int RunModel(Landscape* pLandscape, int seqsim)
+#endif
+{
+ int yr, totalInds;
+ bool filesOK;
+
+ landParams ppLand = pLandscape->getLandParams();
+ envGradParams grad = paramsGrad->getGradient();
+ envStochParams env = paramsStoch->getStoch();
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+ trfrRules trfr = pSpecies->getTrfr();
+ initParams init = paramsInit->getInit();
+ simParams sim = paramsSim->getSim();
+ simView v = paramsSim->getViews();
+
+#if RSDEBUG
+ landPix p = pLandscape->getLandPix();
+ DEBUGLOG << "RunModel(): reps=" << sim.reps
+ << " ppLand.nHab=" << ppLand.nHab
+ << " p.pix=" << p.pix
+ << endl;
+ DEBUGLOG << endl;
+#endif
+
+ if (!ppLand.generated) {
+ if (!ppLand.patchModel) { // cell-based landscape
+ // create patches for suitable cells, adding unsuitable cells to the matrix
+ // NB this is an overhead here, but is necessary in case the identity of
+ // suitable habitats has been changed from one simulation to another (GUI or batch)
+ // substantial time savings may result during simulation in certain landscapes
+ pLandscape->allocatePatches(pSpecies);
+ }
+ pComm = new Community(pLandscape); // set up community
+ // set up a sub-community associated with each patch (incl. the matrix)
+ pLandscape->updateCarryingCapacity(pSpecies, 0, 0);
+ patchData ppp;
+ int npatches = pLandscape->patchCount();
+ for (int i = 0; i < npatches; i++) {
+ ppp = pLandscape->getPatchData(i);
+ pComm->addSubComm(ppp.pPatch, ppp.patchNum); // SET UP ALL SUB-COMMUNITIES
+ }
+ if (init.seedType == 0 && init.freeType < 2 && init.initFrzYr > 0) {
+ // restrict available landscape to initialised region
+ pLandscape->setLandLimits(init.minSeedX, init.minSeedY,
+ init.maxSeedX, init.maxSeedY);
+ }
+ else {
+ pLandscape->resetLandLimits();
+ }
+ }
+
+#if RS_RCPP && !R_CMD
+ Rcpp::List list_outPop;
+#endif
+
+ // Loop through replicates
+ for (int rep = 0; rep < sim.reps; rep++) {
+#if RSDEBUG
+ DEBUGLOG << endl << "RunModel(): starting simulation=" << sim.simulation << " rep=" << rep << endl;
+#endif
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << endl << "starting replicate " << rep << endl;
+#else
+#if BATCH
+ cout << endl << "starting replicate " << rep << endl;
+#endif
+#endif
+
+ MemoLine(("Running replicate " + Int2Str(rep) + "...").c_str());
+
+ if (sim.saveVisits && !ppLand.generated) {
+ pLandscape->resetVisits();
+ }
+
+ patchChange patchchange;
+ costChange costchange;
+ int npatchchanges = pLandscape->numPatchChanges();
+ int ncostchanges = pLandscape->numCostChanges();
+ int ixpchchg = 0;
+ int ixcostchg = 0;
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): npatchchanges=" << npatchchanges << " ncostchanges=" << ncostchanges << endl;
+#endif
+
+ if (ppLand.generated) {
+#if RSDEBUG
+ DEBUGLOG << endl << "RunModel(): generating new landscape ..." << endl;
+#endif
+ // delete previous community (if any)
+ // Note: this must be BEFORE the landscape is reset (as a sub-community accesses
+ // its corresponding patch upon deletion)
+ if (pComm != 0) delete pComm;
+ // generate new cell-based landscape
+ MemoLine("...generating new landscape...");
+ pLandscape->resetLand();
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): finished resetting landscape" << endl << endl;
+#endif
+ pLandscape->generatePatches();
+ if (v.viewLand || sim.saveMaps) {
+ pLandscape->setLandMap();
+ pLandscape->drawLandscape(rep, 0, ppLand.landNum);
+ }
+#if RSDEBUG
+ DEBUGLOG << endl << "RunModel(): finished generating patches" << endl;
+#endif
+ pComm = new Community(pLandscape); // set up community
+ // set up a sub-community associated with each patch (incl. the matrix)
+ pLandscape->updateCarryingCapacity(pSpecies, 0, 0);
+ patchData ppp;
+ int npatches = pLandscape->patchCount();
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): patch count is " << npatches << endl;
+#endif
+ for (int i = 0; i < npatches; i++) {
+ ppp = pLandscape->getPatchData(i);
+#if RSWIN64
+#if LINUX_CLUSTER
+ pComm->addSubComm(ppp.pPatch, ppp.patchNum); // SET UP ALL SUB-COMMUNITIES
+#else
+ SubCommunity* pSubComm = pComm->addSubComm(ppp.pPatch, ppp.patchNum); // SET UP ALL SUB-COMMUNITIES
+#endif
+#else
+ pComm->addSubComm(ppp.pPatch, ppp.patchNum); // SET UP ALL SUB-COMMUNITIES
+#endif
+ }
+ MemoLine("...completed...");
+#if RSDEBUG
+ DEBUGLOG << endl << "RunModel(): finished generating populations" << endl;
+#endif
+ }
+ if (init.seedType == 0 && init.freeType < 2 && init.initFrzYr > 0) {
+ // restrict available landscape to initialised region
+ pLandscape->setLandLimits(init.minSeedX, init.minSeedY,
+ init.maxSeedX, init.maxSeedY);
+ }
+ else {
+ pLandscape->resetLandLimits();
+ }
+
+ filesOK = true;
+ if (rep == 0) {
+ // open output files
+ if (sim.outRange) { // open Range file
+ if (!pComm->outRangeHeaders(pSpecies, ppLand.landNum)) {
+ MemoLine("UNABLE TO OPEN RANGE FILE");
+ filesOK = false;
+ }
+ }
+ if (sim.outOccup && sim.reps > 1)
+ if (!pComm->outOccupancyHeaders(0)) {
+ MemoLine("UNABLE TO OPEN OCCUPANCY FILE(S)");
+ filesOK = false;
+ }
+ if (sim.outPop) {
+ // open Population file
+ if (!pComm->outPopHeaders(pSpecies, ppLand.landNum)) {
+ MemoLine("UNABLE TO OPEN POPULATION FILE");
+ filesOK = false;
+ }
+ }
+ if (sim.outTraitsCells)
+ if (!pComm->outTraitsHeaders(pSpecies, ppLand.landNum)) {
+ MemoLine("UNABLE TO OPEN TRAITS FILE");
+ filesOK = false;
+ }
+ if (sim.outTraitsRows)
+ if (!pComm->outTraitsRowsHeaders(pSpecies, ppLand.landNum)) {
+ MemoLine("UNABLE TO OPEN TRAITS ROWS FILE");
+ filesOK = false;
+ }
+ if (sim.outConnect && ppLand.patchModel) // open Connectivity file
+ if (!pLandscape->outConnectHeaders(0)) {
+ MemoLine("UNABLE TO OPEN CONNECTIVITY FILE");
+ filesOK = false;
+ }
+ }
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): completed opening output files" << endl;
+#endif
+ if (!filesOK) {
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): PROBLEM - closing output files" << endl;
+#endif
+ // close any files which may be open
+ if (sim.outRange) {
+ pComm->outRangeHeaders(pSpecies, -999);
+ }
+ if (sim.outOccup && sim.reps > 1)
+ pComm->outOccupancyHeaders(-999);
+ if (sim.outPop) {
+ pComm->outPopHeaders(pSpecies, -999);
+ }
+ if (sim.outTraitsCells)
+ pComm->outTraitsHeaders(pSpecies, -999);
+ if (sim.outTraitsRows)
+ pComm->outTraitsRowsHeaders(pSpecies, -999);
+ if (sim.outConnect && ppLand.patchModel)
+ pLandscape->outConnectHeaders(-999);
+#if RS_RCPP && !R_CMD
+ return Rcpp::List::create(Rcpp::Named("Errors") = 666);
+#else
+ return 666;
+#endif
+ }
+
+ if (env.stoch && !env.local) {
+ // create time series in case of global environmental stochasticity
+ pLandscape->setGlobalStoch(sim.years + 1);
+ }
+
+ if (grad.gradient) { // set up environmental gradient
+ pLandscape->setEnvGradient(pSpecies, true);
+ }
+
+ if (sim.outConnect && ppLand.patchModel)
+ pLandscape->createConnectMatrix();
+
+ // variables to control dynamic landscape
+ landChange landChg; landChg.chgnum = 0; landChg.chgyear = 999999;
+ if (!ppLand.generated && ppLand.dynamic) {
+ landChg = pLandscape->getLandChange(0); // get first change year
+ }
+
+ // set up populations in the community
+ pLandscape->updateCarryingCapacity(pSpecies, 0, 0);
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): completed updating carrying capacity" << endl;
+#endif
+ // if (init.seedType != 2) {
+ pComm->initialise(pSpecies, -1);
+ // }
+ bool updateland = false;
+ int landIx = 0; // landscape change index
+
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): completed initialisation, rep=" << rep
+ << " pSpecies=" << pSpecies << endl;
+#endif
+#if BATCH && RS_RCPP && !R_CMD
+ Rcpp::Rcout << "RunModel(): completed initialisation " << endl;
+#endif
+
+ // open a new individuals file for each replicate
+ if (sim.outInds)
+ pComm->outInds(rep, 0, 0, ppLand.landNum);
+ // open a new genetics file for each replicate
+ if (sim.outGenetics) {
+ pComm->outGenetics(rep, 0, 0, ppLand.landNum);
+ if (!dem.stageStruct && sim.outStartGenetic == 0) {
+ // write genetic data for initialised individuals of non-strucutred population
+ pComm->outGenetics(rep, 0, 0, -1);
+ }
+ }
+#if RSDEBUG
+ // output initialised Individuals
+ if (sim.outInds)
+ pComm->outInds(rep, -1, -1, -1);
+#endif
+#if RS_RCPP
+ // open a new movement paths file for each replicate
+ if (sim.outPaths)
+ pLandscape->outPathsHeaders(rep, 0);
+#endif
+
+ // years loop
+ MemoLine("...running...");
+ for (yr = 0; yr < sim.years; yr++) {
+#if RSDEBUG
+ DEBUGLOG << endl << "RunModel(): starting simulation=" << sim.simulation
+ << " rep=" << rep << " yr=" << yr << endl;
+#endif
+#if RS_RCPP && !R_CMD
+ Rcpp::checkUserInterrupt();
+#endif
+ bool updateCC = false;
+ if (yr < 4
+ || (yr < 31 && yr % 10 == 0)
+ || (yr < 301 && yr % 100 == 0)
+ || (yr < 3001 && yr % 1000 == 0)
+ || (yr < 30001 && yr % 10000 == 0)
+ || (yr < 300001 && yr % 100000 == 0)
+ || (yr < 3000001 && yr % 1000000 == 0)
+ ) {
+#if RS_RCPP && !R_CMD
+ Rcpp::Rcout << "starting year " << yr << "..." << endl;
+#else
+ cout << "starting year " << yr << endl;
+#endif
+ }
+ if (init.seedType == 0 && init.freeType < 2) {
+ // apply any range restrictions
+ if (yr == init.initFrzYr) {
+ // release initial frozen range - reset landscape to its full extent
+ pLandscape->resetLandLimits();
+ updateCC = true;
+ }
+ if (init.restrictRange) {
+ if (yr > init.initFrzYr && yr < init.finalFrzYr) {
+ if ((yr - init.initFrzYr) % init.restrictFreq == 0) {
+ // apply dynamic range restriction
+ commStats s = pComm->getStats();
+ int minY = s.maxY - init.restrictRows;
+ if (minY < 0) minY = 0;
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): restriction yr=" << yr
+ << " s.minY=" << s.minY << " s.maxY=" << s.maxY
+ << " init.restrictRows=" << init.restrictRows
+ << " minY=" << minY
+ << endl;
+#endif
+ pLandscape->setLandLimits(ppLand.minX, minY, ppLand.maxX, ppLand.maxY);
+ updateCC = true;
+ }
+ }
+ if (yr == init.finalFrzYr) {
+ // apply final range restriction
+ commStats s = pComm->getStats();
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): final restriction yr=" << yr
+ << " s.minY=" << s.minY << " s.maxY=" << s.maxY
+ << endl;
+#endif
+ pLandscape->setLandLimits(ppLand.minX, s.minY, ppLand.maxX, s.maxY);
+ updateCC = true;
+ }
+ }
+ }
+ // environmental gradient, stochasticity & local extinction
+ // or dynamic landscape
+ updateland = false;
+ if (env.stoch || grad.gradient || ppLand.dynamic) {
+ if (grad.shifting && yr > grad.shift_begin && yr < grad.shift_stop) {
+ paramsGrad->incrOptY();
+ pLandscape->setEnvGradient(pSpecies, false);
+ updateCC = true;
+ }
+ if (env.stoch) {
+ if (env.local) pLandscape->updateLocalStoch();
+ updateCC = true;
+ }
+ if (ppLand.dynamic) {
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " landChg.chgnum=" << landChg.chgnum
+ << " landChg.chgyear=" << landChg.chgyear
+ << " npatchchanges=" << npatchchanges << " ncostchanges=" << ncostchanges
+ << " ixpchchg=" << ixpchchg << " ixcostchg=" << ixcostchg
+ << endl;
+#endif
+ if (yr == landChg.chgyear) { // apply landscape change
+ landIx = landChg.chgnum;
+ updateland = updateCC = true;
+ if (ppLand.patchModel) { // apply any patch changes
+ Patch* pPatch;
+ Cell* pCell;
+ patchchange = pLandscape->getPatchChange(ixpchchg++);
+ while (patchchange.chgnum <= landIx && ixpchchg <= npatchchanges) {
+
+ // move cell from original patch to new patch
+ pCell = pLandscape->findCell(patchchange.x, patchchange.y);
+ if (patchchange.oldpatch != 0) { // not matrix
+ pPatch = pLandscape->findPatch(patchchange.oldpatch);
+ pPatch->removeCell(pCell);
+ }
+ if (patchchange.newpatch == 0) { // matrix
+ pPatch = 0;
+ }
+ else {
+ pPatch = pLandscape->findPatch(patchchange.newpatch);
+ pPatch->addCell(pCell, patchchange.x, patchchange.y);
+ }
+ pCell->setPatch((intptr)pPatch);
+ // get next patch change
+ patchchange = pLandscape->getPatchChange(ixpchchg++);
+ }
+ ixpchchg--;
+ pLandscape->resetPatches(); // reset patch limits
+ }
+ if (landChg.costfile != "NULL") { // apply any SMS cost changes
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " landChg.costfile=" << landChg.costfile << endl;
+#endif
+ Cell* pCell;
+ costchange = pLandscape->getCostChange(ixcostchg++);
+ while (costchange.chgnum <= landIx && ixcostchg <= ncostchanges) {
+ pCell = pLandscape->findCell(costchange.x, costchange.y);
+ if (pCell != 0) {
+ pCell->setCost(costchange.newcost);
+ }
+ costchange = pLandscape->getCostChange(ixcostchg++);
+ }
+ ixcostchg--;
+ pLandscape->resetEffCosts();
+ }
+ if (landIx < pLandscape->numLandChanges()) { // get next change
+ landChg = pLandscape->getLandChange(landIx);
+ }
+ else {
+ landChg.chgyear = 9999999;
+ }
+ }
+ }
+ } // end of environmental gradient, etc.
+
+ if (updateCC) {
+ pLandscape->updateCarryingCapacity(pSpecies, yr, landIx);
+ }
+
+
+ if (sim.outConnect && ppLand.patchModel)
+ pLandscape->resetConnectMatrix();
+
+ if (ppLand.dynamic && updateland) {
+ if (trfr.moveModel && trfr.moveType == 1) { // SMS
+ if (!trfr.costMap) pLandscape->resetCosts(); // in case habitats have changed
+ }
+ // apply effects of landscape change to species present in changed patches
+ pComm->patchChanges();
+#if RS_RCPP
+ pComm->dispersal(landIx, yr);
+#else
+ pComm->dispersal(landIx);
+#endif // RS_RCPP
+ }
+ if (init.restrictRange) {
+ // remove any population from region removed from restricted range
+ if (yr > init.initFrzYr && yr < init.finalFrzYr) {
+ if ((yr - init.initFrzYr) % init.restrictFreq == 0) {
+ pComm->patchChanges();
+ }
+ }
+ }
+
+ if (init.seedType == 2) {
+ // add any new initial individuals for the current year
+ pComm->initialise(pSpecies, yr);
+ }
+
+ for (int gen = 0; gen < dem.repSeasons; gen++) // generation loop
+ {
+#if RSDEBUG
+ // TEMPORARY RANDOM STREAM CHECK
+ if (yr % 1 == 0)
+ {
+ DEBUGLOG << endl << "RunModel(): start of gen " << gen << " in year " << yr
+ << " for rep " << rep << " (";
+ for (int i = 0; i < 5; i++) {
+ int rrrr = pRandom->IRandom(1000, 2000);
+ DEBUGLOG << " " << rrrr;
+ }
+ DEBUGLOG << " )" << endl;
+ }
+#endif
+
+ if (v.viewPop || (sim.saveMaps && yr % sim.mapInt == 0)) {
+ if (updateland && gen == 0) {
+ pLandscape->drawLandscape(rep, landIx, ppLand.landNum);
+ }
+ pComm->draw(rep, yr, gen, ppLand.landNum);
+ }
+ // Output and pop. visualisation before reproduction
+ if (v.viewPop || v.viewTraits || sim.outOccup
+ || sim.outTraitsCells || sim.outTraitsRows || sim.saveMaps)
+ PreReproductionOutput(pLandscape, pComm, rep, yr, gen);
+ // for non-structured population, also produce range and population output now
+ if (!dem.stageStruct && (sim.outRange || sim.outPop))
+ RangePopOutput(pComm, rep, yr, gen);
+#if RS_RCPP && !R_CMD
+ if (sim.ReturnPopRaster && sim.outPop && yr >= sim.outStartPop && yr % sim.outIntPop == 0) {
+ list_outPop.push_back(pComm->addYearToPopList(rep, yr), "rep" + std::to_string(rep) + "_year" + std::to_string(yr));
+ }
+#endif
+ // apply local extinction for generation 0 only
+ // CHANGED TO *BEFORE* RANGE & POPN OUTPUT PRODUCTION IN v1.1,
+ // SO THAT NOS. OF JUVENILES BORN CAN BE REPORTED
+ if (!ppLand.patchModel && gen == 0) {
+ if (env.localExt) pComm->localExtinction(0);
+ if (grad.gradient && grad.gradType == 3) pComm->localExtinction(1);
+ }
+
+ // reproduction
+ pComm->reproduction(yr);
+
+ if (dem.stageStruct) {
+ if (sstruct.survival == 0) { // at reproduction
+ pComm->survival(0, 2, 1); // survival of all non-juvenile stages
+ }
+ }
+
+ // Output and pop. visualisation AFTER reproduction
+ if (dem.stageStruct && (sim.outRange || sim.outPop))
+ RangePopOutput(pComm, rep, yr, gen);
+
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " gen=" << gen << " completed reproduction" << endl;
+#endif
+
+ // Dispersal
+
+ pComm->emigration();
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " gen=" << gen << " completed emigration" << endl;
+#endif
+#if RS_RCPP
+ pComm->dispersal(landIx, yr);
+#else
+ pComm->dispersal(landIx);
+#endif // RS_RCPP
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " gen=" << gen << " completed dispersal" << endl;
+#endif
+
+ // survival part 0
+ if (dem.stageStruct) {
+ if (sstruct.survival == 0) { // at reproduction
+ pComm->survival(0, 0, 1); // survival of juveniles only
+ }
+ if (sstruct.survival == 1) { // between reproduction events
+ pComm->survival(0, 1, 1); // survival of all stages
+ }
+ if (sstruct.survival == 2) { // annually
+ pComm->survival(0, 1, 0); // development only of all stages
+ }
+ }
+ else { // non-structured population
+ pComm->survival(0, 1, 1);
+ }
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " gen=" << gen << " completed survival part 0" << endl;
+#endif
+
+
+ // output Individuals
+ if (sim.outInds && yr >= sim.outStartInd && yr % sim.outIntInd == 0)
+ pComm->outInds(rep, yr, gen, -1);
+ // output Genetics
+ if (sim.outGenetics && yr >= sim.outStartGenetic && yr % sim.outIntGenetic == 0)
+ pComm->outGenetics(rep, yr, gen, -1);
+
+ // survival part 1
+ if (dem.stageStruct) {
+ pComm->survival(1, 0, 1);
+ }
+ else { // non-structured population
+ pComm->survival(1, 0, 1);
+ }
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " gen=" << gen << " completed survival part 1" << endl;
+#endif
+
+ } // end of the generation loop
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " completed generation loop" << endl;
+#endif
+
+ totalInds = pComm->totalInds();
+ if (totalInds <= 0) { yr++; break; }
+
+ // Connectivity Matrix
+ if (sim.outConnect && ppLand.patchModel
+ && yr >= sim.outStartConn && yr % sim.outIntConn == 0)
+ pLandscape->outConnect(rep, yr);
+
+ if (dem.stageStruct && sstruct.survival == 2) { // annual survival - all stages
+ pComm->survival(0, 1, 2);
+ pComm->survival(1, 0, 1);
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " completed annual survival" << endl;
+#endif
+ }
+
+ if (dem.stageStruct) {
+ pComm->ageIncrement(); // increment age of all individuals
+ if (sim.outInds && yr >= sim.outStartInd && yr % sim.outIntInd == 0)
+ pComm->outInds(rep, yr, -1, -1); // list any individuals dying having reached maximum age
+ pComm->survival(1, 0, 1); // delete any such individuals
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " completed Age_increment and final survival" << endl;
+#endif
+ totalInds = pComm->totalInds();
+ if (totalInds <= 0) { yr++; break; }
+ }
+
+ } // end of the years loop
+
+ // Final output and popn. visualisation
+#if BATCH
+ if (sim.saveMaps && yr % sim.mapInt == 0) {
+ if (updateland) {
+ pLandscape->drawLandscape(rep, landIx, ppLand.landNum);
+ }
+ pComm->draw(rep, yr, 0, ppLand.landNum);
+ }
+#endif
+ // produce final summary output
+ if (v.viewPop || v.viewTraits || sim.outOccup
+ || sim.outTraitsCells || sim.outTraitsRows || sim.saveMaps)
+ PreReproductionOutput(pLandscape, pComm, rep, yr, 0);
+ if (sim.outRange || sim.outPop)
+ RangePopOutput(pComm, rep, yr, 0);
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " completed final summary output" << endl;
+#endif
+
+ pComm->resetPopns();
+
+ //Reset the gradient optimum
+ if (grad.gradient) paramsGrad->resetOptY();
+
+ pLandscape->resetLandLimits();
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " landIx=" << "reset"
+ << " npatchchanges=" << npatchchanges << " ncostchanges=" << ncostchanges
+ << " ixpchchg=" << ixpchchg << " ixcostchg=" << ixcostchg
+ << endl;
+#endif
+ if (ppLand.patchModel && ppLand.dynamic && ixpchchg > 0) {
+ // apply any patch changes to reset landscape to original configuration
+ // (provided that at least one has already occurred)
+ patchChange patchchange;
+ Patch* pPatch;
+ Cell* pCell;
+ patchchange = pLandscape->getPatchChange(ixpchchg++);
+ while (patchchange.chgnum <= 666666 && ixpchchg <= npatchchanges) {
+
+ // move cell from original patch to new patch
+ pCell = pLandscape->findCell(patchchange.x, patchchange.y);
+ if (patchchange.oldpatch != 0) { // not matrix
+ pPatch = pLandscape->findPatch(patchchange.oldpatch);
+ pPatch->removeCell(pCell);
+ }
+ if (patchchange.newpatch == 0) { // matrix
+ pPatch = 0;
+ }
+ else {
+ pPatch = pLandscape->findPatch(patchchange.newpatch);
+ pPatch->addCell(pCell, patchchange.x, patchchange.y);
+ }
+ pCell->setPatch((intptr)pPatch);
+ // get next patch change
+ patchchange = pLandscape->getPatchChange(ixpchchg++);
+ }
+ ixpchchg--;
+ pLandscape->resetPatches();
+ }
+ if (ppLand.dynamic) {
+ trfrRules trfr = pSpecies->getTrfr();
+ if (trfr.moveModel && trfr.moveType == 1) { // SMS
+ if (ixcostchg > 0) {
+ // apply any cost changes to reset landscape to original configuration
+ // (provided that at least one has already occurred)
+ Cell* pCell;
+ costchange = pLandscape->getCostChange(ixcostchg++);
+ while (costchange.chgnum <= 666666 && ixcostchg <= ncostchanges) {
+
+ pCell = pLandscape->findCell(costchange.x, costchange.y);
+ if (pCell != 0) {
+ pCell->setCost(costchange.newcost);
+ }
+ costchange = pLandscape->getCostChange(ixcostchg++);
+ }
+ ixcostchg--;
+ pLandscape->resetEffCosts();
+ }
+ if (!trfr.costMap) pLandscape->resetCosts(); // in case habitats have changed
+ }
+ }
+#if RSDEBUG
+ DEBUGLOG << "RunModel(): yr=" << yr << " completed reset"
+ << endl;
+#endif
+
+ if (sim.outConnect && ppLand.patchModel)
+ pLandscape->resetConnectMatrix(); // set connectivity matrix to zeroes
+
+ if (sim.outInds) // close Individuals output file
+ pComm->outInds(rep, 0, 0, -999);
+ if (sim.outGenetics) // close Genetics output file
+ pComm->outGenetics(rep, 0, 0, -999);
+
+ if (sim.saveVisits) {
+ pLandscape->outVisits(rep, ppLand.landNum);
+ pLandscape->resetVisits();
+ }
+
+#if RS_RCPP
+ if (sim.outPaths)
+ pLandscape->outPathsHeaders(rep, -999);
+#endif
+#if RSDEBUG
+ DEBUGLOG << endl << "RunModel(): finished rep=" << rep << endl;
+#endif
+
+ } // end of the replicates loop
+
+ if (sim.outConnect && ppLand.patchModel) {
+ pLandscape->deleteConnectMatrix();
+ pLandscape->outConnectHeaders(-999); // close Connectivity Matrix file
+ }
+
+ // Occupancy outputs
+ if (sim.outOccup && sim.reps > 1) {
+ MemoLine("Writing final occupancy output...");
+ pComm->outOccupancy();
+ pComm->outOccSuit(v.viewGraph);
+ pComm->deleteOccupancy((sim.years / sim.outIntOcc) + 1);
+ pComm->outOccupancyHeaders(-999);
+ MemoLine("...finished");
+ }
+
+ if (sim.outRange) {
+ pComm->outRangeHeaders(pSpecies, -999); // close Range file
+ }
+ if (sim.outPop) {
+ pComm->outPopHeaders(pSpecies, -999); // close Population file
+ }
+ if (sim.outTraitsCells)
+ pComm->outTraitsHeaders(pSpecies, -999); // close Traits file
+ if (sim.outTraitsRows)
+ pComm->outTraitsRowsHeaders(pSpecies, -999); // close Traits rows file
+ // close Individuals & Genetics output files if open
+ // they can still be open if the simulation was stopped by the user
+ if (sim.outInds) pComm->outInds(0, 0, 0, -999);
+ if (sim.outGenetics) pComm->outGenetics(0, 0, 0, -999);
+
+ MemoLine("Deleting community...");
+ delete pComm; pComm = 0;
+ MemoLine("...finished");
+
+#if RS_RCPP && !R_CMD
+ return list_outPop;
+#else
+ return 0;
+#endif
+
+}
+
+#if RS_EMBARCADERO || LINUX_CLUSTER || RS_RCPP
+// Check whether a specified directory path exists
+bool is_directory(const char* pathname) {
+ struct stat info;
+ if (stat(pathname, &info) != 0) return false; // path does not exist
+ if (S_ISDIR(info.st_mode)) return true;
+ return false;
+}
+#endif
+
+//---------------------------------------------------------------------------
+bool CheckDirectory(void)
+{
+ bool errorfolder = false;
+
+ string subfolder;
+
+ subfolder = paramsSim->getDir(0) + "Inputs";
+ const char* inputs = subfolder.c_str();
+ if (!is_directory(inputs)) errorfolder = true;
+ subfolder = paramsSim->getDir(0) + "Outputs";
+ const char* outputs = subfolder.c_str();
+ if (!is_directory(outputs)) errorfolder = true;
+ subfolder = paramsSim->getDir(0) + "Output_Maps";
+ const char* outputmaps = subfolder.c_str();
+ if (!is_directory(outputmaps)) errorfolder = true;
+
+ return errorfolder;
+}
+
+//---------------------------------------------------------------------------
+//For outputs and population visualisations pre-reproduction
+void PreReproductionOutput(Landscape* pLand, Community* pComm, int rep, int yr, int gen)
+{
+#if RSDEBUG
+ landParams ppLand = pLand->getLandParams();
+#endif
+ simParams sim = paramsSim->getSim();
+ simView v = paramsSim->getViews();
+
+#if RSDEBUG
+ DEBUGLOG << "PreReproductionOutput(): 11111 rep=" << rep << " yr=" << yr << " gen=" << gen
+ << " landNum=" << ppLand.landNum << " maxX=" << ppLand.maxX << " maxY=" << ppLand.maxY
+ << endl;
+ DEBUGLOG << "PreReproductionOutput(): 11112 outRange=" << sim.outRange
+ << " outIntRange=" << sim.outIntRange
+ << " outPop=" << sim.outPop << " outIntPop=" << sim.outIntPop
+ << endl;
+#endif
+
+ traitCanvas tcanv;
+ for (int i = 0; i < NTRAITS; i++) {
+ tcanv.pcanvas[i] = 0;
+ }
+
+ // trait outputs and visualisation
+
+ if (v.viewTraits) {
+ tcanv = SetupTraitCanvas();
+ }
+
+ if (v.viewTraits
+ || ((sim.outTraitsCells && yr >= sim.outStartTraitCell && yr % sim.outIntTraitCell == 0) ||
+ (sim.outTraitsRows && yr >= sim.outStartTraitRow && yr % sim.outIntTraitRow == 0)))
+ {
+ pComm->outTraits(tcanv, pSpecies, rep, yr, gen);
+ }
+ if (sim.outOccup && yr % sim.outIntOcc == 0 && gen == 0)
+ pComm->updateOccupancy(yr / sim.outIntOcc, rep);
+}
+
+//For outputs and population visualisations pre-reproduction
+void RangePopOutput(Community* pComm, int rep, int yr, int gen)
+{
+ simParams sim = paramsSim->getSim();
+
+ if (sim.outRange && (yr % sim.outIntRange == 0 || pComm->totalInds() <= 0))
+ pComm->outRange(pSpecies, rep, yr, gen);
+
+ if (sim.outPop && yr >= sim.outStartPop && yr % sim.outIntPop == 0)
+ pComm->outPop(rep, yr, gen);
+
+}
+
+//---------------------------------------------------------------------------
+void OutParameters(Landscape* pLandscape)
+{
+ double k;
+ //int nrows,ncols,nsexes,nstages;
+ int nsexes, nstages;
+
+ landParams ppLand = pLandscape->getLandParams();
+ genLandParams ppGenLand = pLandscape->getGenLandParams();
+ envGradParams grad = paramsGrad->getGradient();
+ envStochParams env = paramsStoch->getStoch();
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ settleRules srules;
+ settleSteps ssteps;
+ settleTraits settleDD;
+ simParams sim = paramsSim->getSim();
+
+ string name;
+ if (sim.batchMode)
+ name = paramsSim->getDir(2)
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation)
+ + "_Land" + Int2Str(ppLand.landNum) + "_Parameters.txt";
+ else
+ name = paramsSim->getDir(2) + "Sim" + Int2Str(sim.simulation) + "_Parameters.txt";
+ outPar.open(name.c_str());
+
+ outPar << "RangeShifter 2.0 ";
+
+#if !RS_RCPP
+#if RSWIN64
+ outPar << " - 64 bit implementation";
+#else
+ outPar << " - 32 bit implementation";
+#endif
+#endif
+ outPar << endl;
+
+ outPar << "================ ";
+
+ outPar << " =====================";
+ outPar << endl << endl;
+
+ outPar << "BATCH MODE \t";
+ if (sim.batchMode) outPar << "yes" << endl; else outPar << "no" << endl;
+#if RS_RCPP
+ outPar << "SEED \t" << RS_random_seed << endl;
+#endif
+ outPar << "REPLICATES \t" << sim.reps << endl;
+ outPar << "YEARS \t" << sim.years << endl;
+ outPar << "REPRODUCTIVE SEASONS / YEAR\t" << dem.repSeasons << endl;
+ if (ppLand.patchModel) {
+ outPar << "PATCH-BASED MODEL" << endl;
+ outPar << "No. PATCHES \t" << pLandscape->patchCount() - 1 << endl;
+ }
+ else
+ outPar << "CELL-BASED MODEL" << endl;
+ outPar << "BOUNDARIES \t";
+ if (sim.absorbing) outPar << "absorbing" << endl;
+ else outPar << "reflective" << endl;
+ outPar << endl;
+
+ outPar << "LANDSCAPE:\t";
+ if (ppLand.generated) {
+ outPar << "artificially generated map" << endl;
+ outPar << "TYPE: \t";
+ if (ppGenLand.continuous) outPar << "continuous \t";
+ else outPar << "discrete \t";
+ if (ppGenLand.fractal) outPar << "fractal";
+ else outPar << "random";
+ outPar << endl << "PROPORTION OF SUITABLE HABITAT (p)\t" << ppGenLand.propSuit << endl;
+ if (ppGenLand.fractal) outPar << "HURST EXPONENT\t" << ppGenLand.hurst << endl;
+ }
+ else {
+ outPar << "imported map" << endl;
+ outPar << "TYPE: \t";
+ switch (ppLand.rasterType) {
+ case 0:
+ outPar << "habitat codes" << endl;
+ break;
+ case 1:
+ outPar << "habitat % cover" << endl;
+ break;
+ case 2:
+ outPar << "habitat quality" << endl;
+ break;
+ }
+ outPar << "FILE NAME: ";
+#if RS_RCPP
+ if (ppLand.dynamic) {
+ outPar << name_landscape << endl;
+ }
+ else {
+ outPar << name_landscape << endl;
+ }
+ if (ppLand.patchModel) {
+ outPar << "PATCH FILE: " << name_patch << endl;
+ }
+ if (trfr.costMap) {
+ outPar << "COSTS FILE: " << name_costfile << endl;
+ }
+#else
+ if (sim.batchMode) outPar << " (see batch file) " << landFile << endl;
+ else {
+ outPar << habmapname << endl;
+ if (ppLand.rasterType == 1) { // habitat % cover - list additional layers
+ for (int i = 0; i < ppLand.nHab - 1; i++) {
+ outPar << " " << hfnames[i] << endl;
+ }
+ }
+ if (ppLand.patchModel) {
+ outPar << "PATCH FILE: " << patchmapname << endl;
+ }
+ }
+#endif
+ outPar << "No. HABITATS:\t" << ppLand.nHab << endl;
+ }
+ outPar << "RESOLUTION (m): \t" << ppLand.resol << endl;
+ outPar << "DIMENSIONS: X " << ppLand.dimX << " Y " << ppLand.dimY << endl;
+ outPar << "AVAILABLE: min.X " << ppLand.minX << " min.Y " << ppLand.minY
+ << " max.X " << ppLand.maxX << " max.Y " << ppLand.maxY << endl;
+ if (!ppLand.generated && ppLand.dynamic) {
+ landChange chg;
+ outPar << "DYNAMIC LANDSCAPE: " << endl;
+ int nchanges = pLandscape->numLandChanges();
+ for (int i = 0; i < nchanges; i++) {
+ chg = pLandscape->getLandChange(i);
+ outPar << "Change no. " << chg.chgnum << " in year " << chg.chgyear << endl;
+ outPar << "Landscape: " << chg.habfile << endl;
+ if (ppLand.patchModel) {
+ outPar << "Patches : " << chg.pchfile << endl;
+ }
+ if (chg.costfile != "none" && chg.costfile != "NULL") {
+ outPar << "Costs : " << chg.costfile << endl;
+ }
+ }
+ }
+
+ outPar << endl << "SPECIES DISTRIBUTION LOADED: \t";
+ if (ppLand.spDist)
+ {
+ outPar << "yes" << endl;
+ outPar << "RESOLUTION (m)\t" << ppLand.spResol << endl;
+ outPar << "FILE NAME: ";
+#if !RS_RCPP
+ if (sim.batchMode) outPar << " (see batch file) " << landFile << endl;
+ else {
+ outPar << distnmapname << endl;
+ }
+#else
+ outPar << name_sp_dist << endl;
+#endif
+ }
+ else outPar << "no" << endl;
+
+ outPar << endl << "ENVIRONMENTAL GRADIENT:\t ";
+ if (grad.gradient)
+ {
+ switch (grad.gradType) {
+ case 1:
+ if (dem.stageStruct) outPar << "Density dependence strength (1/b)" << endl;
+ else outPar << "Carrying capacity (K)" << endl;
+ break;
+ case 2:
+ if (dem.stageStruct) outPar << "Fecundity" << endl;
+ else outPar << "Intrinsic growth rate (r)" << endl;
+ break;
+ case 3:
+ outPar << "Local extinction probability" << endl;
+ break;
+ default:
+ outPar << "ERROR ERROR ERROR" << endl;
+ ;
+ }
+ outPar << "G:\t\t " << grad.grad_inc << endl;
+ outPar << "optimum Y:\t " << grad.opt_y << endl;
+ outPar << "f:\t\t " << grad.factor << endl;
+ if (grad.gradType == 3) outPar << "Local extinction prob. at optimum:\t "
+ << grad.extProbOpt << endl;
+ outPar << "GRADIENT SHIFTING:\t ";
+ if (grad.shifting)
+ {
+ outPar << "yes" << endl;
+ outPar << "SHIFTING RATE (rows/year):\t " << grad.shift_rate << endl;
+ outPar << "SHIFTING START (year):\t\t " << grad.shift_begin << endl;
+ outPar << "SHIFTING STOP (year):\t\t " << grad.shift_stop << endl;
+ }
+ else outPar << "no" << endl;
+ }
+ else outPar << "no";
+ outPar << endl;
+ outPar << "ENVIRONMENTAL STOCHASTICITY:\t";
+ if (env.stoch) {
+ outPar << "yes" << endl;
+ outPar << "TYPE\t in ";
+ if (dem.stageStruct) {
+ if (env.inK) outPar << "1/b" << endl;
+ else outPar << "fecundity" << endl;
+ }
+ else {
+ if (env.inK) outPar << "K" << endl;
+ else outPar << "R" << endl;
+ }
+ outPar << "SPATIAL AUTOCORRELATION\t ";
+ if (env.local) outPar << "local" << endl;
+ else outPar << "global" << endl;
+ outPar << "TEMPORAL AUTOCORRELATION (ac)\t" << env.ac << endl;
+ outPar << "AMPLITUDE (std)\t" << env.std << endl;
+ if (dem.stageStruct) {
+ if (env.inK) {
+ outPar << "MIN. 1/b\t" << pSpecies->getMinMax(0)
+ * (10000.0 / (float)(ppLand.resol * ppLand.resol)) << endl;
+ outPar << "MAX. 1/b\t" << pSpecies->getMinMax(1)
+ * (10000.0 / (float)(ppLand.resol * ppLand.resol)) << endl;
+ }
+ else {
+ outPar << "MIN. fecundity\t" << pSpecies->getMinMax(0) << endl;
+ outPar << "MAX. fecundity\t" << pSpecies->getMinMax(1) << endl;
+ }
+ }
+ else {
+ if (env.inK) {
+ outPar << "MIN. K\t" << pSpecies->getMinMax(0)
+ * (10000.0 / (float)(ppLand.resol * ppLand.resol)) << endl;
+ outPar << "MAX. K\t" << pSpecies->getMinMax(1)
+ * (10000.0 / (float)(ppLand.resol * ppLand.resol)) << endl;
+ }
+ else {
+ outPar << "MIN. r\t" << pSpecies->getMinMax(0) << endl;
+ outPar << "MAX. r\t" << pSpecies->getMinMax(1) << endl;
+ }
+ }
+ }
+ else outPar << "no" << endl;
+ outPar << "LOCAL EXTINCTION PROBABILITY:\t";
+ if (env.localExt) outPar << env.locExtProb << endl;
+ else outPar << "0.0" << endl;
+
+ outPar << endl << "SPECIES' PARAMETERS." << endl;
+ outPar << "REPRODUCTION:" << endl;
+ outPar << "TYPE: ";
+ switch (dem.repType) {
+ case 0:
+ outPar << "Asexual / Only female model" << endl;
+ break;
+ case 1:
+ outPar << "Sexual model (simple)";
+ outPar << endl;
+ outPar << "PROP. of MALES\t" << dem.propMales << endl;
+ break;
+ case 2:
+ outPar << "Sexual model (explicit mating system)" << endl;
+ outPar << "PROP. of MALES\t" << dem.propMales << endl;
+ outPar << "MAX. HAREM SIZE (h)\t" << dem.harem << endl;
+ break;
+ }
+ outPar << "STAGE STRUCTURE:\t";
+ if (dem.stageStruct) {
+ outPar << "yes" << endl;
+ outPar << "PROBABILITY OF REPRODUCING IN SUBSEQUENT SEASONS\t" << sstruct.probRep << endl;
+ outPar << "No. OF REP. SEASONS BEFORE SUBSEQUENT REPRODUCTIONS\t" << sstruct.repInterval << endl;
+ if (!ppLand.generated && ppLand.dynamic) {
+ outPar << "ACTION AFTER POPULATION DESTRUCTION: all individuals ";
+ if (sstruct.disperseOnLoss) outPar << "disperse" << endl;
+ else outPar << "die" << endl;
+ }
+ outPar << "No. STAGES\t" << sstruct.nStages << endl;
+ outPar << "MAX. AGE\t" << sstruct.maxAge << endl;
+ // no sex-specific demographic parameters
+ if (dem.repType != 2) {
+ outPar << "MIN. AGES:" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "stage\t" << i << ":\t" << pSpecies->getMinAge(i, 0) << "\tyears" << endl;
+ }
+ outPar << "FECUNDITIES:" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "stage\t" << i << ":\t" << pSpecies->getFec(i, 0) << endl;
+ }
+ outPar << "DEVELOPMENT PROB.:" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "stage\t" << i << ":\t" << pSpecies->getDev(i, 0) << endl;
+ }
+ outPar << "SURVIVAL PROB.:" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "stage\t" << i << ":\t" << pSpecies->getSurv(i, 0) << endl;
+ }
+ }
+ // sex-specific demographic parameters
+ else {
+ outPar << "MIN. AGES:" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "males " << i << ":\t" << pSpecies->getMinAge(i, 1) << " years;\t";
+ outPar << "females " << i << ":\t" << pSpecies->getMinAge(i, 0) << " years" << endl;
+ }
+ outPar << "FECUNDITIES:" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "males " << i << ":\t" << pSpecies->getFec(i, 1) << endl;
+ outPar << "females " << i << ":\t" << pSpecies->getFec(i, 0) << endl;
+ }
+ outPar << "DEVELOPMENT PROB.:" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "males " << i << ":\t" << pSpecies->getDev(i, 1) << endl;
+ outPar << "females " << i << ":\t" << pSpecies->getDev(i, 0) << endl;
+ }
+ outPar << "SURVIVAL PROB.:" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "males " << i << ":\t" << pSpecies->getSurv(i, 1) << endl;
+ outPar << "females " << i << ":\t" << pSpecies->getSurv(i, 0) << endl;
+ }
+ }
+
+ outPar << "SCHEDULING OF SURVIVAL: ";
+ switch (sstruct.survival) {
+ case 0:
+ outPar << "At reproduction" << endl;
+ break;
+ case 1:
+ outPar << "Between reproductive events" << endl;
+ break;
+ case 2:
+ outPar << "Annually" << endl;
+ break;
+ }
+
+ int mSize; // index for weights matrices
+ if (dem.repType == 2) mSize = sstruct.nStages * NSEXES;
+ else mSize = sstruct.nStages;
+
+ outPar << "DENSITY-DEPENDENCE IN FECUNDITY:\t";
+ if (sstruct.fecDens) {
+ outPar << "yes" << endl;
+ if (sstruct.fecStageDens) {
+ outPar << "STAGE'S WEIGHTS:" << endl;
+ for (int i = 0; i < mSize; i++) {
+ if (dem.repType == 2) {
+ outPar << "stage " << i / NSEXES << " ";
+ if (i % NSEXES == 0) outPar << "males : \t";
+ else outPar << "females: \t";
+ }
+ else outPar << "stage " << i << ": \t";
+ for (int j = 0; j < mSize; j++) outPar << pSpecies->getDDwtFec(j, i) << "\t";
+ outPar << endl;
+ }
+ }
+ else outPar << "not stage-dependent" << endl;
+ }
+ else outPar << "no" << endl;
+
+ densDepParams ddparams = pSpecies->getDensDep();
+
+ outPar << "DENSITY-DEPENDENCE IN DEVELOPMENT:\t";
+ if (sstruct.devDens) {
+ outPar << "yes - coefficient: " << ddparams.devCoeff << endl;
+ if (sstruct.devStageDens) {
+ outPar << "STAGE'S WEIGHTS:" << endl;
+ for (int i = 0; i < mSize; i++) {
+ if (dem.repType == 2) {
+ outPar << "stage " << i / NSEXES << " ";
+ if (i % NSEXES == 0) outPar << "males : \t";
+ else outPar << "females: \t";
+ }
+ else outPar << "stage " << i << ": \t";
+ for (int j = 0; j < mSize; j++) outPar << pSpecies->getDDwtDev(j, i) << "\t";
+ outPar << endl;
+ }
+ }
+ else outPar << "not stage-dependent" << endl;
+ }
+ else outPar << "no" << endl;
+
+ outPar << "DENSITY-DEPENDENCE IN SURVIVAL:\t\t";
+ if (sstruct.survDens) {
+ outPar << "yes - coefficient: " << ddparams.survCoeff << endl;
+ if (sstruct.survStageDens) {
+ outPar << "STAGE'S WEIGHTS:" << endl;
+ for (int i = 0; i < mSize; i++) {
+ if (dem.repType == 2) {
+ outPar << "stage " << i / NSEXES << " ";
+ if (i % NSEXES == 0) outPar << "males : \t";
+ else outPar << "females: \t";
+ }
+ else outPar << "stage " << i << ": \t";
+ for (int j = 0; j < mSize; j++) outPar << pSpecies->getDDwtSurv(j, i) << "\t";
+ outPar << endl;
+ }
+ }
+ else outPar << "not stage-dependent" << endl;
+ }
+ else outPar << "no" << endl;
+ } // end of if (dem.stageStruct)
+ else { // not stage-strutured
+ outPar << "no" << endl;
+ outPar << "Rmax\t" << dem.lambda << endl;
+ outPar << "bc\t" << dem.bc << endl;
+ }
+
+ if (dem.stageStruct) {
+ outPar << endl << "HABITAT SPECIFIC 1/b:" << endl;
+ }
+ else {
+ outPar << endl << "CARRYING CAPACITIES:" << endl;
+ }
+ int nhab = ppLand.nHab;
+ if (ppLand.generated) {
+ if (ppGenLand.continuous) nhab = 1;
+ }
+ for (int i = 0; i < nhab; i++) {
+ k = pSpecies->getHabK(i) * (10000.0 / (float)(ppLand.resol * ppLand.resol));
+ if (!ppLand.generated && ppLand.rasterType == 0) { // imported & habitat codes
+ outPar << "Habitat " << pLandscape->getHabCode(i) << ": \t";
+ }
+ else {
+ outPar << "Habitat " << i << ": ";
+ }
+ if (dem.stageStruct) outPar << "1/b ";
+ else outPar << "K ";
+ outPar << k << endl;
+ }
+
+ emigTraits ep0, ep1;
+ emigParams eparams0, eparams1;
+ string sexdept = "SEX-DEPENDENT: ";
+ string stgdept = "STAGE-DEPENDENT: ";
+ string indvar = "INDIVIDUAL VARIABILITY: ";
+ string emigstage = "EMIGRATION STAGE: ";
+
+ outPar << endl << "DISPERSAL - EMIGRATION:\t";
+ if (emig.densDep) {
+ outPar << "density-dependent" << endl;
+
+ if (emig.sexDep) {
+ outPar << sexdept << "yes" << endl;
+ if (emig.stgDep) {
+ outPar << stgdept << "yes" << endl;
+ outPar << indvar << "no" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "stage " << i << ":" << endl;
+ ep0 = pSpecies->getEmigTraits(i, 0);
+ ep1 = pSpecies->getEmigTraits(i, 1);
+ outPar << "D0: females " << ep0.d0 << " males " << ep1.d0 << endl;
+ outPar << "alpha: females " << ep0.alpha << " males " << ep1.alpha << endl;
+ outPar << "beta: females " << ep0.beta << " males " << ep1.beta << endl;
+ }
+ }
+ else { // !emig.stgDep
+ outPar << stgdept << "no" << endl;
+ outPar << indvar;
+ if (emig.indVar) {
+ eparams0 = pSpecies->getEmigParams(0, 0);
+ eparams1 = pSpecies->getEmigParams(0, 1);
+ outPar << "yes" << endl;
+ if (dem.stageStruct) {
+ outPar << emigstage << emig.emigStage << endl;
+ }
+ outPar << "D0 females: mean " << eparams0.d0Mean << " s.d. " << eparams0.d0SD
+ << " scaling factor " << eparams0.d0Scale << endl;
+ outPar << "D0 males: mean " << eparams1.d0Mean << " s.d. " << eparams1.d0SD
+ << " scaling factor " << eparams1.d0Scale << endl;
+ outPar << "Alpha females: mean " << eparams0.alphaMean << " s.d. " << eparams0.alphaSD
+ << " scaling factor " << eparams0.alphaScale << endl;
+ outPar << "Alpha males: mean " << eparams1.alphaMean << " s.d. " << eparams1.alphaSD
+ << " scaling factor " << eparams1.alphaScale << endl;
+ outPar << "Beta females: mean " << eparams0.betaMean << " s.d. " << eparams0.betaSD
+ << " scaling factor " << eparams0.betaScale << endl;
+ outPar << "Beta males: mean " << eparams1.betaMean << " s.d. " << eparams1.betaSD
+ << " scaling factor " << eparams1.betaScale << endl;
+ }
+ else {
+ outPar << "no" << endl;
+ ep0 = pSpecies->getEmigTraits(0, 0);
+ ep1 = pSpecies->getEmigTraits(0, 1);
+ outPar << "D0: females " << ep0.d0 << " males " << ep1.d0 << endl;
+ outPar << "alpha: females " << ep0.alpha << " males " << ep1.alpha << endl;
+ outPar << "beta: females " << ep0.beta << " males " << ep1.beta << endl;
+ }
+ }
+ }
+ else { // !emig.sexDep
+ outPar << sexdept << "no" << endl;
+ if (emig.stgDep) {
+ outPar << stgdept << "yes" << endl;
+ outPar << indvar << "no" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ ep0 = pSpecies->getEmigTraits(i, 0);
+ outPar << "stage " << i << ": \t" << "D0: " << ep0.d0;
+ outPar << " \talpha: " << ep0.alpha << " \tbeta: " << ep0.beta << endl;
+ }
+ }
+ else { // !emig.stgDep
+ outPar << stgdept << "no" << endl;
+ outPar << indvar;
+ if (emig.indVar) {
+ eparams0 = pSpecies->getEmigParams(0, 0);
+ emigScales scale = pSpecies->getEmigScales();
+ outPar << "yes" << endl;
+ if (dem.stageStruct) {
+ outPar << emigstage << emig.emigStage << endl;
+ }
+ outPar << "D0 mean: " << eparams0.d0Mean << " s.d.: " << eparams0.d0SD
+ << " scaling factor: " << scale.d0Scale << endl;
+ outPar << "Alpha mean: " << eparams0.alphaMean << " s.d.: " << eparams0.alphaSD
+ << " scaling factor: " << scale.alphaScale << endl;
+ outPar << "Beta mean: " << eparams0.betaMean << " s.d.: " << eparams0.betaSD
+ << " scaling factor: " << scale.betaScale << endl;
+ }
+ else {
+ outPar << "no" << endl;
+ ep0 = pSpecies->getEmigTraits(0, 0);
+ outPar << "D0: " << ep0.d0 << endl;
+ outPar << "alpha: " << ep0.alpha << endl;
+ outPar << "beta: " << ep0.beta << endl;
+ }
+ }
+ }
+ }
+ else { // not density-dependent
+ string initprob = "INITIAL EMIGRATION PROB. ";
+ outPar << "density-independent" << endl;
+ if (!trfr.moveModel) { // transfer by kernel
+ outPar << "USE FULL KERNEL TO DETERMINE EMIGRATION: ";
+ if (pSpecies->useFullKernel()) outPar << "yes";
+ else outPar << "no";
+ outPar << endl;
+ }
+
+ if (emig.sexDep) {
+ outPar << sexdept << "yes" << endl;
+ if (emig.stgDep) {
+ outPar << stgdept << "yes" << endl;
+ outPar << indvar << "no" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "stage " << i << ": \t" << "EMIGRATION PROB.: \tfemales "
+ << pSpecies->getEmigD0(i, 0) << " \tmales " << pSpecies->getEmigD0(i, 1) << endl;
+ }
+ }
+ else { // !emig.stgDep
+ outPar << stgdept << "no" << endl;
+ outPar << indvar;
+ if (emig.indVar) {
+ eparams0 = pSpecies->getEmigParams(0, 0);
+ eparams1 = pSpecies->getEmigParams(0, 1);
+ emigScales scale = pSpecies->getEmigScales();
+ outPar << "yes" << endl;
+ if (dem.stageStruct) {
+ outPar << emigstage << emig.emigStage << endl;
+ }
+ outPar << initprob << "mean: " << "females " << eparams0.d0Mean
+ << " males " << eparams1.d0Mean << endl;
+ outPar << initprob << "s.d.: " << "females " << eparams0.d0SD
+ << " males " << eparams1.d0SD << endl;
+ outPar << initprob << "scaling factor: " << scale.d0Scale
+ << endl;
+ }
+ else {
+ outPar << "no" << endl;
+ outPar << "EMIGRATION PROB.: \tfemales " << pSpecies->getEmigD0(0, 0)
+ << "\t males " << pSpecies->getEmigD0(0, 1) << endl;
+ }
+ }
+ }
+ else { // !emig.sexDep
+ outPar << sexdept << "no" << endl;
+ if (emig.stgDep) {
+ outPar << stgdept << "yes" << endl;
+ outPar << indvar << "no" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "stage " << i << ": \t" << "EMIGRATION PROB.: "
+ << pSpecies->getEmigD0(i, 0) << endl;
+ }
+ }
+ else { // !emig.stgDep
+ outPar << stgdept << "no" << endl;
+ outPar << indvar;
+ if (emig.indVar) {
+ eparams0 = pSpecies->getEmigParams(0, 0);
+ emigScales scale = pSpecies->getEmigScales();
+ outPar << "yes" << endl;
+ if (dem.stageStruct) {
+ outPar << emigstage << emig.emigStage << endl;
+ }
+ outPar << initprob << "mean: " << eparams0.d0Mean << endl;
+ outPar << initprob << "s.d.: " << eparams0.d0SD << endl;
+ outPar << initprob << "scaling factor: " << scale.d0Scale << endl;
+ }
+ else {
+ outPar << "no" << endl;
+ outPar << "EMIGRATION PROB.:\t" << pSpecies->getEmigD0(0, 0) << endl;
+ }
+ }
+ }
+ }
+
+ // Transfer
+
+ outPar << endl << "DISPERSAL - TRANSFER: \t";
+
+ if (trfr.moveModel) {
+ bool straigtenPath;
+ if (trfr.moveType == 1) { // SMS
+ trfrSMSTraits move = pSpecies->getSMSTraits();
+ straigtenPath = move.straigtenPath;
+ if (trfr.costMap) {
+ outPar << "SMS\tcosts from imported cost map" << endl;
+#if !RS_RCPP
+ outPar << "FILE NAME: " << costmapname << endl;
+#endif
+ }
+ else {
+ outPar << "SMS\tcosts:" << endl;
+ if (!ppLand.generated && ppLand.rasterType == 0) {
+ for (int i = 0; i < ppLand.nHab; i++)
+ outPar << "\thab. " << pLandscape->getHabCode(i) << "\t"
+ << pSpecies->getHabCost(i) << endl;
+ }
+ else {
+ for (int i = 0; i < ppLand.nHab; i++)
+ outPar << "\thab. " << i << "\t"
+ << pSpecies->getHabCost(i) << endl;
+ }
+ }
+ string pr = "PERCEPTUAL RANGE";
+ outPar << pr << ": " << move.pr << endl;
+ outPar << pr << " METHOD: " << move.prMethod << endl;
+ if (!trfr.indVar) outPar << "DIRECTIONAL PERSISTENCE: " << move.dp << endl;
+ outPar << "MEMORY SIZE: " << move.memSize << endl;
+ outPar << "GOAL TYPE: " << move.goalType << endl;
+ if (!trfr.indVar) {
+ if (move.goalType == 2) { // dispersal bias
+ outPar << "GOAL BIAS: " << move.gb << endl;
+ outPar << "ALPHA DB: " << move.alphaDB << endl;
+ outPar << "BETA DB: " << move.betaDB << endl;
+ }
+ }
+ if (trfr.indVar) {
+ trfrSMSParams s = pSpecies->getSMSParams(0, 0);
+ outPar << indvar << "yes " << endl;
+ outPar << "DP mean: " << s.dpMean << " s.d.: " << s.dpSD
+ << " scaling factor: " << s.dpScale << endl;
+ outPar << "GB mean: " << s.gbMean << " s.d.: " << s.gbSD
+ << " scaling factor: " << s.gbScale << endl;
+ if (move.goalType == 2) { // dispersal bias
+ outPar << "Alpha DB mean: " << s.alphaDBMean << " s.d.: " << s.alphaDBSD
+ << " scaling factor: " << s.alphaDBScale << endl;
+ outPar << "Beta DB mean: " << s.betaDBMean << " s.d.: " << s.betaDBSD
+ << " scaling factor: " << s.betaDBScale << endl;
+ }
+ }
+ else {
+ outPar << indvar << "no " << endl;
+ }
+ }
+ else { // CRW
+ trfrCRWTraits move = pSpecies->getCRWTraits();
+ straigtenPath = move.straigtenPath;
+ outPar << "CRW" << endl;
+ string lgth = "STEP LENGTH (m) ";
+ string corr = "STEP CORRELATION";
+ if (trfr.indVar) {
+ trfrCRWParams m = pSpecies->getCRWParams(0, 0);
+ outPar << indvar << "yes" << endl;
+ outPar << lgth << " mean: " << m.stepLgthMean;
+ outPar << " s.d.: " << m.stepLgthSD;
+ outPar << " scaling factor: " << m.stepLScale << endl;
+ outPar << corr << " mean: " << m.rhoMean;
+ outPar << " s.d.: " << m.rhoSD;
+ outPar << " scaling factor: " << m.rhoScale << endl;
+ }
+ else {
+ outPar << indvar << "no" << endl;
+ outPar << lgth << ": " << move.stepLength << endl;
+ outPar << corr << ": " << move.rho << endl;
+ }
+ }
+ outPar << "STRAIGHTEN PATH AFTER DECISION NOT TO SETTLE: ";
+ if (straigtenPath) outPar << "yes" << endl;
+ else outPar << "no" << endl;
+ outPar << "STEP MORTALITY:\t" << endl;
+ if (trfr.habMort)
+ {
+ outPar << "habitat dependent:\t" << endl;
+ if (!ppLand.generated && ppLand.rasterType == 0) {
+ for (int i = 0; i < ppLand.nHab; i++)
+ outPar << "\thab. " << pLandscape->getHabCode(i) << "\t"
+ << pSpecies->getHabMort(i) << endl;
+ }
+ else {
+ for (int i = 0; i < ppLand.nHab; i++)
+ outPar << "\thab. " << i << "\t"
+ << pSpecies->getHabMort(i) << endl;
+ }
+ }
+ else
+ {
+ trfrCRWTraits move = pSpecies->getCRWTraits();
+ outPar << "constant " << move.stepMort << endl;
+ }
+ } // end of movement process
+ else { // kernel
+ string meandist = "MEAN DISTANCE";
+ string probkern = "PROB. KERNEL I";
+ trfrKernTraits kern0, kern1;
+ trfrKernParams k0, k1;
+ outPar << "dispersal kernel" << endl << "TYPE: \t";
+ if (trfr.twinKern) outPar << "double ";
+ outPar << "negative exponential" << endl;
+
+ if (trfr.sexDep) {
+ outPar << sexdept << "yes" << endl;
+ if (trfr.stgDep) {
+ outPar << stgdept << "yes" << endl;
+ outPar << indvar << "no" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ outPar << "stage " << i << ":" << endl;
+ kern0 = pSpecies->getKernTraits(i, 0);
+ kern1 = pSpecies->getKernTraits(i, 1);
+ outPar << meandist << " I: \tfemales " << kern0.meanDist1 << " \tmales " << kern1.meanDist1 << endl;
+ if (trfr.twinKern)
+ {
+ outPar << meandist << " II: \tfemales " << kern0.meanDist2 << " \tmales " << kern1.meanDist2 << endl;
+ outPar << probkern << ": \tfemales " << kern0.probKern1 << " \tmales " << kern1.probKern1 << endl;
+ }
+ }
+ }
+ else { // !trfr.stgDep
+ outPar << stgdept << "no" << endl;
+ outPar << indvar;
+ if (trfr.indVar) {
+ k0 = pSpecies->getKernParams(0, 0);
+ k1 = pSpecies->getKernParams(0, 1);
+ outPar << "yes" << endl;
+ outPar << meandist << " I (mean): \tfemales " << k0.dist1Mean
+ << " \tmales " << k1.dist1Mean << endl;
+ outPar << meandist << " I (s.d.): \tfemales " << k0.dist1SD
+ << " \tmales " << k1.dist1SD << endl;
+ outPar << meandist << " I (scaling factor): \tfemales " << k0.dist1Scale
+ << " \tmales " << k1.dist1Scale << endl;
+ if (trfr.twinKern)
+ {
+ outPar << meandist << " II (mean): \tfemales " << k0.dist2Mean
+ << " \tmales " << k1.dist2Mean << endl;
+ outPar << meandist << " II (s.d.): \tfemales " << k0.dist2SD
+ << " \tmales " << k1.dist2SD << endl;
+ outPar << meandist << " II (scaling factor): \tfemales " << k0.dist2Scale
+ << " \tmales " << k1.dist2Scale << endl;
+ outPar << probkern << " (mean): \tfemales " << k0.PKern1Mean
+ << " \tmales " << k1.PKern1Mean << endl;
+ outPar << probkern << " (s.d.): \tfemales " << k0.PKern1SD
+ << " \tmales " << k1.PKern1SD << endl;
+ outPar << probkern << " (scaling factor): \tfemales " << k0.PKern1Scale
+ << " \tmales " << k1.PKern1Scale << endl;
+ }
+ }
+ else {
+ outPar << "no" << endl;
+ kern0 = pSpecies->getKernTraits(0, 0);
+ kern1 = pSpecies->getKernTraits(0, 1);
+ outPar << meandist << " I: \tfemales " << kern0.meanDist1 << " \tmales " << kern1.meanDist1 << endl;
+ if (trfr.twinKern)
+ {
+ outPar << meandist << " II: \tfemales " << kern0.meanDist2 << " \tmales " << kern1.meanDist2 << endl;
+ outPar << probkern << ": \tfemales " << kern0.probKern1 << " \tmales " << kern1.probKern1 << endl;
+ }
+ }
+ }
+ }
+ else { // !trfr.sexDep
+ outPar << sexdept << "no" << endl;
+ if (trfr.stgDep) {
+ outPar << stgdept << "yes" << endl;
+ outPar << indvar << "no" << endl;
+ for (int i = 0; i < sstruct.nStages; i++) {
+ kern0 = pSpecies->getKernTraits(i, 0);
+ outPar << "stage " << i << ": \t" << meandist << " I: " << kern0.meanDist1;
+ if (trfr.twinKern)
+ {
+ outPar << " \t" << meandist << " II: " << kern0.meanDist2;
+ outPar << " \t" << probkern << ": " << kern0.probKern1;
+ }
+ outPar << endl;
+ }
+ }
+ else { // !trfr.stgDep
+ outPar << stgdept << "no" << endl;
+ outPar << indvar;
+ if (trfr.indVar) {
+ k0 = pSpecies->getKernParams(0, 0);
+ outPar << "yes" << endl;
+ outPar << meandist << " I (mean): " << k0.dist1Mean
+ << " \t(s.d.): " << k0.dist1SD
+ << " \t(scaling factor): " << k0.dist1Scale << endl;
+ if (trfr.twinKern)
+ {
+ outPar << meandist << " II (mean): " << k0.dist2Mean
+ << " \t(s.d.): " << k0.dist2SD
+ << " \t(scaling factor): " << k0.dist2Scale << endl;
+ outPar << probkern << " (mean): " << k0.PKern1Mean
+ << " \t(s.d.): " << k0.PKern1SD
+ << " \t(scaling factor): " << k0.PKern1Scale << endl;
+ }
+ }
+ else {
+ outPar << "no" << endl;
+ kern0 = pSpecies->getKernTraits(0, 0);
+ outPar << meandist << " I: \t" << kern0.meanDist1 << endl;
+ if (trfr.twinKern)
+ {
+ outPar << meandist << " II: \t" << kern0.meanDist2 << endl;
+ outPar << probkern << ": \t" << kern0.probKern1 << endl;
+ }
+ }
+ }
+ }
+
+ outPar << "DISPERSAL MORTALITY: ";
+ trfrMortParams mort = pSpecies->getMortParams();
+ if (trfr.distMort) {
+ outPar << "distance-dependent" << endl;
+ outPar << "SLOPE: " << mort.mortAlpha << " \tINFLECTION POINT: " << mort.mortBeta << endl;
+ }
+ else {
+ outPar << "constant" << endl << "MORTALITY PROBABILITY: " << mort.fixedMort << endl;
+ }
+ } // end of kernel transfer
+
+ // Settlement
+
+ outPar << endl << "DISPERSAL - SETTLEMENT:" << endl;
+
+ if (trfr.moveModel) {
+ string plusmating = "+ mating requirements";
+ ssteps = pSpecies->getSteps(0, 0);
+
+ outPar << "MIN. No. OF STEPS:\t " << ssteps.minSteps << endl;
+ outPar << "MAX. No. OF STEPS:\t ";
+ if (ssteps.maxSteps == 99999999) outPar << "not applied" << endl;
+ else outPar << ssteps.maxSteps << endl;
+
+ if (sett.sexDep) {
+ nsexes = 2;
+ outPar << sexdept << "yes" << endl;
+ if (sett.stgDep) {
+ nstages = sstruct.nStages;
+ outPar << stgdept << "yes" << endl;
+ }
+ else { // !sett.stgDep
+ nstages = 1;
+ outPar << stgdept << "no" << endl;
+ }
+ }
+ else { // !sett.sexDep
+ nsexes = 1;
+ outPar << sexdept << "no" << endl;
+ if (sett.stgDep) {
+ nstages = sstruct.nStages;
+ outPar << stgdept << "yes" << endl;
+ }
+ else { // !sett.stgDep
+ nstages = 1;
+ outPar << stgdept << "no" << endl;
+ }
+ }
+ for (int sx = 0; sx < nsexes; sx++) {
+ if (sett.sexDep) {
+ if (sx == 0) outPar << "FEMALES:" << endl;
+ else outPar << "MALES:" << endl;
+ }
+ outPar << "SETTLE IF: ";
+ for (int i = 0; i < nstages; i++) {
+ if (dem.stageStruct && nstages > 1) outPar << "stage " << i << ": " << endl;
+ outPar << "find a suitable cell/patch ";
+ srules = pSpecies->getSettRules(i, sx);
+ if (srules.densDep) {
+ settleDD = pSpecies->getSettTraits(i, sx);
+ outPar << "+ density dependence ";
+ if (srules.findMate) outPar << plusmating;
+ outPar << endl;
+ if (!sett.indVar) {
+ outPar << "S0: " << settleDD.s0 << " AlphaS: " << settleDD.alpha
+ << " BetaS: " << settleDD.beta << endl;
+ }
+ }
+ else {
+ if (srules.findMate) outPar << plusmating << endl;
+ else outPar << "(not the natal one)" << endl;
+ }
+ if (dem.stageStruct) {
+ ssteps = pSpecies->getSteps(i, sx);
+ outPar << "MAX. No. OF STEPS/YEAR:\t ";
+ if (ssteps.maxStepsYr == 99999999) outPar << "not applied" << endl;
+ else outPar << ssteps.maxStepsYr << endl;
+ }
+ }
+ }
+ if (sett.indVar) {
+ settParams sparams0;
+ outPar << "DENSITY DEPENDENCE + " << indvar << "yes" << endl;
+ for (int sex = 0; sex < nsexes; sex++) {
+ if (sett.sexDep) {
+ if (sex == 0) outPar << "FEMALES:" << endl;
+ else outPar << "MALES:" << endl;
+ }
+ sparams0 = pSpecies->getSettParams(0, sex);
+ settScales scale = pSpecies->getSettScales();
+ outPar << "S0 - mean: " << sparams0.s0Mean << " s.d.: " << sparams0.s0SD
+ << " scaling factor: " << scale.s0Scale << endl;
+ outPar << "AlphaS - mean: " << sparams0.alphaSMean << " s.d.: " << sparams0.alphaSSD
+ << " scaling factor: " << scale.alphaSScale << endl;
+ outPar << "BetaS - mean: " << sparams0.betaSMean << " s.d.: " << sparams0.betaSSD
+ << " scaling factor: " << scale.betaSScale << endl;
+ }
+ }
+ }
+ else { // kernel-based transfer
+ string notsuit = "IF THE ARRIVAL CELL/PATCH IS UNSUITABLE: ";
+ string rchoose = " randomly choose a suitable neighb. cell/patch or ";
+ string matereq = "MATING REQUIREMENTS: ";
+ if (sett.sexDep) {
+ nsexes = 2;
+ outPar << sexdept << "yes" << endl;
+ if (sett.stgDep) {
+ nstages = sstruct.nStages;
+ outPar << stgdept << "yes" << endl;
+ outPar << notsuit << endl;
+ }
+ else {
+ nstages = 1;
+ outPar << stgdept << "no" << endl;
+ }
+ }
+ else {
+ nsexes = 1;
+ outPar << sexdept << "no" << endl;
+ if (sett.stgDep) {
+ nstages = sstruct.nStages;
+ outPar << stgdept << "yes" << endl;
+ outPar << notsuit << endl;
+ }
+ else {
+ nstages = 1;
+ outPar << stgdept << "no" << endl;
+ outPar << notsuit;
+ }
+ }
+ for (int i = 0; i < nstages; i++) {
+ if (sett.stgDep) {
+ outPar << "stage " << i << ":" << endl;
+ }
+ for (int sx = 0; sx < nsexes; sx++) {
+ if (sett.sexDep) {
+ if (sx == 0) outPar << "FEMALES: ";
+ else outPar << "MALES: ";
+ if (!sett.stgDep) outPar << notsuit;
+ }
+ srules = pSpecies->getSettRules(i, sx);
+ if (srules.go2nbrLocn) {
+ outPar << rchoose;
+ if (srules.wait) outPar << "wait" << endl;
+ else outPar << "die" << endl;
+ }
+ else {
+ if (srules.wait) outPar << "wait" << endl;
+ else outPar << "die" << endl;
+ }
+ outPar << matereq;
+ if (srules.findMate) outPar << "yes" << endl;
+ else outPar << "no" << endl;
+ }
+ }
+ }
+
+ // Genetics
+
+ outPar << endl << "GENETICS:" << endl;
+ int nspptraits = pSpecies->getNTraits();
+ outPar << "No. of variable traits: " << nspptraits << endl;
+
+ genomeData d = pSpecies->getGenomeData();
+ if (emig.indVar || trfr.indVar || sett.indVar || d.neutralMarkers)
+ {
+ if (d.diploid) outPar << "DIPLOID" << endl; else outPar << "HAPLOID" << endl;
+ int nchromosomes = pSpecies->getNChromosomes();
+ outPar << "No. of chromosomes: " << nchromosomes;
+ if (d.trait1Chromosome) {
+ outPar << endl << "No. of loci/chromosome: " << d.nLoci << endl;
+ }
+ else {
+ outPar << " (chrom:loci)";
+ for (int i = 0; i < nchromosomes; i++) {
+ outPar << " " << i << ":" << pSpecies->getNLoci(i);
+ }
+ outPar << endl;
+ }
+ outPar << "Mutation probability: " << d.probMutn << endl;
+ outPar << "Crossover probability: " << d.probCrossover << endl;
+ outPar << "Initial allele s.d.: " << d.alleleSD << endl;
+ outPar << "Mutation s.d.: " << d.mutationSD << endl;
+ if (d.neutralMarkers) {
+ outPar << "NEUTRAL MARKERS ONLY" << endl;
+ }
+ else {
+ if (!d.trait1Chromosome) {
+ traitAllele allele;
+ outPar << "TRAIT MAPPING:" << endl;
+ outPar << "Architecture file: " << genfilename << endl;
+ int ntraitmaps = pSpecies->getNTraitMaps();
+ outPar << "No. of traits defined: " << ntraitmaps << endl;
+ for (int i = 0; i < ntraitmaps; i++) {
+ int nalleles = pSpecies->getNTraitAlleles(i);
+ outPar << "Trait " << i << ": (" << pSpecies->getTraitName(i)
+ << ") alleles: " << nalleles << " (chrom:locus)";
+ for (int j = 0; j < nalleles; j++) {
+ allele = pSpecies->getTraitAllele(i, j);
+ outPar << " " << allele.chromo << ":" << allele.locus;
+ }
+ outPar << endl;
+ }
+ if (ntraitmaps < nspptraits) { // list undefined traits
+ outPar << "WARNING - the following traits were not defined"
+ << " in the genetic architecture file:" << endl;
+ for (int i = ntraitmaps; i < nspptraits; i++) {
+ outPar << "Trait " << i << ": (" << pSpecies->getTraitName(i)
+ << ") all individuals have mean phenotype" << endl;
+ }
+ }
+ int nneutral = pSpecies->getNNeutralLoci();
+ if (nneutral > 0) {
+ outPar << "Neutral loci: " << nneutral << " (chrom:locus)";
+ for (int i = 0; i < nneutral; i++) {
+ allele = pSpecies->getNeutralAllele(i);
+ outPar << " " << allele.chromo << ":" << allele.locus;
+ }
+ outPar << endl;
+ }
+ if (d.pleiotropic)
+ outPar << "Genome exhibits pleiotropy" << endl;
+ }
+ }
+ }
+
+ // Initialisation
+
+ initParams init = paramsInit->getInit();
+ outPar << endl << "INITIALISATION CONDITIONS:" << endl;
+ switch (init.seedType) {
+ case 0:
+ outPar << "Free initialisation: \t";
+ switch (init.freeType) {
+ case 0:
+ outPar << "Random \t";
+ outPar << "No. of cells/patches: " << init.nSeedPatches << endl;
+ break;
+ case 1:
+ outPar << "all suitable cells/patches" << endl;
+ break;
+ case 2:
+ outPar << "manually selected cells/patches" << endl;
+ break;
+ }
+ break;
+ case 1:
+ outPar << "From species distribution: \t" << endl;
+ switch (init.spDistType) {
+ case 0:
+ outPar << "all presence cells/patches" << endl;
+ break;
+ case 1:
+ outPar << "some random presence cells/patches" << endl;
+ break;
+ case 2:
+ outPar << "all cells/patches within selected distribution cells" << endl;
+ break;
+ }
+ break;
+ case 2:
+ outPar << "From initial individuals file: " << paramsSim->getDir(1) + init.indsFile << endl;
+ break;
+ case 3:
+ outPar << "From file" << endl;
+ break;
+ }
+ if (init.seedType != 2) {
+ outPar << "INITIAL NO. OF INDIVIDUALS: \t";
+ switch (init.initDens) {
+ case 0:
+ outPar << "at carrying capacity" << endl;
+ break;
+ case 1:
+ outPar << "at half carrying capacity" << endl;
+ break;
+ case 2:
+ if (ppLand.patchModel) {
+ outPar << init.indsHa << " individuals per ha" << endl;
+ }
+ else {
+ outPar << init.indsCell << " individuals per cell" << endl;
+ }
+ break;
+ }
+ if (dem.stageStruct) {
+ outPar << "INITIAL STAGE PROPORTIONS:" << endl;
+ for (int i = 1; i < sstruct.nStages; i++) {
+ outPar << "stage " << i << ": " << paramsInit->getProp(i) << " \t";
+ }
+ outPar << endl;
+ outPar << "Initial age distribution: ";
+ switch (init.initAge) {
+ case 0:
+ outPar << "lowest possible age";
+ break;
+ case 1:
+ outPar << "randomised";
+ break;
+ case 2:
+ outPar << "quasi-equilibrium";
+ break;
+ }
+ outPar << endl;
+ }
+ outPar << "GEOGRAPHICAL CONSTRAINTS (cell numbers): " << endl;
+ outPar << "min X: " << init.minSeedX << " max X: " << init.maxSeedX << endl;
+ outPar << "min Y: " << init.minSeedY << " max Y: " << init.maxSeedY << endl;
+ if (init.seedType == 0 && init.freeType < 2) {
+ if (init.initFrzYr > 0) {
+ outPar << "Freeze initial range until year " << init.initFrzYr << endl;
+ }
+ if (init.restrictRange) {
+ outPar << "Restrict range to northern " << init.restrictRows
+ << " rows every " << init.restrictFreq << " years" << endl;
+ if (init.finalFrzYr < sim.years) {
+ outPar << "Freeze range at year " << init.finalFrzYr << endl;
+ }
+ }
+ }
+ }
+
+ outPar << endl << "OUTPUTS:" << endl;
+ if (sim.outRange) {
+ outPar << "Range - every " << sim.outIntRange << " year";
+ if (sim.outIntRange > 1) outPar << "s";
+ outPar << endl;
+ }
+ if (sim.outOccup) {
+ outPar << "Occupancy - every " << sim.outIntOcc << " year";
+ if (sim.outIntOcc > 1) outPar << "s";
+ outPar << endl;
+ }
+ if (sim.outPop) {
+ outPar << "Populations - every " << sim.outIntPop << " year";
+ if (sim.outIntPop > 1) outPar << "s";
+ if (sim.outStartPop > 0) outPar << " starting year " << sim.outStartPop;
+ outPar << endl;
+ }
+ if (sim.outInds) {
+ outPar << "Individuals - every " << sim.outIntInd << " year";
+ if (sim.outIntInd > 1) outPar << "s";
+ if (sim.outStartInd > 0) outPar << " starting year " << sim.outStartInd;
+ outPar << endl;
+ }
+ if (sim.outGenetics) {
+ outPar << "Genetics - every " << sim.outIntGenetic << " year";
+ if (sim.outIntGenetic > 1) outPar << "s";
+ if (sim.outStartGenetic > 0) outPar << " starting year " << sim.outStartGenetic;
+ if (dem.stageStruct) {
+ switch (sim.outGenType) {
+ case 0:
+ outPar << " - juveniles only";
+ break;
+ case 1:
+ outPar << " - all individuals";
+ break;
+ case 2:
+ outPar << " - adults only";
+ break;
+ }
+ }
+ if (sim.outGenXtab) outPar << " (as cross table)";
+ outPar << endl;
+ }
+
+ if (sim.outTraitsCells) {
+ outPar << "Traits per ";
+ if (ppLand.patchModel) outPar << "patch"; else outPar << "cell";
+ outPar << " - every " << sim.outIntTraitCell << " year";
+ if (sim.outIntTraitCell > 1) outPar << "s";
+ if (sim.outStartTraitCell > 0) outPar << " starting year " << sim.outStartTraitCell;
+ outPar << endl;
+ }
+ if (sim.outTraitsRows) {
+ outPar << "Traits per row - every " << sim.outIntTraitRow << " year";
+ if (sim.outIntTraitRow > 1) outPar << "s";
+ if (sim.outStartTraitRow > 0) outPar << " starting year " << sim.outStartTraitRow;
+ outPar << endl;
+ }
+ if (sim.outConnect) {
+ outPar << "Connectivity matrix - every " << sim.outIntConn << " year";
+ if (sim.outIntConn > 1) outPar << "s";
+ if (sim.outStartConn > 0) outPar << " starting year " << sim.outStartConn;
+ outPar << endl;
+ }
+#if RS_RCPP
+ if (sim.outPaths) {
+ outPar << "SMS paths - every " << sim.outIntPaths << " year";
+ if (sim.outIntPaths > 1) outPar << "s";
+ if (sim.outStartPaths > 0) outPar << " starting year " << sim.outStartPaths;
+ outPar << endl;
+ }
+#endif
+ outPar << "SAVE MAPS: ";
+ if (sim.saveMaps) {
+ outPar << "yes - every " << sim.mapInt << " year";
+ if (sim.mapInt > 1) outPar << "s";
+ outPar << endl;
+ }
+ else outPar << "no" << endl;
+ outPar << "SAVE TRAITS MAPS: ";
+ if (sim.saveTraitMaps) {
+ outPar << "yes - every " << sim.traitInt << " year";
+ if (sim.traitInt > 1) outPar << "s";
+ outPar << endl;
+ }
+ else outPar << "no" << endl;
+ if (trfr.moveModel && trfr.moveType == 1) {
+ outPar << "SMS HEAT MAPS: ";
+ if (sim.saveVisits) outPar << "yes" << endl;
+ else outPar << "no" << endl;
+ }
+
+ outPar.close(); outPar.clear();
+
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
diff --git a/src/RScore/Model.h b/src/RScore/Model.h
new file mode 100644
index 00000000..f48d1554
--- /dev/null
+++ b/src/RScore/Model.h
@@ -0,0 +1,141 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 Model
+
+Implements three functions which run the model and produce output common to both
+GUI and batch version.
+
+RunModel() handles looping through replicates, years and generations
+
+Further functions are declared here, but defined differently in main function of
+GUI and batch versions.
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Peer G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 26 October 2021 by Steve Palmer
+------------------------------------------------------------------------------*/
+
+#ifndef ModelH
+#define ModelH
+
+#include
+#include
+
+#include "Parameters.h"
+#include "Landscape.h"
+#include "Community.h"
+#include "SubCommunity.h"
+#include "Species.h"
+
+#if !RS_EMBARCADERO && !LINUX_CLUSTER && !RS_RCPP
+#include
+using namespace std::filesystem;
+#endif
+
+#if RSDEBUG
+extern ofstream DEBUGLOG;
+#endif
+
+#if RS_RCPP && !R_CMD
+Rcpp::List RunModel(
+ Landscape*, // pointer to Landscape
+ int // sequential simulation number
+);
+#else
+int RunModel(
+ Landscape*, // pointer to Landscape
+ int // sequential simulation number
+);
+#endif // RS_RCPP && !R_CMD
+bool CheckDirectory(void);
+void PreReproductionOutput(
+ Landscape*, // pointer to Landscape
+ Community*, // pointer to Community
+ int, // replicate
+ int, // year
+ int // generation
+);
+void RangePopOutput(
+ Community*, // pointer to Community
+ int, // replicate
+ int, // year
+ int // generation
+);
+void Outputs_Visuals_B(
+ int, // replicate
+ int, // year
+ int, // generation
+ int // Landscape number
+);
+void RefreshVisualCost(void);
+traitCanvas SetupTraitCanvas(void);
+void SetupVisualOutput(void);
+void ResetVisualOutput(void);
+void DrawPopnGraph(
+ Community*, // pointer to Community
+ int // year
+);
+void OutParameters(
+ Landscape* // pointer to Landscape
+);
+
+extern paramGrad *paramsGrad;
+extern paramStoch *paramsStoch;
+extern Species *pSpecies;
+extern paramSim *paramsSim;
+extern paramInit *paramsInit;
+extern Community *pComm;
+
+const bool batchMode = true;
+extern string landFile;
+extern vector hfnames;
+extern string habmapname; // see Main.cpp (batch)
+extern string patchmapname; // see Main.cpp (batch)
+extern string distnmapname; // see Main.cpp (batch)
+extern string costmapname; // see Main.cpp (batch)
+extern string genfilename; // see Main.cpp (batch)
+extern RSrandom *pRandom;
+
+// these functions to have different version for GUI and batch applications ...
+#if BATCH
+extern void MemoLine(string);
+#endif
+void GUIsetLandScale(
+ int, // landscape image height (pixels)
+ int // landscape image width (pixels)
+);
+
+#if RS_RCPP
+extern std::uint32_t RS_random_seed;
+extern string name_landscape, name_patch, name_costfile, name_sp_dist;
+#endif
+//---------------------------------------------------------------------------
+#endif
diff --git a/src/RScore/Parameters.cpp b/src/RScore/Parameters.cpp
new file mode 100644
index 00000000..5cfb3d72
--- /dev/null
+++ b/src/RScore/Parameters.cpp
@@ -0,0 +1,382 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+ //---------------------------------------------------------------------------
+
+#include "Parameters.h"
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+
+// Environmental gradient parameters
+
+paramGrad::paramGrad(void) {
+ gradient = false; gradType = 0; grad_inc = 0.05f;
+ opt_y0 = opt_y = factor = extProbOpt = 0.0;
+ shifting = false; shift_rate = 0.5; shift_begin = 0; shift_stop = 100;
+}
+
+paramGrad::~paramGrad() { }
+
+void paramGrad::setGradient(int gtype, float inc, float y, float f, float p)
+{
+ if (gtype > 0 && gtype < 4)
+ { // valid gradient type
+ gradient = true; gradType = gtype;
+ if (inc >= 0.0 && inc <= 1.0) grad_inc = inc;
+ if (y >= 0.0) opt_y0 = opt_y = y;
+ if (f >= 0.0) factor = f;
+ if (p > 0.0 && p < 1.0) extProbOpt = p;
+ }
+ else {
+ gradient = false; gradType = 0;
+ }
+}
+
+void paramGrad::setShifting(float r, int begin, int end)
+{
+ shifting = true;
+ if (r > 0.0) shift_rate = r;
+ if (begin >= 0) shift_begin = begin;
+ if (end > 0) shift_stop = end;
+}
+
+void paramGrad::noGradient(void) { gradient = false; gradType = 0; }
+
+void paramGrad::noShifting(void) { shifting = false; }
+
+envGradParams paramGrad::getGradient(void) {
+ envGradParams g;
+ g.gradient = gradient; g.gradType = gradType; g.grad_inc = grad_inc;
+ g.opt_y = opt_y; g.factor = factor; g.extProbOpt = extProbOpt;
+ g.shifting = shifting; g.shift_rate = shift_rate;
+ g.shift_begin = shift_begin; g.shift_stop = shift_stop;
+ return g;
+}
+
+void paramGrad::incrOptY(void)
+{
+ if (gradient && shifting) opt_y += shift_rate;
+}
+
+void paramGrad::resetOptY(void) { opt_y = opt_y0; }
+
+//---------------------------------------------------------------------------
+
+// Environmental stochasticity parameters
+
+paramStoch::paramStoch(void) {
+ stoch = false; local = false; inK = false; localExt = false;
+ ac = 0.0; std = 0.25;
+ locExtProb = 0.1;
+}
+
+paramStoch::~paramStoch(void) {}
+
+
+void paramStoch::setStoch(envStochParams e)
+{
+ stoch = e.stoch; local = e.local; inK = e.inK; localExt = e.localExt;
+ if (e.ac >= 0.0 && e.ac < 1.0) ac = e.ac;
+ if (e.std > 0.0 && e.std <= 1.0) std = e.std;
+ locExtProb = e.locExtProb;
+}
+
+bool paramStoch::envStoch(void) { return stoch; }
+
+envStochParams paramStoch::getStoch(void)
+{
+ envStochParams e;
+ e.stoch = stoch; e.local = local; e.inK = inK; e.localExt = localExt;
+ e.ac = ac; e.std = std;
+ e.locExtProb = locExtProb;
+ return e;
+}
+
+
+//---------------------------------------------------------------------------
+
+// Initialisation (seeding) parameters
+
+paramInit::paramInit(void) {
+ seedType = freeType = spDistType = initDens = 0;
+ initAge = initFrzYr = 0;
+ restrictRange = false;
+ restrictRows = 100;
+ restrictFreq = 10;
+ finalFrzYr = 99999999;
+ indsCell = 1; indsHa = 0.0;
+ minSeedX = 0; maxSeedX = 99999999; minSeedY = 0; maxSeedY = 99999999;
+ nSeedPatches = 1; nSpDistPatches = 1;
+ indsFile = "NULL";
+ for (int i = 0; i < NSTAGES; i++) {
+ initProp[i] = 0.0;
+ }
+}
+
+paramInit::~paramInit(void) {
+ initinds.clear();
+}
+
+void paramInit::setInit(initParams i) {
+ if (i.seedType >= 0 && i.seedType <= 3) seedType = i.seedType;
+ if (i.freeType >= 0 && i.freeType <= 2) freeType = i.freeType;
+ if (i.spDistType >= 0 && i.spDistType <= 2) spDistType = i.spDistType;
+ initDens = i.initDens;
+ initAge = i.initAge;
+ if (i.initFrzYr >= 0) initFrzYr = i.initFrzYr;
+ restrictRange = i.restrictRange;
+ if (i.restrictRows > 0) restrictRows = i.restrictRows;
+ if (i.restrictFreq > 0) restrictFreq = i.restrictFreq;
+ if (i.finalFrzYr > 0) finalFrzYr = i.finalFrzYr;
+ if (i.indsCell >= 1) indsCell = i.indsCell;
+ if (i.indsHa > 0.0) indsHa = i.indsHa;
+ if (i.minSeedX >= 0) minSeedX = i.minSeedX;
+ if (i.maxSeedX >= 0) maxSeedX = i.maxSeedX;
+ if (i.minSeedY >= 0) minSeedY = i.minSeedY;
+ if (i.maxSeedY >= 0) maxSeedY = i.maxSeedY;
+ if (i.nSeedPatches >= 1) nSeedPatches = i.nSeedPatches;
+ if (i.nSpDistPatches >= 1) nSpDistPatches = i.nSpDistPatches;
+ indsFile = i.indsFile;
+}
+
+initParams paramInit::getInit(void) {
+ initParams i;
+ i.seedType = seedType; i.freeType = freeType; i.spDistType = spDistType;
+ i.initDens = initDens; i.initAge = initAge;
+ i.initFrzYr = initFrzYr;
+ i.restrictRange = restrictRange;
+ i.restrictRows = restrictRows; i.restrictFreq = restrictFreq;
+ i.finalFrzYr = finalFrzYr;
+ i.indsCell = indsCell; i.indsHa = indsHa;
+ i.minSeedX = minSeedX; i.minSeedY = minSeedY;
+ i.maxSeedX = maxSeedX; i.maxSeedY = maxSeedY;
+ i.nSeedPatches = nSeedPatches; i.nSpDistPatches = nSpDistPatches;
+ i.indsFile = indsFile;
+ return i;
+}
+
+void paramInit::setProp(short stg, float p) {
+ if (stg >= 0 && stg < NSTAGES && p >= 0.0 && p <= 1.0) initProp[stg] = p;
+}
+
+float paramInit::getProp(short stg) {
+ float p = 0.0;
+ if (stg >= 0 && stg < NSTAGES) p = initProp[stg];
+ return p;
+}
+
+void paramInit::addInitInd(initInd iind) {
+ initinds.push_back(iind);
+}
+
+initInd paramInit::getInitInd(int ix) {
+ initInd iind;
+ if (ix >= 0 && ix < (int)initinds.size()) {
+ iind = initinds[ix];
+ }
+ else {
+ iind.year = iind.patchID = iind.x = iind.y = iind.sex = iind.age = iind.stage = 0;
+ iind.species = -1;
+ }
+ return iind;
+}
+
+void paramInit::resetInitInds(void) { initinds.clear(); }
+
+int paramInit::numInitInds(void) { return (int)initinds.size(); }
+
+
+//---------------------------------------------------------------------------
+
+// Simulation parameters
+
+paramSim::paramSim(void) {
+ simulation = 0;
+ reps = years = 1;
+ outIntRange = 1;
+ outStartPop = outStartInd = outStartGenetic = 0;
+ outStartTraitCell = outStartTraitRow = outStartConn = 0;
+ outIntOcc = outIntPop = outIntInd = outIntGenetic = 10;
+ outIntTraitCell = outIntTraitRow = outIntConn = 10;
+ mapInt = traitInt = 10;
+ slowFactor = 1;
+ batchMode = absorbing = false;
+ outRange = outOccup = outPop = outInds = false;
+ outGenetics = outGenXtab = false; outGenType = 0;
+ outTraitsCells = outTraitsRows = outConnect = false;
+ saveMaps = false; saveTraitMaps = false;
+ saveVisits = false;
+#if RS_RCPP
+ outStartPaths = 0; outIntPaths = 0;
+ outPaths = false; ReturnPopRaster = false; CreatePopFile = true;
+#endif
+ drawLoaded = false;
+ viewLand = false; viewPatch = false; viewGrad = false; viewCosts = false;
+ viewPop = false; viewTraits = false; viewPaths = false; viewGraph = false;
+ dir = ' ';
+}
+
+paramSim::~paramSim(void) { }
+
+void paramSim::setSim(simParams s) {
+ if (s.batchNum >= 0) batchNum = s.batchNum;
+ if (s.simulation >= 0) simulation = s.simulation;
+ if (s.reps >= 1) reps = s.reps;
+ if (s.years >= 1) years = s.years;
+ if (s.mapInt >= 1) mapInt = s.mapInt;
+ if (s.traitInt >= 1) traitInt = s.traitInt;
+ batchMode = s.batchMode; absorbing = s.absorbing;
+ outRange = s.outRange; outOccup = s.outOccup;
+ outPop = s.outPop; outInds = s.outInds;
+ outGenetics = s.outGenetics;
+ if (s.outGenType >= 0 && s.outGenType <= 2) {
+ outGenType = s.outGenType;
+ }
+ outGenXtab = s.outGenXtab;
+ outTraitsCells = s.outTraitsCells; outTraitsRows = s.outTraitsRows;
+ outConnect = s.outConnect;
+ if (s.outStartPop >= 0) outStartPop = s.outStartPop;
+ if (s.outStartInd >= 0) outStartInd = s.outStartInd;
+ if (s.outStartGenetic >= 0) outStartGenetic = s.outStartGenetic;
+ if (s.outStartTraitCell >= 0) outStartTraitCell = s.outStartTraitCell;
+ if (s.outStartTraitRow >= 0) outStartTraitRow = s.outStartTraitRow;
+ if (s.outStartConn >= 0) outStartConn = s.outStartConn;
+ if (s.outIntRange >= 1) outIntRange = s.outIntRange;
+ if (s.outIntOcc >= 1) outIntOcc = s.outIntOcc;
+ if (s.outIntPop >= 1) outIntPop = s.outIntPop;
+ if (s.outIntInd >= 1) outIntInd = s.outIntInd;
+ if (s.outIntGenetic >= 1) outIntGenetic = s.outIntGenetic;
+ if (s.outIntTraitCell >= 1) outIntTraitCell = s.outIntTraitCell;
+ if (s.outIntTraitRow >= 1) outIntTraitRow = s.outIntTraitRow;
+ if (s.outIntConn >= 1) outIntConn = s.outIntConn;
+ saveMaps = s.saveMaps; saveTraitMaps = s.saveTraitMaps;
+ saveVisits = s.saveVisits;
+#if RS_RCPP
+ outStartPaths = s.outStartPaths;
+ outIntPaths = s.outIntPaths;
+ outPaths = s.outPaths;
+ ReturnPopRaster = s.ReturnPopRaster;
+ CreatePopFile = s.CreatePopFile;
+#endif
+ drawLoaded = s.drawLoaded;
+}
+
+simParams paramSim::getSim(void) {
+ simParams s;
+ s.batchNum = batchNum;
+ s.simulation = simulation; s.reps = reps; s.years = years;
+ s.outRange = outRange; s.outOccup = outOccup; s.outPop = outPop; s.outInds = outInds;
+ s.outGenetics = outGenetics; s.outGenType = outGenType; s.outGenXtab = outGenXtab;
+ s.outTraitsCells = outTraitsCells; s.outTraitsRows = outTraitsRows; s.outConnect = outConnect;
+ s.outStartPop = outStartPop; s.outStartInd = outStartInd; s.outStartGenetic = outStartGenetic;
+ s.outStartTraitCell = outStartTraitCell; s.outStartTraitRow = outStartTraitRow;
+ s.outStartConn = outStartConn;
+ s.outIntRange = outIntRange;
+ s.outIntOcc = outIntOcc; s.outIntPop = outIntPop;
+ s.outIntInd = outIntInd; s.outIntGenetic = outIntGenetic;
+ s.outIntTraitCell = outIntTraitCell;
+ s.outIntTraitRow = outIntTraitRow;
+ s.outIntConn = outIntConn;
+ s.batchMode = batchMode;
+ s.absorbing = absorbing;
+ s.saveMaps = saveMaps; s.saveTraitMaps = saveTraitMaps;
+ s.saveVisits = saveVisits;
+ s.mapInt = mapInt; s.traitInt = traitInt;
+#if RS_RCPP
+ s.outStartPaths = outStartPaths;
+ s.outIntPaths = outIntPaths;
+ s.outPaths = outPaths;
+ s.ReturnPopRaster = ReturnPopRaster;
+ s.CreatePopFile = CreatePopFile;
+#endif
+ s.drawLoaded = drawLoaded;
+ return s;
+}
+
+int paramSim::getSimNum(void) { return simulation; }
+
+void paramSim::setViews(simView v) {
+ viewLand = v.viewLand; viewPatch = v.viewPatch;
+ viewGrad = v.viewGrad; viewCosts = v.viewCosts;
+ viewPop = v.viewPop; viewTraits = v.viewTraits;
+ viewPaths = v.viewPaths; viewGraph = v.viewGraph;
+ if (v.slowFactor > 0) slowFactor = v.slowFactor;
+}
+
+simView paramSim::getViews(void) {
+ simView v;
+ v.viewLand = viewLand; v.viewPatch = viewPatch;
+ v.viewGrad = viewGrad; v.viewCosts = viewCosts;
+ v.viewPop = viewPop; v.viewTraits = viewTraits;
+ v.viewPaths = viewPaths; v.viewGraph = viewGraph;
+ v.slowFactor = slowFactor;
+ return v;
+}
+
+void paramSim::setDir(string s) {
+ dir = s;
+}
+
+// return directory name depending on option specified
+string paramSim::getDir(int option) {
+ string s;
+ switch (option) {
+ case 0: // working directory
+ s = dir;
+ break;
+#if LINUX_CLUSTER || RS_RCPP
+ case 1: // Inputs folder
+ s = dir + "Inputs/";
+ break;
+ case 2: // Outputs folder
+ s = dir + "Outputs/";
+ break;
+ case 3: // Maps folder
+ s = dir + "Output_Maps/";
+ break;
+#else
+ case 1: // Inputs folder
+ s = dir + "Inputs\\";
+ break;
+ case 2: // Outputs folder
+ s = dir + "Outputs\\";
+ break;
+ case 3: // Maps folder
+ s = dir + "Output_Maps\\";
+ break;
+#endif
+ default:
+ s = "ERROR_ERROR_ERROR";
+ }
+ return s;
+}
+
+#if RS_RCPP
+bool paramSim::getReturnPopRaster(void) { return ReturnPopRaster; }
+bool paramSim::getCreatePopFile(void) { return CreatePopFile; }
+#endif
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
diff --git a/src/RScore/Parameters.h b/src/RScore/Parameters.h
new file mode 100644
index 00000000..9cc51d2e
--- /dev/null
+++ b/src/RScore/Parameters.h
@@ -0,0 +1,386 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 Parameters
+
+Implements the following classes:
+
+paramGrad - Environmental gradient parameters
+paramInit - Initialisation (seeding) parameters
+paramSim - Simulation parameters
+paramStoch - Environmental stochasticity parameters
+
+Also declares some structures and functions used throughout the program.
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Peer G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 25 June 2021 by Steve Palmer
+
+------------------------------------------------------------------------------*/
+
+#ifndef ParametersH
+#define ParametersH
+
+//#if LINUX_CLUSTER
+//#include
+//#else
+#include
+//#endif
+#include
+#include
+//#include
+#include
+#include
+#include
+using namespace std;
+
+#include "RSrandom.h"
+
+#define NSTAGES 10 // maximum number of stages permitted
+#define NSEXES 2 // maximum number of sexes permitted
+#define PARAMDEBUG 0
+#define NTRAITS 18 // maximum number of variable traits which can be displayed
+ // in GUI (VCL version)
+#define NSD 3.0 // no. of s.d. to use to control range for displaying traits
+
+#if RS_RCPP
+typedef intptr_t intptr;
+#else
+#if RSWIN64
+typedef unsigned long long intptr;
+#else
+typedef unsigned int intptr;
+#endif
+#endif
+
+#if RS_RCPP
+ #ifndef R_EXT_CONSTANTS_H_ // the R headers define PI as a macro, so that the 'else' line results in an error
+ #define M_2PI 6.283185307179586
+ const double PI = 3.141592653589793238462643383279502884197169399375;
+ #endif
+#else
+ #define M_2PI 6.283185307179586
+ const double PI = 3.141592654;
+#endif
+
+const double SQRT2 = std::sqrt(double(2.0)); // more efficient than calculating every time
+
+//---------------------------------------------------------------------------
+
+// Common declarations
+
+struct locn { int x; int y; };
+struct rgb { // colour scheme for drawing maps
+ int r,g,b;
+};
+
+const string Int2Str(const int);
+#if RS_RCPP
+const string Int2Str(const int, unsigned int);
+#endif
+const string Float2Str(const float);
+const string Double2Str(const double);
+const rgb draw_wheel(int);
+
+//---------------------------------------------------------------------------
+
+// Environmental gradient parameters
+
+// SHOULD THIS BE PART OF LANDSCAPE OBJECT OR A SEPARATE OBJECT?????????????
+
+struct envGradParams {
+ bool gradient; bool shifting;
+ int gradType; float grad_inc; float opt_y; float factor; float extProbOpt;
+ float shift_rate; int shift_begin; int shift_stop;
+};
+
+class paramGrad {
+
+public:
+ paramGrad(void);
+ ~paramGrad(void);
+ void setGradient(
+ int, // gradient type
+ float, // gradient steepness
+ float, // optimum row (Y dimension)
+ float, // local scaling factor
+ float // local extinction probability at optimum
+ );
+ void setShifting(
+ float, // shifting rate (rows/year)
+ int, // first year of shifting
+ int // last year of shifting
+ );
+ void noGradient(void);
+ void noShifting(void);
+ envGradParams getGradient(void);
+ void incrOptY(void);
+ void resetOptY(void);
+
+private:
+ bool gradient; // there a gradient
+ bool shifting; // the gradient is shifting
+ int gradType; // 0 = none, 1 = carrying capacity,
+ // 2 = growth rate, 3 = local extinction probability
+ float grad_inc; // gradient steepness
+ float opt_y; // optimum row (Y dimension)
+ float opt_y0; // optimum row at year 0 (internal use only)
+ float factor; // local scaling factor
+ float extProbOpt; // local extinction probability at optimum (if gradient = 4, otherwise 0)
+ float shift_rate; // rows/year
+ int shift_begin; // first year of shifting
+ int shift_stop; // last year of shifting
+};
+
+//---------------------------------------------------------------------------
+
+// Environmental stochasticity parameters
+
+// SHOULD THIS BE PART OF LANDSCAPE OBJECT OR A SEPARATE OBJECT?????????????
+
+struct envStochParams {
+ bool stoch; bool local; bool inK; bool localExt;
+ float ac; float std;
+ float locExtProb;
+};
+
+class paramStoch {
+
+public:
+ paramStoch(void);
+ ~paramStoch(void);
+ void setStoch(envStochParams);
+ bool envStoch(void);
+ envStochParams getStoch(void);
+
+private:
+ bool stoch; // stochasticity applied
+ bool local; // applied locally (if not, application is global)
+ bool inK; // in carrying capacity (if not, in growth rate)
+ bool localExt; // local extinction applied
+ float ac; // temporal autocorrelation coefficient
+ float std; // amplitude of fluctuations: sampled from N(0,std)
+ float locExtProb; // local extinction probability
+};
+
+//---------------------------------------------------------------------------
+
+// Initialisation (seeding) parameters
+
+struct initParams {
+ short seedType; short freeType; short spDistType; short initDens;
+ short initAge; int initFrzYr; bool restrictRange;
+ int restrictRows; int restrictFreq; int finalFrzYr;
+ int indsCell; float indsHa;
+ int minSeedX; int maxSeedX; int minSeedY; int maxSeedY;
+ int nSeedPatches; int nSpDistPatches;
+ string indsFile;
+};
+
+struct initInd {
+ int year,patchID,x,y; short species,sex,age,stage;
+};
+
+class paramInit {
+
+public:
+ paramInit(void);
+ ~paramInit(void);
+ void setInit(initParams);
+ initParams getInit(void);
+ void setProp(
+ short, // stage
+ float // initial proportion
+ );
+ float getProp(
+ short // stage
+ );
+ void addInitInd(initInd);
+ initInd getInitInd(int);
+ void resetInitInds(void);
+ int numInitInds(void);
+
+private:
+ short seedType; // initialisation type: 0 = free, 1 = from species distn,
+ // 2 = initial individuals, 3 = from file
+ short freeType; // free initialisation type:
+ // 0 = random (given no.)
+ // 1 = all suitable cells/patches
+ // 2 = manually selected cells/patches
+ short spDistType; // species distribution initialisation type:
+ // 0 = all suitable cells/patches,
+ // 1 = some randomly chosen suitable cells/patches,
+ // 2 = all cells/patches within selected sp. dist. cells
+ short initDens; // initialisation density:
+ // 0 = at carrying capacity
+ // 1 = at half carrying capacity
+ // 2 = specified no. per cell or density
+ short initAge; // initial age distribution within each stage:
+ // 0 = lowest possible age
+ // 1 = randomised
+ // 2 = quasi-equilibrium
+ int initFrzYr; // year until which initial range is frozen
+ bool restrictRange; // restrict range to northern front
+ int restrictRows; // no. of rows to retain behind front
+ int restrictFreq; // frequency of range restriction
+ int finalFrzYr; // year after which range is frozen
+ int indsCell; // initial individuals / cell (cell-based model)
+ float indsHa; // initial density (patch-based model)
+ int minSeedX; // )
+ int maxSeedX; // ) min. and max. of area to initialise (cell numbers)
+ int minSeedY; // ) only applied if seedType is 0
+ int maxSeedY; // )
+ int nSeedPatches; // no. of cells/patches to initialise
+ int nSpDistPatches; // no. of species distribution cells to initialise
+ string indsFile; // no. of species distribution cells to initialise
+ float initProp[NSTAGES]; // initial stage proportions (structured population only)
+
+ vector initinds; // individuals to be initialised
+
+};
+
+//---------------------------------------------------------------------------
+
+// Simulation parameters
+
+struct simParams {
+ int batchNum;
+ int simulation; int reps; int years;
+// int outStartRange;
+// int outStartOcc;
+ int outStartPop; int outStartInd; int outStartGenetic;
+ int outStartTraitCell; int outStartTraitRow; int outStartConn;
+ int outIntRange; int outIntOcc; int outIntPop; int outIntInd; int outIntGenetic;
+ int outIntTraitCell; int outIntTraitRow; int outIntConn;
+ int mapInt; int traitInt;
+ bool batchMode; bool absorbing;
+ bool outRange; bool outOccup; bool outPop; bool outInds;
+ bool outGenetics; short outGenType; bool outGenXtab;
+ bool outTraitsCells; bool outTraitsRows; bool outConnect;
+ bool saveMaps;
+ bool drawLoaded; bool saveTraitMaps;
+ bool saveVisits;
+#if RS_RCPP
+ int outStartPaths; int outIntPaths;
+ bool outPaths; bool ReturnPopRaster; bool CreatePopFile;
+#endif
+};
+
+struct simView {
+ bool viewLand; bool viewPatch; bool viewGrad; bool viewCosts;
+ bool viewPop; bool viewTraits; bool viewPaths; bool viewGraph;
+ int slowFactor;
+};
+
+class paramSim {
+
+public:
+ paramSim(void);
+ ~paramSim(void);
+ void setSim(simParams);
+ simParams getSim(void);
+ int getSimNum(void);
+ void setViews(simView);
+ simView getViews(void);
+ void setDir(string);
+ string getDir(int);
+#if RS_RCPP
+ bool getReturnPopRaster(void);
+ bool getCreatePopFile(void);
+#endif
+
+private:
+ int batchNum; // batch number
+ int simulation; // simulation no.
+ int reps; // no. of replicates
+ int years; // no. of years
+// int outStartRange; // output start year for range file
+// int outStartOcc; // output start year for occupancy file
+ int outStartPop; // output start year for population file
+ int outStartInd; // output start year for individuals file
+ int outStartGenetic; // output start year for genetics file
+ int outStartTraitCell; // output start year for traits by cell file
+ int outStartTraitRow; // output start year for traits by row file
+ int outStartConn; // output start year for connectivity matrix
+ int outIntRange; // output interval for range file
+ int outIntOcc; // output interval for occupancy file
+ int outIntPop; // output interval for population file
+ int outIntInd; // output interval for individuals file
+ int outIntGenetic; // output interval for genetics file
+ int outIntTraitCell; // output interval for traits by cell file
+ int outIntTraitRow; // output interval for traits by row file
+ int outIntConn; // output interval for connectivity matrix
+ int mapInt; // output interval for maps
+ int traitInt; // output interval for evolving traits maps
+ int slowFactor; // to reduce speed of movement paths on screen
+ bool batchMode; //
+ bool absorbing; // landscape boundary and no-data regions are
+ // absorbing boundaries
+ bool outRange; // produce output range file?
+ bool outOccup; // produce output occupancy file?
+ bool outPop; // produce output population file?
+ bool outInds; // produce output individuals file?
+ bool outGenetics; // produce output genetics file?
+ short outGenType; // produce output genetics for: 0 = juveniles only
+ // 1 = all individuals, 2 = adults (i.e. final stage) only
+ bool outGenXtab; // produce output genetics as a cross table?
+ bool outTraitsCells; // produce output summary traits by cell file?
+ bool outTraitsRows; // produce output summary traits by row (y) file?
+ bool outConnect; // produce output connectivity file?
+ bool saveMaps; // save landscape/population maps?
+ bool saveVisits; // save dispersal visits heat maps?
+#if RS_RCPP
+ int outStartPaths;
+ int outIntPaths;
+ bool outPaths;
+ bool ReturnPopRaster;
+ bool CreatePopFile;
+#endif
+ bool drawLoaded; // draw initial distribution on landscape/population maps?
+ bool saveTraitMaps; // save summary traits maps?
+ bool viewLand; // view landscape map on screen?
+ bool viewPatch; // view map of landscape patches on screen?
+ bool viewGrad; // view gradient map on screen?
+ bool viewCosts; // view costs map on screen?
+ bool viewPop; // view population density on landscape map on screen?
+ bool viewTraits; // view summary traits map(s) on screen?
+ bool viewPaths; // view individual movement paths on screen?
+ bool viewGraph; // view population/occupancy graph on screen?
+ string dir; // full name of working directory
+
+};
+
+#if RSDEBUG
+extern ofstream DEBUGLOG;
+void DebugGUI(string);
+#endif
+
+//---------------------------------------------------------------------------
+#endif
diff --git a/src/RScore/Patch.cpp b/src/RScore/Patch.cpp
new file mode 100644
index 00000000..60421c45
--- /dev/null
+++ b/src/RScore/Patch.cpp
@@ -0,0 +1,358 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+//---------------------------------------------------------------------------
+
+#include "Patch.h"
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+
+Patch::Patch(int seqnum,int num)
+{
+patchSeqNum = seqnum; patchNum = num; nCells = 0;
+xMin = yMin = 999999999; xMax = yMax = 0; x = y = 0;
+subCommPtr = 0;
+localK = 0.0;
+for (int sex = 0; sex < NSEXES; sex++) {
+ nTemp[sex] = 0;
+}
+changed = false;
+}
+
+Patch::~Patch() {
+cells.clear();
+popns.clear();
+}
+
+int Patch::getSeqNum(void) { return patchSeqNum; }
+
+int Patch::getPatchNum(void) { return patchNum; }
+
+int Patch::getNCells(void) { return nCells; }
+
+patchLimits Patch::getLimits(void) {
+patchLimits p;
+p.xMin = xMin; p.xMax = xMax; p.yMin = yMin; p.yMax = yMax;
+return p;
+}
+
+// Does the patch fall (partially) within a specified rectangle?
+bool Patch::withinLimits(patchLimits rect){
+locn loc;
+if (xMin <= rect.xMax && xMax >= rect.xMin && yMin <= rect.yMax && yMax >= rect.yMin) {
+ // patch is within the rectangle UNLESS it is irregular in shape and lies at a corner
+ // of the rectangle
+ if ((xMin >= rect.xMin && xMax <= rect.xMax)
+ || (yMin >= rect.yMin && yMax <= rect.yMax)) {
+ // patch lies within or along an edge of the initialistaion rectangle
+ return true;
+ }
+ else {
+ // check for any cell of the patch lying within the rectangle
+ int ncells = (int)cells.size();
+ for (int i = 0; i < ncells; i++) {
+ loc = getCellLocn(i);
+ if (loc.x >= rect.xMin && loc.x <= rect.xMax
+ && loc.y >= rect.yMin && loc.y <= rect.yMax) {
+ // cell lies within the rectangle
+ return true;
+ }
+ }
+ }
+ }
+return false;
+}
+
+// Reset minimum and maximum co-ordinates of the patch if it has been changed
+void Patch::resetLimits(void) {
+if (changed) {
+ // remove any deleted cells
+ std::vector newcells; // for all retained and added cells
+ int ncells = (int)cells.size();
+ for (int i = 0; i < ncells; i++) {
+ if (cells[i] != NULL) {
+ newcells.push_back(cells[i]);
+ }
+ }
+ cells.clear();
+ cells = newcells;
+ // reset patch limits
+ locn loc;
+ xMin = yMin = 999999999; xMax = yMax = 0;
+ ncells = (int)cells.size();
+ for (int i = 0; i < ncells; i++) {
+ loc = getCellLocn(i);
+ if (loc.x < xMin) xMin = loc.x;
+ if (loc.x > xMax) xMax = loc.x;
+ if (loc.y < yMin) yMin = loc.y;
+ if (loc.y > yMax) yMax = loc.y;
+ }
+ changed = false;
+}
+}
+
+// Add a cell to the patch
+void Patch::addCell(Cell* pCell,int x,int y) {
+ cells.push_back(pCell);
+ nCells++;
+ if (x < xMin) xMin = x;
+ if (x > xMax) xMax = x;
+ if (y < yMin) yMin = y;
+ if (y > yMax) yMax = y;
+}
+
+// Calculate the total carrying capacity (no. of individuals) and
+// centroid co-ordinates of the patch
+void Patch::setCarryingCapacity(Species *pSpecies,patchLimits landlimits,
+ float epsGlobal,short nHab,short rasterType,short landIx,bool gradK) {
+envStochParams env = paramsStoch->getStoch();
+//Cell *pCell;
+locn loc;
+int xsum,ysum;
+short hx;
+float k,q,envval;
+
+localK = 0.0; // no. of suitable cells (unadjusted K > 0) in the patch
+int nsuitable = 0;
+double mean;
+
+#if RSDEBUG
+//DEBUGLOG << "Patch::setCarryingCapacity(): patchNum=" << patchNum
+// << " xMin=" << xMin << " yMin=" << yMin << " xMax=" << xMax << " yMax=" << yMax
+// << endl;
+#endif
+
+if (xMin > landlimits.xMax || xMax < landlimits.xMin
+|| yMin > landlimits.yMax || yMax < landlimits.yMin) {
+ // patch lies wholely outwith current landscape limits
+ // NB the next statement is unnecessary, as localK has been set to zero above
+ // retained only for consistency in standard variant
+ localK = 0.0;
+#if RSDEBUG
+//DEBUGLOG << "Patch::setCarryingCapacity(): patchNum=" << patchNum
+// << " localK=" << localK
+// << endl;
+#endif
+ return;
+}
+
+int ncells = (int)cells.size();
+xsum = ysum = 0;
+for (int i = 0; i < ncells; i++) {
+ if (gradK) // gradient in carrying capacity
+ envval = cells[i]->getEnvVal(); // environmental gradient value
+ else envval = 1.0; // no gradient effect
+ if (env.stoch && env.inK) { // environmental stochasticity in K
+ if (env.local) {
+// pCell = getRandomCell();
+// if (pCell != 0) envval += pCell->getEps();
+ envval += cells[i]->getEps();
+ }
+ else { // global stochasticity
+ envval += epsGlobal;
+ }
+ }
+ switch (rasterType) {
+ case 0: // habitat codes
+ hx = cells[i]->getHabIndex(landIx);
+ k = pSpecies->getHabK(hx);
+ if (k > 0.0) {
+ nsuitable++;
+ localK += envval * k;
+ }
+ break;
+ case 1: // cover %
+ k = 0.0;
+ for (int j = 0; j < nHab; j++) { // loop through cover layers
+ q = cells[i]->getHabitat(j);
+ k += q * pSpecies->getHabK(j) / 100.0f;
+ }
+ if (k > 0.0) {
+ nsuitable++;
+ localK += envval * k;
+ }
+ break;
+ case 2: // habitat quality
+ q = cells[i]->getHabitat(landIx);
+ if (q > 0.0) {
+ nsuitable++;
+ localK += envval * pSpecies->getHabK(0) * q / 100.0f;
+ }
+ break;
+ }
+#if RSDEBUG
+//DEBUGLOG << "Patch::setCarryingCapacity(): patchNum=" << patchNum
+// << " i=" << i << " hx=" << hx << " q=" << q << " k=" << k << " localK=" << localK
+// << endl;
+#endif
+ loc = cells[i]->getLocn();
+ xsum += loc.x; ysum += loc.y;
+}
+#if RSDEBUG
+//DEBUGLOG << "Patch::setCarryingCapacity(): patchNum=" << patchNum
+// << " epsGlobal=" << epsGlobal << " localK=" << localK
+// << endl;
+#endif
+// calculate centroid co-ordinates
+if (ncells > 0) {
+ mean = (double)xsum / (double)ncells;
+ x = (int)(mean + 0.5);
+ mean = (double)ysum / (double)ncells;
+ y = (int)(mean + 0.5);
+}
+if (env.stoch && env.inK) { // environmental stochasticity in K
+ // apply min and max limits to K over the whole patch
+ // NB limits have been stored as N/cell rather than N/ha
+ float limit;
+ limit = pSpecies->getMinMax(0) * (float)nsuitable;
+ if (localK < limit) localK = limit;
+#if RSDEBUG
+//DEBUGLOG << "Patch::setCarryingCapacity(): patchNum=" << patchNum
+// << " limit=" << limit << " localK=" << localK
+// << endl;
+#endif
+ limit = pSpecies->getMinMax(1) * (float)nsuitable;
+ if (localK > limit) localK = limit;
+#if RSDEBUG
+//DEBUGLOG << "Patch::setCarryingCapacity(): patchNum=" << patchNum
+// << " limit=" << limit << " localK=" << localK
+// << endl;
+#endif
+}
+#if RSDEBUG
+//DEBUGLOG << "Patch::setCarryingCapacity(): patchNum=" << patchNum
+// << " localK=" << localK
+// << endl;
+#endif
+}
+
+
+float Patch::getK(void) { return localK; }
+
+// Return co-ordinates of a specified cell
+locn Patch::getCellLocn(int ix) {
+locn loc; loc.x = -666; loc.y = -666;
+int ncells = (int)cells.size();
+if (ix >= 0 && ix < ncells) {
+ loc = cells[ix]->getLocn();
+}
+return loc;
+}
+// Return pointer to a specified cell
+Cell* Patch::getCell(int ix) {
+int ncells = (int)cells.size();
+if (ix >= 0 && ix < ncells) return cells[ix];
+else return 0;
+}
+// Return co-ordinates of patch centroid
+locn Patch::getCentroid(void) {
+locn loc; loc.x = x; loc.y = y;
+return loc;
+}
+
+// Select a Cell within the Patch at random, and return pointer to it
+// For a cell-based model, this will be the only Cell
+Cell* Patch::getRandomCell(void) {
+Cell *pCell = 0;
+int ix;
+int ncells = (int)cells.size();
+if (ncells > 0) {
+ if (ncells == 1) ix = 0;
+ else ix = pRandom->IRandom(0,ncells-1);
+ pCell = cells[ix];
+}
+return pCell;
+}
+
+// Remove a cell from the patch
+void Patch::removeCell(Cell* pCell) {
+int ncells = (int)cells.size();
+for (int i = 0; i < ncells; i++) {
+ if (pCell == cells[i]) {
+ cells[i] = NULL; i = ncells;
+ nCells--;
+ changed = true;
+ }
+}
+}
+
+void Patch::setSubComm(intptr sc)
+{ subCommPtr = sc; }
+
+// Get pointer to corresponding Sub-community (cast as an integer)
+intptr Patch::getSubComm(void)
+{ return subCommPtr; }
+
+void Patch::addPopn(patchPopn pop) {
+popns.push_back(pop);
+}
+
+// Return pointer (cast as integer) to the Population of the specified Species
+intptr Patch::getPopn(intptr sp)
+{
+int npops = (int)popns.size();
+for (int i = 0; i < npops; i++) {
+ if (popns[i].pSp == sp) return popns[i].pPop;
+}
+return 0;
+}
+
+void Patch::resetPopn(void) {
+popns.clear();
+}
+
+void Patch::resetPossSettlers(void) {
+for (int sex = 0; sex < NSEXES; sex++) {
+ nTemp[sex] = 0;
+}
+}
+
+// Record the presence of a potential settler within the Patch
+void Patch::incrPossSettler(Species *pSpecies,int sex) {
+#if RSDEBUG
+//DEBUGLOG << "Patch::incrPossSettler(): 5555: patchNum = " << patchNum
+// << " sex = " << sex << endl;
+#endif
+// NOTE: THE FOLLOWING OPERATION WILL NEED TO BE MADE SPECIES-SPECIFIC...
+if (sex >= 0 && sex < NSEXES) {
+ nTemp[sex]++;
+}
+}
+
+// Get number of a potential settlers within the Patch
+int Patch::getPossSettlers(Species *pSpecies,int sex) {
+#if RSDEBUG
+//DEBUGLOG << "Patch::getPossSettlers(): 5555: patchNum = " << patchNum
+// << " sex = " << sex << endl;
+#endif
+// NOTE: THE FOLLOWING OPERATION WILL NEED TO BE MADE SPECIES-SPECIFIC...
+if (sex >= 0 && sex < NSEXES) return nTemp[sex];
+else return 0;
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+
+
diff --git a/src/RScore/Patch.h b/src/RScore/Patch.h
new file mode 100644
index 00000000..40959083
--- /dev/null
+++ b/src/RScore/Patch.h
@@ -0,0 +1,174 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 Patch
+
+Implements the class: Patch
+
+A patch is a collection of one or more Cells in the the gridded Landscape,
+which together provide the area in which a single demographic unit of a Species,
+i.e. a Population, can reproduce. One or more Populations (of different Species)
+form a Sub-community associated with the Patch.
+
+There is no requirement that all the Cells be adjacent, although in practice
+that would usually be the case.
+
+Each Patch must have a unique positive integer id number supplied by the user,
+and the matrix, i.e. any part of the landscape which is not a breeding patch,
+is represented by Patch 0. However, as patch numbers need not be sequential,
+an internal sequential number is also applied.
+
+For a 'cell-based model', the user supplies no patch numbers, and a separate
+Patch is generated internally for each Cell, i.e. the 'cell-based model' is a
+special case of the 'patch-based model' in which each Patch has a single Cell.
+Moreover, there is also the 'matrix' Patch 0, which has no cells, but which
+holds the disperser population whilst its Individuals are in transit.
+
+In a true patch-based model, each Patch hold a list of its constituent Cells,
+EXCEPT for the matrix Patch 0. This is because that list would be extremely
+long for a very large landscape in which suitable patches are small and/or rare,
+and removing Cells from it if the landscape is dynamic would be inefficient.
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Peer G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 25 June 2021 by Steve Palmer
+
+------------------------------------------------------------------------------*/
+
+#ifndef PatchH
+#define PatchH
+
+#include
+using namespace std;
+
+#include "Parameters.h"
+#include "Cell.h"
+#include "Species.h"
+
+//---------------------------------------------------------------------------
+
+struct patchLimits {
+ int xMin,xMax,yMin,yMax;
+};
+struct patchPopn {
+ intptr pSp,pPop; // pointers to Species and Population cast as integers
+};
+
+class Patch{
+public:
+ Patch(
+ int, // internal sequential number
+ int // patch id number
+ );
+ ~Patch();
+ int getSeqNum(void);
+ int getPatchNum(void);
+ int getNCells(void);
+ patchLimits getLimits(void); // Returns the minimum and maximum co-ordinates of the patch
+ bool withinLimits( // Does the patch fall (partially) within a specified rectangle?
+ patchLimits // structure holding the SW and NE co-ordinates of the rectangle
+ );
+ void resetLimits(void); // Reset minimum and maximum co-ordinates of the patch
+ void addCell(
+ Cell*, // pointer to the Cell to be added to the Patch
+ int,int // x (column) and y (row) co-ordinates of the Cell
+ );
+ locn getCellLocn( // Return co-ordinates of a specified cell
+ int // index no. of the Cell within the vector cells
+ );
+ Cell* getCell( // Return pointer to a specified cell
+ int // index no. of the Cell within the vector cells
+ );
+ locn getCentroid(void); // Return co-ordinates of patch centroid
+ void removeCell(
+ Cell* // pointer to the Cell to be removed from the Patch
+ );
+ Cell* getRandomCell(void);
+ void setSubComm(
+ intptr // pointer to the Sub-community cast as an integer
+ );
+ intptr getSubComm(void);
+ void addPopn(
+ patchPopn // structure holding pointers to Species and Population cast as integers
+ );
+ intptr getPopn( // return pointer (cast as integer) to the Population of the Species
+ intptr // pointer to Species cast as integer
+ );
+ void resetPopn(void);
+ void resetPossSettlers(void);
+ void incrPossSettler( // Record the presence of a potential settler within the Patch
+ Species*, // pointer to the Species
+ int // sex of the settler
+ );
+ int getPossSettlers( // Get number of a potential settlers within the Patch
+ Species*, // pointer to the Species
+ int // sex of the settlers
+ );
+ void setCarryingCapacity( // Calculate total Patch carrying capacity (no. of inds)
+ Species*, // pointer to the Species
+ patchLimits, // current min and max limits of landscape
+ float, // global stochasticity value (epsilon) for the current year
+ short, // no. of habitat classes in the Landscape
+ short, // rasterType (see Landscape)
+ short, // landscape change index (always zero if not dynamic)
+ bool // TRUE if there is a gradient in carrying capacity across the Landscape
+ );
+ float getK(void);
+ // dummy function for batch version
+ void drawCells(float,int,rgb);
+
+ private:
+ int patchSeqNum;// sequential patch number - patch 0 is reserved for the inter-patch matrix
+ int patchNum; // patch number as supplied by the user (not forced to be sequential)
+ int nCells; // no. of cells in the patch
+ int xMin,xMax,yMin,yMax; // min and max cell co-ordinates
+ int x,y; // centroid co-ordinates (approx.)
+ intptr subCommPtr; // pointer (cast as integer) to sub-community associated with the patch
+ // NOTE: FOR MULTI-SPECIES MODEL, PATCH WILL NEED TO STORE K FOR EACH SPECIES
+ float localK; // patch carrying capacity (individuals)
+ bool changed;
+// NOTE: THE FOLLOWING ARRAY WILL NEED TO BE MADE SPECIES-SPECIFIC...
+ short nTemp[NSEXES]; // no. of potential settlers in each sex
+
+ std::vector cells;
+ std::vector popns;
+
+};
+
+//---------------------------------------------------------------------------
+
+extern paramStoch *paramsStoch;
+extern RSrandom *pRandom;
+
+#if RSDEBUG
+extern ofstream DEBUGLOG;
+#endif
+
+#endif
diff --git a/src/RScore/Population.cpp b/src/RScore/Population.cpp
new file mode 100644
index 00000000..3dbb6a29
--- /dev/null
+++ b/src/RScore/Population.cpp
@@ -0,0 +1,1673 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+ //---------------------------------------------------------------------------
+
+#include "Population.h"
+//---------------------------------------------------------------------------
+
+ofstream outPop;
+ofstream outInds;
+
+//---------------------------------------------------------------------------
+
+Population::Population(void) {
+ nSexes = nStages = 0;
+ pPatch = NULL;
+ pSpecies = NULL;
+ return;
+}
+
+Population::Population(Species* pSp, Patch* pPch, int ninds, int resol)
+{
+ // constructor for a Population of a specified size
+
+ int n, nindivs, age = 0, minage, maxage, nAges = 0;
+ int cumtotal = 0;
+ float probmale;
+ double ageprob, ageprobsum;
+ std::vector ageProb; // for quasi-equilibrium initial age distribution
+ Cell* pCell;
+
+ if (ninds > 0) {
+ inds.reserve(ninds);
+ juvs.reserve(ninds);
+ }
+
+ pSpecies = pSp;
+ pPatch = pPch;
+ // record the new population in the patch
+ patchPopn pp;
+ pp.pSp = (intptr)pSpecies; pp.pPop = (intptr)this;
+ pPatch->addPopn(pp);
+
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ genomeData gen = pSpecies->getGenomeData();
+ initParams init = paramsInit->getInit();
+
+ // determine no. of stages and sexes of species to initialise
+ if (dem.stageStruct) {
+ nStages = sstruct.nStages;
+ }
+ else // non-structured population has 2 stages, but user only ever sees stage 1
+ nStages = 2;
+ if (dem.repType == 0) { nSexes = 1; probmale = 0.0; }
+ else { nSexes = 2; probmale = dem.propMales; }
+
+ // set up population sub-totals
+ for (int stg = 0; stg < NSTAGES; stg++) {
+ for (int sex = 0; sex < NSEXES; sex++) {
+ nInds[stg][sex] = 0;
+ }
+ }
+
+ // set up local copy of minimum age table
+ short minAge[NSTAGES][NSEXES];
+ for (int stg = 0; stg < nStages; stg++) {
+ for (int sex = 0; sex < nSexes; sex++) {
+ if (dem.stageStruct) {
+ if (dem.repType == 1) { // simple sexual model
+ // both sexes use minimum ages recorded for females
+ minAge[stg][sex] = pSpecies->getMinAge(stg, 0);
+ }
+ else {
+ minAge[stg][sex] = pSpecies->getMinAge(stg, sex);
+ }
+ }
+ else { // non-structured population
+ minAge[stg][sex] = 0;
+ }
+ }
+ }
+
+ // individuals of new population must be >= stage 1
+ for (int stg = 1; stg < nStages; stg++) {
+ if (dem.stageStruct) { // allocate to stages according to initialisation conditions
+ // final stage is treated separately to ensure that correct total
+ // no. of individuals is created
+ if (stg == nStages - 1) {
+ n = ninds - cumtotal;
+ }
+ else {
+ n = (int)(ninds * paramsInit->getProp(stg) + 0.5);
+ cumtotal += n;
+ }
+ }
+ else { // non-structured - all individuals go into stage 1
+ n = ninds;
+ }
+ // establish initial age distribution
+ minage = maxage = stg;
+ if (dem.stageStruct) {
+ // allow for stage-dependent minimum ages (use whichever sex is greater)
+ if (minAge[stg][0] > 0 && minage < minAge[stg][0]) minage = minAge[stg][0];
+ if (nSexes == 2 && minAge[stg][1] > 0 && minage < minAge[stg][1]) minage = minAge[stg][1];
+ // allow for specified age distribution
+ if (init.initAge != 0) { // not lowest age
+ if (stg == nStages - 1) maxage = sstruct.maxAge; // final stage
+ else { // all other stages - use female max age, as sex of individuals is not predetermined
+ maxage = minAge[stg + 1][0] - 1;
+ }
+ if (maxage < minage) maxage = minage;
+ nAges = maxage - minage + 1;
+ if (init.initAge == 2) { // quasi-equilibrium distribution
+ double psurv = (double)pSpecies->getSurv(stg, 0); // use female survival for the stage
+ ageProb.clear();
+ ageprobsum = 0.0;
+ ageprob = 1.0;
+ for (int i = 0; i < nAges; i++) {
+ ageProb.push_back(ageprob); ageprobsum += ageprob; ageprob *= psurv;
+ }
+ for (int i = 0; i < nAges; i++) {
+ ageProb[i] /= ageprobsum;
+ if (i > 0) ageProb[i] += ageProb[i - 1]; // to give cumulative probability
+ }
+ }
+ }
+ }
+ // create individuals
+ int sex;
+ nindivs = (int)inds.size();
+ for (int i = 0; i < n; i++) {
+ pCell = pPatch->getRandomCell();
+ if (dem.stageStruct) {
+ switch (init.initAge) {
+ case 0: // lowest possible age
+ age = minage;
+ break;
+ case 1: // randomised
+ if (maxage > minage) age = pRandom->IRandom(minage, maxage);
+ else age = minage;
+ break;
+ case 2: // quasi-equilibrium
+ if (nAges > 1) {
+ double rrr = pRandom->Random();
+ int ageclass = 0;
+ while (rrr > ageProb[ageclass]) ageclass++;
+ age = minage + ageclass;
+ }
+ else age = minage;
+ break;
+ }
+ }
+ else age = stg;
+#if RSDEBUG
+ // NOTE: CURRENTLY SETTING ALL INDIVIDUALS TO RECORD NO. OF STEPS ...
+ inds.push_back(new Individual(pCell, pPatch, stg, age, sstruct.repInterval,
+ probmale, true, trfr.moveType));
+#else
+ inds.push_back(new Individual(pCell, pPatch, stg, age, sstruct.repInterval,
+ probmale, trfr.moveModel, trfr.moveType));
+#endif
+ sex = inds[nindivs + i]->getSex();
+ if (emig.indVar || trfr.indVar || sett.indVar || gen.neutralMarkers)
+ {
+ // individual variation - set up genetics
+ inds[nindivs + i]->setGenes(pSpecies, resol);
+ }
+ nInds[stg][sex]++;
+ }
+ }
+}
+
+Population::~Population(void) {
+ int ninds = (int)inds.size();
+ for (int i = 0; i < ninds; i++) {
+ if (inds[i] != NULL) delete inds[i];
+ }
+ inds.clear();
+ int njuvs = (int)juvs.size();
+ for (int i = 0; i < njuvs; i++) {
+ if (juvs[i] != NULL) delete juvs[i];
+ }
+ juvs.clear();
+}
+
+traitsums Population::getTraits(Species* pSpecies) {
+ int g;
+ traitsums ts;
+ for (int i = 0; i < NSEXES; i++) {
+ ts.ninds[i] = 0;
+ ts.sumD0[i] = ts.ssqD0[i] = 0.0;
+ ts.sumAlpha[i] = ts.ssqAlpha[i] = 0.0; ts.sumBeta[i] = ts.ssqBeta[i] = 0.0;
+ ts.sumDist1[i] = ts.ssqDist1[i] = 0.0; ts.sumDist2[i] = ts.ssqDist2[i] = 0.0;
+ ts.sumProp1[i] = ts.ssqProp1[i] = 0.0;
+ ts.sumDP[i] = ts.ssqDP[i] = 0.0;
+ ts.sumGB[i] = ts.ssqGB[i] = 0.0;
+ ts.sumAlphaDB[i] = ts.ssqAlphaDB[i] = 0.0;
+ ts.sumBetaDB[i] = ts.ssqBetaDB[i] = 0.0;
+ ts.sumStepL[i] = ts.ssqStepL[i] = 0.0; ts.sumRho[i] = ts.ssqRho[i] = 0.0;
+ ts.sumS0[i] = ts.ssqS0[i] = 0.0;
+ ts.sumAlphaS[i] = ts.ssqAlphaS[i] = 0.0; ts.sumBetaS[i] = ts.ssqBetaS[i] = 0.0;
+ }
+
+ demogrParams dem = pSpecies->getDemogr();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+
+ int ninds = (int)inds.size();
+ for (int i = 0; i < ninds; i++) {
+ int sex = inds[i]->getSex();
+ if (emig.sexDep || trfr.sexDep || sett.sexDep) g = sex; else g = 0;
+ ts.ninds[g] += 1;
+ // emigration traits
+ emigTraits e = inds[i]->getEmigTraits();
+ if (emig.sexDep) g = sex; else g = 0;
+ ts.sumD0[g] += e.d0; ts.ssqD0[g] += e.d0 * e.d0;
+ ts.sumAlpha[g] += e.alpha; ts.ssqAlpha[g] += e.alpha * e.alpha;
+ ts.sumBeta[g] += e.beta; ts.ssqBeta[g] += e.beta * e.beta;
+ // transfer traits
+ trfrKernTraits k = inds[i]->getKernTraits();
+ if (trfr.sexDep) g = sex; else g = 0;
+ ts.sumDist1[g] += k.meanDist1; ts.ssqDist1[g] += k.meanDist1 * k.meanDist1;
+ ts.sumDist2[g] += k.meanDist2; ts.ssqDist2[g] += k.meanDist2 * k.meanDist2;
+ ts.sumProp1[g] += k.probKern1; ts.ssqProp1[g] += k.probKern1 * k.probKern1;
+ trfrSMSTraits sms = inds[i]->getSMSTraits();
+ g = 0; // CURRENTLY INDIVIDUAL VARIATION CANNOT BE SEX-DEPENDENT
+ ts.sumDP[g] += sms.dp; ts.ssqDP[g] += sms.dp * sms.dp;
+ ts.sumGB[g] += sms.gb; ts.ssqGB[g] += sms.gb * sms.gb;
+ ts.sumAlphaDB[g] += sms.alphaDB; ts.ssqAlphaDB[g] += sms.alphaDB * sms.alphaDB;
+ ts.sumBetaDB[g] += sms.betaDB; ts.ssqBetaDB[g] += sms.betaDB * sms.betaDB;
+ trfrCRWTraits c = inds[i]->getCRWTraits();
+ g = 0; // CURRENTLY INDIVIDUAL VARIATION CANNOT BE SEX-DEPENDENT
+ ts.sumStepL[g] += c.stepLength; ts.ssqStepL[g] += c.stepLength * c.stepLength;
+ ts.sumRho[g] += c.rho; ts.ssqRho[g] += c.rho * c.rho;
+ // settlement traits
+ settleTraits s = inds[i]->getSettTraits();
+ if (sett.sexDep) g = sex; else g = 0;
+ ts.sumS0[g] += s.s0; ts.ssqS0[g] += s.s0 * s.s0;
+ ts.sumAlphaS[g] += s.alpha; ts.ssqAlphaS[g] += s.alpha * s.alpha;
+ ts.sumBetaS[g] += s.beta; ts.ssqBetaS[g] += s.beta * s.beta;
+ }
+
+ return ts;
+}
+
+int Population::getNInds(void) { return (int)inds.size(); }
+
+popStats Population::getStats(void)
+{
+ popStats p;
+ int ninds;
+ float fec;
+ bool breeders[2]; breeders[0] = breeders[1] = false;
+ demogrParams dem = pSpecies->getDemogr();
+ p.pSpecies = pSpecies;
+ p.pPatch = pPatch;
+ p.spNum = pSpecies->getSpNum();
+ p.nInds = (int)inds.size();
+ p.nNonJuvs = p.nAdults = 0;
+ p.breeding = false;
+ for (int stg = 1; stg < nStages; stg++) {
+ for (int sex = 0; sex < nSexes; sex++) {
+ ninds = nInds[stg][sex];
+ p.nNonJuvs += ninds;
+
+ if (ninds > 0) {
+ if (pSpecies->stageStructured()) {
+ if (dem.repType == 2) fec = pSpecies->getFec(stg, sex);
+ else fec = pSpecies->getFec(stg, 0);
+ if (fec > 0.0) { breeders[sex] = true; p.nAdults += ninds; }
+ }
+ else breeders[sex] = true;
+ }
+ }
+ }
+ // is there a breeding population present?
+ if (nSexes == 1) {
+ p.breeding = breeders[0];
+ }
+ else {
+ if (breeders[0] && breeders[1]) p.breeding = true;
+ }
+ return p;
+}
+
+Species* Population::getSpecies(void) { return pSpecies; }
+
+int Population::totalPop(void) {
+ int t = 0;
+ for (int stg = 0; stg < nStages; stg++) {
+ for (int sex = 0; sex < nSexes; sex++) {
+ t += nInds[stg][sex];
+ }
+ }
+ return t;
+}
+
+int Population::stagePop(int stg) {
+ int t = 0;
+ if (stg < 0 || stg >= nStages) return t;
+ for (int sex = 0; sex < nSexes; sex++) {
+ t += nInds[stg][sex];
+ }
+ return t;
+}
+
+//---------------------------------------------------------------------------
+// Remove all Individuals
+void Population::extirpate(void) {
+ int ninds = (int)inds.size();
+ for (int i = 0; i < ninds; i++) {
+ if (inds[i] != NULL) delete inds[i];
+ }
+ inds.clear();
+ int njuvs = (int)juvs.size();
+ for (int i = 0; i < njuvs; i++) {
+ if (juvs[i] != NULL) delete juvs[i];
+ }
+ juvs.clear();
+ for (int sex = 0; sex < nSexes; sex++) {
+ for (int stg = 0; stg < nStages; stg++) {
+ nInds[stg][sex] = 0;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+// Produce juveniles and hold them in the juvs vector
+void Population::reproduction(const float localK, const float envval, const int resol)
+{
+
+ // get population size at start of reproduction
+ int ninds = (int)inds.size();
+ if (ninds == 0) return;
+
+ int nsexes, stage, sex, njuvs, nj, nmales, nfemales;
+ Cell* pCell;
+ indStats ind;
+ double expected;
+ bool skipbreeding;
+
+ envStochParams env = paramsStoch->getStoch();
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ genomeData gen = pSpecies->getGenomeData();
+ simView v = paramsSim->getViews();
+
+ if (dem.repType == 0) nsexes = 1; else nsexes = 2;
+
+ // set up local copy of species fecundity table
+ float fec[NSTAGES][NSEXES];
+ for (int stg = 0; stg < sstruct.nStages; stg++) {
+ for (int sex = 0; sex < nsexes; sex++) {
+ if (dem.stageStruct) {
+ if (dem.repType == 1) { // simple sexual model
+ // both sexes use fecundity recorded for females
+ fec[stg][sex] = pSpecies->getFec(stg, 0);
+ }
+ else fec[stg][sex] = pSpecies->getFec(stg, sex);
+ }
+ else { // non-structured population
+ if (stg == 1) fec[stg][sex] = dem.lambda; // adults
+ else fec[stg][sex] = 0.0; // juveniles
+ }
+ }
+ }
+
+ if (dem.stageStruct) {
+ // apply environmental effects and density dependence
+ // to all non-zero female non-juvenile stages
+ for (int stg = 1; stg < nStages; stg++) {
+ if (fec[stg][0] > 0.0) {
+ // apply any effect of environmental gradient and/or stochasticty
+ fec[stg][0] *= envval;
+ if (env.stoch && !env.inK) {
+ // fecundity (at low density) is constrained to lie between limits specified
+ // for the species
+ float limit;
+ limit = pSpecies->getMinMax(0);
+ if (fec[stg][0] < limit) fec[stg][0] = limit;
+ limit = pSpecies->getMinMax(1);
+ if (fec[stg][0] > limit) fec[stg][0] = limit;
+ }
+ if (sstruct.fecDens) { // apply density dependence
+ float effect = 0.0;
+ if (sstruct.fecStageDens) { // stage-specific density dependence
+ // NOTE: matrix entries represent effect of ROW on COLUMN
+ // AND males precede females
+ float weight = 0.0;
+ for (int effstg = 0; effstg < nStages; effstg++) {
+ for (int effsex = 0; effsex < nSexes; effsex++) {
+ if (dem.repType == 2) {
+ if (effsex == 0) weight = pSpecies->getDDwtFec(2 * stg + 1, 2 * effstg + 1);
+ else weight = pSpecies->getDDwtFec(2 * stg + 1, 2 * effstg);
+ }
+ else {
+ weight = pSpecies->getDDwtFec(stg, effstg);
+ }
+ effect += (float)nInds[effstg][effsex] * weight;
+ }
+ }
+ }
+ else // not stage-specific
+ effect = (float)totalPop();
+ if (localK > 0.0) fec[stg][0] *= exp(-effect / localK);
+ }
+ }
+ }
+ }
+ else { // non-structured - set fecundity for adult females only
+ // apply any effect of environmental gradient and/or stochasticty
+ fec[1][0] *= envval;
+ if (env.stoch && !env.inK) {
+ // fecundity (at low density) is constrained to lie between limits specified
+ // for the species
+ float limit;
+ limit = pSpecies->getMinMax(0);
+ if (fec[1][0] < limit) fec[1][0] = limit;
+ limit = pSpecies->getMinMax(1);
+ if (fec[1][0] > limit) fec[1][0] = limit;
+ }
+ // apply density dependence
+ if (localK > 0.0) {
+ if (dem.repType == 1 || dem.repType == 2) { // sexual model
+ // apply factor of 2 (as in manual, eqn. 6)
+ fec[1][0] *= 2.0;
+ }
+ fec[1][0] /= (1.0f + fabs(dem.lambda - 1.0f) * pow(((float)ninds / localK), dem.bc));
+ }
+ }
+
+ double propBreed;
+ Individual* father;
+ std::vector fathers;
+
+ switch (dem.repType) {
+
+ case 0: // asexual model
+ for (int i = 0; i < ninds; i++) {
+ stage = inds[i]->breedingFem();
+ if (stage > 0) { // female of breeding age
+ if (dem.stageStruct) {
+ // determine whether she must miss current breeding attempt
+ ind = inds[i]->getStats();
+ if (ind.fallow >= sstruct.repInterval) {
+ if (pRandom->Bernoulli(sstruct.probRep)) skipbreeding = false;
+ else skipbreeding = true;
+ }
+ else skipbreeding = true; // cannot breed this time
+ }
+ else skipbreeding = false; // not structured - always breed
+ if (skipbreeding) {
+ inds[i]->incFallow();
+ }
+ else { // attempt to breed
+ inds[i]->resetFallow();
+ expected = fec[stage][0];
+ if (expected <= 0.0) njuvs = 0;
+ else njuvs = pRandom->Poisson(expected);
+ nj = (int)juvs.size();
+ pCell = pPatch->getRandomCell();
+ for (int j = 0; j < njuvs; j++) {
+#if RSDEBUG
+ // NOTE: CURRENTLY SETTING ALL INDIVIDUALS TO RECORD NO. OF STEPS ...
+ juvs.push_back(new Individual(pCell, pPatch, 0, 0, 0, 0.0, true, trfr.moveType));
+#else
+ juvs.push_back(new Individual(pCell, pPatch, 0, 0, 0, 0.0, trfr.moveModel, trfr.moveType));
+#endif
+ nInds[0][0]++;
+ if (emig.indVar || trfr.indVar || sett.indVar || gen.neutralMarkers)
+ {
+ // juv inherits genome from parent (mother)
+ juvs[nj + j]->setGenes(pSpecies, inds[i], 0, resol);
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case 1: // simple sexual model
+ case 2: // complex sexual model
+ // count breeding females and males
+ // add breeding males to list of potential fathers
+
+ nfemales = nmales = 0;
+ for (int i = 0; i < ninds; i++) {
+ ind = inds[i]->getStats();
+ if (ind.sex == 0 && fec[ind.stage][0] > 0.0) nfemales++;
+ if (ind.sex == 1 && fec[ind.stage][1] > 0.0) {
+ fathers.push_back(inds[i]);
+ nmales++;
+ }
+ }
+ if (nfemales > 0 && nmales > 0)
+ { // population can breed
+ if (dem.repType == 2) { // complex sexual model
+ // calculate proportion of eligible females which breed
+ propBreed = (2.0 * dem.harem * nmales) / (nfemales + dem.harem * nmales);
+ if (propBreed > 1.0) propBreed = 1.0;
+ }
+ else propBreed = 1.0;
+ for (int i = 0; i < ninds; i++) {
+ stage = inds[i]->breedingFem();
+ if (stage > 0 && fec[stage][0] > 0.0) { // (potential) breeding female
+ if (dem.stageStruct) {
+ // determine whether she must miss current breeding attempt
+ ind = inds[i]->getStats();
+ if (ind.fallow >= sstruct.repInterval) {
+ if (pRandom->Bernoulli(sstruct.probRep)) skipbreeding = false;
+ else skipbreeding = true;
+ }
+ else skipbreeding = true; // cannot breed this time
+ }
+ else skipbreeding = false; // not structured - always breed
+ if (skipbreeding) {
+ inds[i]->incFallow();
+ }
+ else { // attempt to breed
+ inds[i]->resetFallow();
+ // NOTE: FOR COMPLEX SEXUAL MODEL, NO. OF FEMALES *ACTUALLY* BREEDING DOES NOT
+ // NECESSARILY EQUAL THE EXPECTED NO. FROM EQN. 7 IN THE MANUAL...
+ if (pRandom->Bernoulli(propBreed)) {
+ expected = fec[stage][0]; // breeds
+ }
+ else expected = 0.0; // fails to breed
+ if (expected <= 0.0) njuvs = 0;
+ else njuvs = pRandom->Poisson(expected);
+ if (njuvs > 0)
+ {
+ nj = (int)juvs.size();
+ // select father at random from breeding males ...
+ int rrr = 0;
+ if (nmales > 1) rrr = pRandom->IRandom(0, nmales - 1);
+ father = fathers[rrr];
+ pCell = pPatch->getRandomCell();
+ for (int j = 0; j < njuvs; j++) {
+#if RSDEBUG
+ // NOTE: CURRENTLY SETTING ALL INDIVIDUALS TO RECORD NO. OF STEPS ...
+ juvs.push_back(new Individual(pCell, pPatch, 0, 0, 0, dem.propMales, true, trfr.moveType));
+#else
+ juvs.push_back(new Individual(pCell, pPatch, 0, 0, 0, dem.propMales, trfr.moveModel, trfr.moveType));
+#endif
+ sex = juvs[nj + j]->getSex();
+ nInds[0][sex]++;
+ if (emig.indVar || trfr.indVar || sett.indVar || gen.neutralMarkers)
+ {
+ // juv inherits genome from parents
+ juvs[nj + j]->setGenes(pSpecies, inds[i], father, resol);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ fathers.clear();
+ break;
+
+ } // end of switch (dem.repType)
+
+// THIS MAY NOT BE CORRECT FOR MULTIPLE SPECIES IF THERE IS SOME FORM OF
+// CROSS-SPECIES DENSITY-DEPENDENT FECUNDITY
+}
+
+// Following reproduction of ALL species, add juveniles to the population prior to dispersal
+void Population::fledge(void)
+{
+ demogrParams dem = pSpecies->getDemogr();
+
+ if (dem.stageStruct) { // juveniles are added to the individuals vector
+ inds.insert(inds.end(), juvs.begin(), juvs.end());
+ }
+ else { // all adults die and juveniles replace adults
+ int ninds = (int)inds.size();
+ for (int i = 0; i < ninds; i++) {
+ delete inds[i];
+ }
+ inds.clear();
+ for (int sex = 0; sex < nSexes; sex++) {
+ nInds[1][sex] = 0; // set count of adults to zero
+ }
+ inds = juvs;
+ }
+ juvs.clear();
+
+}
+
+// Determine which individuals will disperse
+void Population::emigration(float localK)
+{
+ int nsexes;
+ double disp, Pdisp, NK;
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+ emigRules emig = pSpecies->getEmig();
+ emigTraits eparams;
+ trfrRules trfr = pSpecies->getTrfr();
+ indStats ind;
+
+// to avoid division by zero, assume carrying capacity is at least one individual
+// localK can be zero if there is a moving gradient or stochasticity in K
+ if (localK < 1.0) localK = 1.0;
+ NK = (float)totalPop() / localK;
+
+ int ninds = (int)inds.size();
+
+ // set up local copy of emigration probability table
+ // used when there is no individual variability
+ // NB - IT IS DOUBTFUL THIS CONTRIBUTES ANY SUBSTANTIAL TIME SAVING
+ if (dem.repType == 0) nsexes = 1; else nsexes = 2;
+ double Pemig[NSTAGES][NSEXES];
+
+ for (int stg = 0; stg < sstruct.nStages; stg++) {
+ for (int sex = 0; sex < nsexes; sex++) {
+ if (emig.indVar) Pemig[stg][sex] = 0.0;
+ else {
+ if (emig.densDep) {
+ if (emig.sexDep) {
+ if (emig.stgDep) {
+ eparams = pSpecies->getEmigTraits(stg, sex);
+ }
+ else {
+ eparams = pSpecies->getEmigTraits(0, sex);
+ }
+ }
+ else { // !emig.sexDep
+ if (emig.stgDep) {
+ eparams = pSpecies->getEmigTraits(stg, 0);
+ }
+ else {
+ eparams = pSpecies->getEmigTraits(0, 0);
+ }
+ }
+ Pemig[stg][sex] = eparams.d0 / (1.0 + exp(-(NK - eparams.beta) * eparams.alpha));
+ }
+ else { // density-independent
+ if (emig.sexDep) {
+ if (emig.stgDep) {
+ Pemig[stg][sex] = pSpecies->getEmigD0(stg, sex);
+ }
+ else { // !emig.stgDep
+ Pemig[stg][sex] = pSpecies->getEmigD0(0, sex);
+ }
+ }
+ else { // !emig.sexDep
+ if (emig.stgDep) {
+ Pemig[stg][sex] = pSpecies->getEmigD0(stg, 0);
+ }
+ else { // !emig.stgDep
+ Pemig[stg][sex] = pSpecies->getEmigD0(0, 0);
+ }
+ }
+ }
+ } // end of !emig.indVar
+ }
+ }
+
+ for (int i = 0; i < ninds; i++) {
+ ind = inds[i]->getStats();
+ if (ind.status < 1)
+ {
+ if (emig.indVar) { // individual variability in emigration
+ if (dem.stageStruct && ind.stage != emig.emigStage) {
+ // emigration may not occur
+ Pdisp = 0.0;
+ }
+ else { // non-structured or individual is in emigration stage
+ eparams = inds[i]->getEmigTraits();
+ if (emig.densDep) { // density-dependent
+ NK = (float)totalPop() / localK;
+ Pdisp = eparams.d0 / (1.0 + exp(-(NK - eparams.beta) * eparams.alpha));
+ }
+ else { // density-independent
+ if (emig.sexDep) {
+ Pdisp = Pemig[0][ind.sex] + eparams.d0;
+ }
+ else {
+ Pdisp = Pemig[0][0] + eparams.d0;
+ }
+ }
+ }
+ } // end of individual variability
+ else { // no individual variability
+
+ if (emig.densDep) {
+ if (emig.sexDep) {
+ if (emig.stgDep) {
+ Pdisp = Pemig[ind.stage][ind.sex];
+ }
+ else {
+ Pdisp = Pemig[0][ind.sex];
+ }
+ }
+ else { // !emig.sexDep
+ if (emig.stgDep) {
+ Pdisp = Pemig[ind.stage][0];
+ }
+ else {
+ Pdisp = Pemig[0][0];
+ }
+ }
+ }
+ else { // density-independent
+ if (emig.sexDep) {
+ if (emig.stgDep) {
+ Pdisp = Pemig[ind.stage][ind.sex];
+ }
+ else { // !emig.stgDep
+ Pdisp = Pemig[0][ind.sex];
+ }
+ }
+ else { // !emig.sexDep
+ if (emig.stgDep) {
+ Pdisp = Pemig[ind.stage][0];
+ }
+ else { // !emig.stgDep
+ Pdisp = Pemig[0][0];
+ }
+ }
+ }
+
+
+ } // end of no individual variability
+
+ disp = pRandom->Bernoulli(Pdisp);
+
+ if (disp == 1) { // emigrant
+ inds[i]->setStatus(1);
+ }
+ } // end of if (ind.status < 1) condition
+ } // end of for loop
+}
+
+// All individuals emigrate after patch destruction
+void Population::allEmigrate(void) {
+ int ninds = (int)inds.size();
+ for (int i = 0; i < ninds; i++) {
+ inds[i]->setStatus(1);
+ }
+}
+
+// If an Individual has been identified as an emigrant, remove it from the Population
+disperser Population::extractDisperser(int ix) {
+ disperser d;
+ indStats ind = inds[ix]->getStats();
+ if (ind.status == 1) { // emigrant
+ d.pInd = inds[ix]; d.yes = true;
+ inds[ix] = 0;
+ nInds[ind.stage][ind.sex]--;
+ }
+ else {
+ d.pInd = NULL; d.yes = false;
+ }
+ return d;
+}
+
+// For an individual identified as being in the matrix population:
+// if it is a settler, return its new location and remove it from the current population
+// otherwise, leave it in the matrix population for possible reporting before deletion
+disperser Population::extractSettler(int ix) {
+ disperser d;
+ Cell* pCell;
+
+ indStats ind = inds[ix]->getStats();
+
+ pCell = inds[ix]->getLocn(1);
+ d.pInd = inds[ix]; d.pCell = pCell; d.yes = false;
+ if (ind.status == 4 || ind.status == 5) { // settled
+ d.yes = true;
+ inds[ix] = 0;
+ nInds[ind.stage][ind.sex]--;
+ }
+ return d;
+}
+
+// Add a specified individual to the new/current dispersal group
+// Add a specified individual to the population
+void Population::recruit(Individual* pInd) {
+ inds.push_back(pInd);
+ indStats ind = pInd->getStats();
+ nInds[ind.stage][ind.sex]++;
+}
+
+//---------------------------------------------------------------------------
+
+// Transfer is run for populations in the matrix only
+#if RS_RCPP // included also SEASONAL
+int Population::transfer(Landscape* pLandscape, short landIx, short nextseason)
+#else
+int Population::transfer(Landscape* pLandscape, short landIx)
+#endif
+{
+ int ndispersers = 0;
+ int disperser;
+ short othersex;
+ bool mateOK, densdepOK;
+ intptr patch, popn;
+ int patchnum;
+ double localK, popsize, settprob;
+ Patch* pPatch = 0;
+ Cell* pCell = 0;
+ indStats ind;
+ Population* pNewPopn = 0;
+ locn newloc, nbrloc;
+
+ landData ppLand = pLandscape->getLandData();
+ short reptype = pSpecies->getRepType();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType settletype = pSpecies->getSettle();
+ settleRules sett;
+ settleTraits settDD;
+ settlePatch settle;
+ simParams sim = paramsSim->getSim();
+
+ // each individual takes one step
+ // for dispersal by kernel, this should be the only step taken
+ int ninds = (int)inds.size();
+ for (int i = 0; i < ninds; i++) {
+ if (trfr.moveModel) {
+ disperser = inds[i]->moveStep(pLandscape, pSpecies, landIx, sim.absorbing);
+ }
+ else {
+ disperser = inds[i]->moveKernel(pLandscape, pSpecies, reptype, sim.absorbing);
+ }
+ ndispersers += disperser;
+ if (disperser) {
+ if (reptype > 0)
+ { // sexual species - record as potential settler in new patch
+ if (inds[i]->getStatus() == 2)
+ { // disperser has found a patch
+ pCell = inds[i]->getLocn(1);
+ patch = pCell->getPatch();
+ if (patch != 0) { // not no-data area
+ pPatch = (Patch*)patch;
+ pPatch->incrPossSettler(pSpecies, inds[i]->getSex());
+ }
+ }
+ }
+ }
+ }
+
+// each individual which has reached a potential patch decides whether to settle
+ for (int i = 0; i < ninds; i++) {
+ ind = inds[i]->getStats();
+ if (ind.sex == 0) othersex = 1; else othersex = 0;
+ if (settletype.stgDep) {
+ if (settletype.sexDep) sett = pSpecies->getSettRules(ind.stage, ind.sex);
+ else sett = pSpecies->getSettRules(ind.stage, 0);
+ }
+ else {
+ if (settletype.sexDep) sett = pSpecies->getSettRules(0, ind.sex);
+ else sett = pSpecies->getSettRules(0, 0);
+ }
+ if (ind.status == 2)
+ { // awaiting settlement
+ pCell = inds[i]->getLocn(1);
+ if (pCell == 0) {
+ // this condition can occur in a patch-based model at the time of a dynamic landscape
+ // change when there is a range restriction in place, since a patch can straddle the
+ // range restriction and an individual forced to disperse upon patch removal could
+ // start its trajectory beyond the boundary of the restrictyed range - such a model is
+ // not good practice, but the condition must be handled by killing the individual conceerned
+ ind.status = 6;
+ }
+ else {
+ mateOK = false;
+ if (sett.findMate) {
+ // determine whether at least one individual of the opposite sex is present in the
+ // new population
+ if (matePresent(pCell, othersex)) mateOK = true;
+ }
+ else { // no requirement to find a mate
+ mateOK = true;
+ }
+
+ densdepOK = false;
+ settle = inds[i]->getSettPatch();
+ if (sett.densDep)
+ {
+ patch = pCell->getPatch();
+ if (patch != 0) { // not no-data area
+ pPatch = (Patch*)patch;
+ if (settle.settleStatus == 0
+ || settle.pSettPatch != pPatch)
+ // note: second condition allows for having moved from one patch to another
+ // adjacent one
+ {
+ // determine whether settlement occurs in the (new) patch
+ localK = (double)pPatch->getK();
+ popn = pPatch->getPopn((intptr)pSpecies);
+ if (popn == 0) { // population has not been set up in the new patch
+ popsize = 0.0;
+ }
+ else {
+ pNewPopn = (Population*)popn;
+ popsize = (double)pNewPopn->totalPop();
+ }
+ if (localK > 0.0) {
+ // make settlement decision
+ if (settletype.indVar) settDD = inds[i]->getSettTraits();
+#if RS_RCPP
+ else settDD = pSpecies->getSettTraits(ind.stage, ind.sex);
+#else
+ else {
+ if (settletype.sexDep) {
+ if (settletype.stgDep)
+ settDD = pSpecies->getSettTraits(ind.stage, ind.sex);
+ else
+ settDD = pSpecies->getSettTraits(0, ind.sex);
+ }
+ else {
+ if (settletype.stgDep)
+ settDD = pSpecies->getSettTraits(ind.stage, 0);
+ else
+ settDD = pSpecies->getSettTraits(0, 0);
+ }
+ }
+#endif //RS_RCPP
+ settprob = settDD.s0 /
+ (1.0 + exp(-(popsize / localK - (double)settDD.beta) * (double)settDD.alpha));
+
+ if (pRandom->Bernoulli(settprob)) { // settlement allowed
+ densdepOK = true;
+ settle.settleStatus = 2;
+ }
+ else { // settlement procluded
+ settle.settleStatus = 1;
+ }
+ settle.pSettPatch = pPatch;
+ }
+ inds[i]->setSettPatch(settle);
+ }
+ else {
+ if (settle.settleStatus == 2) { // previously allowed to settle
+ densdepOK = true;
+ }
+ }
+ }
+ }
+ else { // no density-dependent settlement
+ densdepOK = true;
+ settle.settleStatus = 2;
+ settle.pSettPatch = pPatch;
+ inds[i]->setSettPatch(settle);
+ }
+
+ if (mateOK && densdepOK) { // can recruit to patch
+ ind.status = 4;
+ ndispersers--;
+ }
+ else { // does not recruit
+ if (trfr.moveModel) {
+ ind.status = 1; // continue dispersing, unless ...
+ // ... maximum steps has been exceeded
+ pathSteps steps = inds[i]->getSteps();
+ settleSteps settsteps = pSpecies->getSteps(ind.stage, ind.sex);
+ if (steps.year >= settsteps.maxStepsYr) {
+ ind.status = 3; // waits until next year
+ }
+ if (steps.total >= settsteps.maxSteps) {
+ ind.status = 6; // dies
+ }
+ }
+ else { // dispersal kernel
+ if (sett.wait) {
+ ind.status = 3; // wait until next dispersal event
+ }
+ else {
+ ind.status = 6; // (dies unless a neighbouring cell is suitable)
+ }
+ ndispersers--;
+ }
+ }
+ }
+
+ inds[i]->setStatus(ind.status);
+ }
+#if RS_RCPP
+ // write each individuals current movement step and status to paths file
+ if (trfr.moveModel && sim.outPaths) {
+ if (nextseason >= sim.outStartPaths && nextseason % sim.outIntPaths == 0) {
+ inds[i]->outMovePath(nextseason);
+ }
+ }
+#endif
+
+ if (!trfr.moveModel && sett.go2nbrLocn && (ind.status == 3 || ind.status == 6))
+ {
+ // for kernel-based transfer only ...
+ // determine whether recruitment to a neighbouring cell is possible
+
+ pCell = inds[i]->getLocn(1);
+ newloc = pCell->getLocn();
+ vector nbrlist;
+ for (int dx = -1; dx < 2; dx++) {
+ for (int dy = -1; dy < 2; dy++) {
+ if (dx != 0 || dy != 0) { //cell is not the current cell
+ nbrloc.x = newloc.x + dx; nbrloc.y = newloc.y + dy;
+ if (nbrloc.x >= 0 && nbrloc.x <= ppLand.maxX
+ && nbrloc.y >= 0 && nbrloc.y <= ppLand.maxY) { // within landscape
+ // add to list of potential neighbouring cells if suitable, etc.
+ pCell = pLandscape->findCell(nbrloc.x, nbrloc.y);
+ if (pCell != 0) { // not no-data area
+ patch = pCell->getPatch();
+ if (patch != 0) { // not no-data area
+ pPatch = (Patch*)patch;
+ patchnum = pPatch->getPatchNum();
+ if (patchnum > 0 && pPatch != inds[i]->getNatalPatch())
+ { // not the matrix or natal patch
+ if (pPatch->getK() > 0.0)
+ { // suitable
+ if (sett.findMate) {
+ if (matePresent(pCell, othersex)) nbrlist.push_back(pCell);
+ }
+ else
+ nbrlist.push_back(pCell);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ int listsize = (int)nbrlist.size();
+ if (listsize > 0) { // there is at least one suitable neighbouring cell
+ if (listsize == 1) {
+ inds[i]->moveto(nbrlist[0]);
+ }
+ else { // select at random from the list
+ int rrr = pRandom->IRandom(0, listsize - 1);
+ inds[i]->moveto(nbrlist[rrr]);
+ }
+ }
+ // else list empty - do nothing - individual retains its current location and status
+ }
+ }
+ return ndispersers;
+}
+
+// Determine whether there is a potential mate present in a patch which a potential
+// settler has reached
+bool Population::matePresent(Cell* pCell, short othersex)
+{
+ int patch;
+ Patch* pPatch;
+ Population* pNewPopn;
+ int popsize = 0;
+ bool matefound = false;
+
+ patch = (int)pCell->getPatch();
+ if (patch != 0) {
+ pPatch = (Patch*)pCell->getPatch();
+ if (pPatch->getPatchNum() > 0) { // not the matrix patch
+ if (pPatch->getK() > 0.0)
+ { // suitable
+ pNewPopn = (Population*)pPatch->getPopn((intptr)pSpecies);
+ if (pNewPopn != 0) {
+ // count members of other sex already resident in the patch
+ for (int stg = 0; stg < nStages; stg++) {
+ popsize += pNewPopn->nInds[stg][othersex];
+ }
+ }
+ if (popsize < 1) {
+ // add any potential settlers of the other sex
+ popsize += pPatch->getPossSettlers(pSpecies, othersex);
+ }
+ }
+ }
+ }
+ if (popsize > 0) matefound = true;
+ return matefound;
+}
+
+//---------------------------------------------------------------------------
+// Determine survival and development and record in individual's status code
+// Changes are NOT applied to the Population at this stage
+
+// FOR MULTIPLE SPECIES, MAY NEED TO SEPARATE OUT THIS IDENTIFICATION STAGE,
+// SO THAT IT CAN BE PERFORMED FOR ALL SPECIES BEFORE ANY UPDATING OF POPULATIONS
+
+void Population::survival0(float localK, short option0, short option1)
+{
+ // option0: 0 - stage 0 (juveniles) only
+ // 1 - all stages
+ // 2 - stage 1 and above (all non-juveniles)
+ // option1: 0 - development only (when survival is annual)
+ // 1 - development and survival
+ // 2 - survival only (when survival is annual)
+
+ densDepParams ddparams = pSpecies->getDensDep();
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+
+ // get surrent population size
+ int ninds = (int)inds.size();
+ if (ninds == 0) return;
+
+ // set up local copies of species development and survival tables
+ int nsexes;
+ if (dem.repType == 0) nsexes = 1; else nsexes = 2;
+ float dev[NSTAGES][NSEXES];
+ float surv[NSTAGES][NSEXES];
+ short minAge[NSTAGES][NSEXES];
+ for (int stg = 0; stg < sstruct.nStages; stg++) {
+ for (int sex = 0; sex < nsexes; sex++) {
+ if (dem.stageStruct) {
+ if (dem.repType == 1) { // simple sexual model
+ // both sexes use development and survival recorded for females
+ dev[stg][sex] = pSpecies->getDev(stg, 0);
+ surv[stg][sex] = pSpecies->getSurv(stg, 0);
+ minAge[stg][sex] = pSpecies->getMinAge(stg, 0);
+ }
+ else {
+ dev[stg][sex] = pSpecies->getDev(stg, sex);
+ surv[stg][sex] = pSpecies->getSurv(stg, sex);
+ minAge[stg][sex] = pSpecies->getMinAge(stg, sex);
+ }
+ if (option1 == 0) surv[stg][sex] = 1.0; // development only - all survive
+ if (option1 == 2) dev[stg][sex] = 0.0; // survival only - none develops
+ }
+ else { // non-structured population
+ if (stg == 1) { // adults
+ dev[stg][sex] = 0.0; surv[stg][sex] = 0.0; minAge[stg][sex] = 0;
+ }
+ else { // juveniles
+ dev[stg][sex] = 1.0; surv[stg][sex] = 1.0; minAge[stg][sex] = 0;
+ }
+ }
+ }
+ }
+
+ if (dem.stageStruct) {
+ // apply density dependence in development and/or survival probabilities
+ for (int stg = 0; stg < nStages; stg++) {
+ for (int sex = 0; sex < nsexes; sex++) {
+ if (option1 != 2 && sstruct.devDens && stg > 0) {
+ // NB DD in development does NOT apply to juveniles,
+ // which must develop to stage 1 if they survive
+ float effect = 0.0;
+ if (sstruct.devStageDens) { // stage-specific density dependence
+ // NOTE: matrix entries represent effect of ROW on COLUMN
+ // AND males precede females
+ float weight = 0.0;
+ for (int effstg = 0; effstg < nStages; effstg++) {
+ for (int effsex = 0; effsex < nSexes; effsex++) {
+ if (dem.repType == 2) {
+ int rowincr, colincr;
+ if (effsex == 0) rowincr = 1; else rowincr = 0;
+ if (sex == 0) colincr = 1; else colincr = 0;
+ weight = pSpecies->getDDwtDev(2 * stg + colincr, 2 * effstg + rowincr);
+ }
+ else {
+ weight = pSpecies->getDDwtDev(stg, effstg);
+ }
+ effect += (float)nInds[effstg][effsex] * weight;
+ }
+ }
+ }
+ else // not stage-specific
+ effect = (float)totalPop();
+ if (localK > 0.0)
+ dev[stg][sex] *= exp(-(ddparams.devCoeff * effect) / localK);
+ } // end of if (sstruct.devDens && stg > 0)
+ if (option1 != 0 && sstruct.survDens) {
+ float effect = 0.0;
+ if (sstruct.survStageDens) { // stage-specific density dependence
+ // NOTE: matrix entries represent effect of ROW on COLUMN
+ // AND males precede females
+ float weight = 0.0;
+ for (int effstg = 0; effstg < nStages; effstg++) {
+ for (int effsex = 0; effsex < nSexes; effsex++) {
+ if (dem.repType == 2) {
+ int rowincr, colincr;
+ if (effsex == 0) rowincr = 1; else rowincr = 0;
+ if (sex == 0) colincr = 1; else colincr = 0;
+ weight = pSpecies->getDDwtSurv(2 * stg + colincr, 2 * effstg + rowincr);
+ }
+ else {
+ weight = pSpecies->getDDwtSurv(stg, effstg);
+ }
+ effect += (float)nInds[effstg][effsex] * weight;
+ }
+ }
+ }
+ else // not stage-specific
+ effect = (float)totalPop();
+ if (localK > 0.0)
+ surv[stg][sex] *= exp(-(ddparams.survCoeff * effect) / localK);
+ } // end of if (sstruct.survDens)
+ }
+ }
+ }
+
+ // identify which individuals die or develop
+ for (int i = 0; i < ninds; i++) {
+ indStats ind = inds[i]->getStats();
+ if ((ind.stage == 0 && option0 < 2) || (ind.stage > 0 && option0 > 0)) {
+ // condition for processing the stage is met...
+ if (ind.status < 6) { // not already doomed
+ double probsurv = surv[ind.stage][ind.sex];
+ // does the individual survive?
+ if (pRandom->Bernoulli(probsurv)) { // survives
+ // does the individual develop?
+ double probdev = dev[ind.stage][ind.sex];
+ if (ind.stage < nStages - 1) { // not final stage
+ if (ind.age >= minAge[ind.stage + 1][ind.sex]) { // old enough to enter next stage
+ if (pRandom->Bernoulli(probdev)) {
+ inds[i]->developing();
+ }
+ }
+ }
+ }
+ else { // doomed to die
+ inds[i]->setStatus(8);
+ }
+ }
+ }
+ }
+}
+
+// Apply survival changes to the population
+void Population::survival1(void)
+{
+
+ int ninds = (int)inds.size();
+ for (int i = 0; i < ninds; i++) {
+ indStats ind = inds[i]->getStats();
+ if (ind.status > 5) { // doomed to die
+ delete inds[i];
+ inds[i] = NULL;
+ nInds[ind.stage][ind.sex]--;
+ }
+ else {
+ if (ind.isDeveloping) { // develops to next stage
+ nInds[ind.stage][ind.sex]--;
+ inds[i]->develop();
+ nInds[ind.stage + 1][ind.sex]++;
+ }
+ }
+ }
+
+// remove pointers to dead individuals
+ clean();
+}
+
+void Population::ageIncrement(void) {
+ int ninds = (int)inds.size();
+ stageParams sstruct = pSpecies->getStage();
+ for (int i = 0; i < ninds; i++) {
+ inds[i]->ageIncrement(sstruct.maxAge);
+ }
+}
+
+//---------------------------------------------------------------------------
+// Remove zero pointers to dead or dispersed individuals
+void Population::clean(void)
+{
+ int ninds = (int)inds.size();
+ if (ninds > 0) {
+ // ALTERNATIVE METHOD: AVOIDS SLOW SORTING OF POPULATION
+ std::vector survivors; // all surviving individuals
+ for (int i = 0; i < ninds; i++) {
+ if (inds[i] != NULL) {
+ survivors.push_back(inds[i]);
+ }
+ }
+ inds.clear();
+ inds = survivors;
+#if RS_RCPP
+ shuffle(inds.begin(), inds.end(), pRandom->getRNG());
+#else
+
+#if !RSDEBUG
+ // do not randomise individuals in RSDEBUG mode, as the function uses rand()
+ // and therefore the randomisation will differ between identical runs of RS
+ shuffle(inds.begin(), inds.end(), pRandom->getRNG());
+#endif // !RSDEBUG
+
+#endif // RS_RCPP
+ }
+}
+
+//---------------------------------------------------------------------------
+// Open population file and write header record
+bool Population::outPopHeaders(int landNr, bool patchModel) {
+
+ if (landNr == -999) { // close file
+ if (outPop.is_open()) outPop.close();
+ outPop.clear();
+ return true;
+ }
+
+ string name;
+ simParams sim = paramsSim->getSim();
+ envGradParams grad = paramsGrad->getGradient();
+
+ // NEED TO REPLACE CONDITIONAL COLUMNS BASED ON ATTRIBUTES OF ONE SPECIES TO COVER
+ // ATTRIBUTES OF *ALL* SPECIES AS DETECTED AT MODEL LEVEL
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+
+ if (sim.batchMode) {
+ name = paramsSim->getDir(2)
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation) + "_Land" + Int2Str(landNr) + "_Pop.txt";
+ }
+ else {
+ name = paramsSim->getDir(2) + "Sim" + Int2Str(sim.simulation) + "_Pop.txt";
+ }
+ outPop.open(name.c_str());
+ outPop << "Rep\tYear\tRepSeason";
+ if (patchModel) outPop << "\tPatchID\tNcells";
+ else outPop << "\tx\ty";
+ // determine whether environmental data need be written for populations
+ bool writeEnv = false;
+ if (grad.gradient) writeEnv = true;
+ if (paramsStoch->envStoch()) writeEnv = true;
+ if (writeEnv) outPop << "\tEpsilon\tGradient\tLocal_K";
+ outPop << "\tSpecies\tNInd";
+ if (dem.stageStruct) {
+ if (dem.repType == 0)
+ {
+ for (int i = 1; i < sstruct.nStages; i++) outPop << "\tNInd_stage" << i;
+ outPop << "\tNJuvs";
+ }
+ else {
+ for (int i = 1; i < sstruct.nStages; i++)
+ outPop << "\tNfemales_stage" << i << "\tNmales_stage" << i;
+ outPop << "\tNJuvFemales\tNJuvMales";
+ }
+ }
+ else {
+ if (dem.repType != 0) outPop << "\tNfemales\tNmales";
+ }
+ outPop << endl;
+
+ return outPop.is_open();
+}
+
+//---------------------------------------------------------------------------
+// Write record to population file
+void Population::outPopulation(int rep, int yr, int gen, float eps,
+ bool patchModel, bool writeEnv, bool gradK)
+{
+ Cell* pCell;
+// NEED TO REPLACE CONDITIONAL COLUMNS BASED ON ATTRIBUTES OF ONE SPECIES TO COVER
+// ATTRIBUTES OF *ALL* SPECIES AS DETECTED AT MODEL LEVEL
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+ popStats p;
+
+ outPop << rep << "\t" << yr << "\t" << gen;
+ if (patchModel) {
+ outPop << "\t" << pPatch->getPatchNum();
+ outPop << "\t" << pPatch->getNCells();
+ }
+ else {
+ locn loc = pPatch->getCellLocn(0);
+ outPop << "\t" << loc.x << "\t" << loc.y;
+ }
+ if (writeEnv) {
+ if (pPatch->getPatchNum() == 0) { // matrix
+ outPop << "\t0\t0\t0";
+ }
+ else {
+ float k = pPatch->getK();
+ float envval = 0.0;
+ pCell = pPatch->getRandomCell();
+ if (pCell != 0) envval = pCell->getEnvVal();
+ outPop << "\t" << eps << "\t" << envval << "\t" << k;
+ }
+ }
+ outPop << "\t" << pSpecies->getSpNum();
+ if (dem.stageStruct) {
+ p = getStats();
+ outPop << "\t" << p.nNonJuvs;
+ // non-juvenile stage totals from permanent array
+ for (int stg = 1; stg < nStages; stg++) {
+ for (int sex = 0; sex < nSexes; sex++) {
+ outPop << "\t" << nInds[stg][sex];
+ }
+ }
+ // juveniles from permanent array
+ for (int sex = 0; sex < nSexes; sex++) {
+ outPop << "\t" << nInds[0][sex];
+ }
+ }
+ else { // non-structured population
+ outPop << "\t" << totalPop();
+ if (dem.repType != 0)
+ { // sexual model
+ outPop << "\t" << nInds[1][0] << "\t" << nInds[1][1];
+ }
+ }
+ outPop << endl;
+}
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+// Open individuals file and write header record
+void Population::outIndsHeaders(int rep, int landNr, bool patchModel)
+{
+
+ if (landNr == -999) { // close file
+ if (outInds.is_open()) {
+ outInds.close(); outInds.clear();
+ }
+ return;
+ }
+
+ string name;
+ demogrParams dem = pSpecies->getDemogr();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ simParams sim = paramsSim->getSim();
+
+ if (sim.batchMode) {
+ name = paramsSim->getDir(2)
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation)
+ + "_Land" + Int2Str(landNr) + "_Rep" + Int2Str(rep) + "_Inds.txt";
+ }
+ else {
+ name = paramsSim->getDir(2) + "Sim" + Int2Str(sim.simulation)
+ + "_Rep" + Int2Str(rep) + "_Inds.txt";
+ }
+ outInds.open(name.c_str());
+
+ outInds << "Rep\tYear\tRepSeason\tSpecies\tIndID\tStatus";
+ if (patchModel) outInds << "\tNatal_patch\tPatchID";
+ else outInds << "\tNatal_X\tNatal_Y\tX\tY";
+ if (dem.repType != 0) outInds << "\tSex";
+ if (dem.stageStruct) outInds << "\tAge\tStage";
+ if (emig.indVar) {
+ if (emig.densDep) outInds << "\tD0\tAlpha\tBeta";
+ else outInds << "\tEP";
+ }
+ if (trfr.indVar) {
+ if (trfr.moveModel) {
+ if (trfr.moveType == 1) { // SMS
+ outInds << "\tDP\tGB\tAlphaDB\tBetaDB";
+ }
+ if (trfr.moveType == 2) { // CRW
+ outInds << "\tStepLength\tRho";
+ }
+ }
+ else { // kernel
+ outInds << "\tMeanDistI";
+ if (trfr.twinKern) outInds << "\tMeanDistII\tPKernelI";
+ }
+ }
+ if (sett.indVar) {
+ outInds << "\tS0\tAlphaS\tBetaS";
+ }
+ outInds << "\tDistMoved";
+#if RSDEBUG
+ // ALWAYS WRITE NO. OF STEPS
+ outInds << "\tNsteps";
+#else
+ if (trfr.moveModel) outInds << "\tNsteps";
+#endif
+ outInds << endl;
+}
+
+//---------------------------------------------------------------------------
+// Write records to individuals file
+void Population::outIndividual(Landscape* pLandscape, int rep, int yr, int gen,
+ int patchNum)
+{
+ //int x, y, p_id;
+ bool writeInd;
+ pathSteps steps;
+ Cell* pCell;
+
+ landParams ppLand = pLandscape->getLandParams();
+ demogrParams dem = pSpecies->getDemogr();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ short spNum = pSpecies->getSpNum();
+
+ int ninds = (int)inds.size();
+
+ for (int i = 0; i < ninds; i++) {
+ indStats ind = inds[i]->getStats();
+ if (yr == -1) { // write all initialised individuals
+ writeInd = true;
+ outInds << rep << "\t" << yr << "\t" << dem.repSeasons - 1;
+ }
+ else {
+ if (dem.stageStruct && gen < 0) { // write status 9 individuals only
+ if (ind.status == 9) {
+ writeInd = true;
+ outInds << rep << "\t" << yr << "\t" << dem.repSeasons - 1;
+ }
+ else writeInd = false;
+ }
+ else {
+ writeInd = true;
+ outInds << rep << "\t" << yr << "\t" << gen;
+ }
+ }
+ if (writeInd) {
+ outInds << "\t" << spNum << "\t" << inds[i]->getId();
+ if (dem.stageStruct) outInds << "\t" << ind.status;
+ else { // non-structured population
+ outInds << "\t" << ind.status;
+ }
+ pCell = inds[i]->getLocn(1);
+ locn loc;
+ if (pCell == 0) loc.x = loc.y = -1; // beyond boundary or in no-data cell
+ else loc = pCell->getLocn();
+ pCell = inds[i]->getLocn(0);
+ locn natalloc = pCell->getLocn();
+ if (ppLand.patchModel) {
+ outInds << "\t" << inds[i]->getNatalPatch()->getPatchNum();
+ if (loc.x == -1) outInds << "\t-1";
+ else outInds << "\t" << patchNum;
+ }
+ else { // cell-based model
+ outInds << "\t" << (float)natalloc.x << "\t" << natalloc.y;
+ outInds << "\t" << (float)loc.x << "\t" << (float)loc.y;
+ }
+ if (dem.repType != 0) outInds << "\t" << ind.sex;
+ if (dem.stageStruct) outInds << "\t" << ind.age << "\t" << ind.stage;
+
+ if (emig.indVar) {
+ emigTraits e = inds[i]->getEmigTraits();
+ if (emig.densDep) {
+ outInds << "\t" << e.d0 << "\t" << e.alpha << "\t" << e.beta;
+ }
+ else {
+ outInds << "\t" << e.d0;
+ }
+ } // end of if (emig.indVar)
+
+ if (trfr.indVar) {
+ if (trfr.moveModel) {
+ if (trfr.moveType == 1) { // SMS
+ trfrSMSTraits s = inds[i]->getSMSTraits();
+ outInds << "\t" << s.dp << "\t" << s.gb;
+ outInds << "\t" << s.alphaDB << "\t" << s.betaDB;
+ } // end of SMS
+ if (trfr.moveType == 2) { // CRW
+ trfrCRWTraits c = inds[i]->getCRWTraits();
+ outInds << "\t" << c.stepLength << "\t" << c.rho;
+ } // end of CRW
+ }
+ else { // kernel
+ trfrKernTraits k = inds[i]->getKernTraits();
+ if (trfr.twinKern)
+ {
+ outInds << "\t" << k.meanDist1 << "\t" << k.meanDist2 << "\t" << k.probKern1;
+ }
+ else {
+ outInds << "\t" << k.meanDist1;
+ }
+ }
+ }
+
+ if (sett.indVar) {
+ settleTraits s = inds[i]->getSettTraits();
+ outInds << "\t" << s.s0 << "\t" << s.alpha << "\t" << s.beta;
+ }
+
+ // distance moved (metres)
+ if (loc.x == -1) outInds << "\t-1";
+ else {
+ float d = ppLand.resol * sqrt((float)((natalloc.x - loc.x) * (natalloc.x - loc.x)
+ + (natalloc.y - loc.y) * (natalloc.y - loc.y)));
+ outInds << "\t" << d;
+ }
+#if RSDEBUG
+ // ALWAYS WRITE NO. OF STEPS
+ steps = inds[i]->getSteps();
+ outInds << "\t" << steps.year;
+#else
+ if (trfr.moveModel) {
+ steps = inds[i]->getSteps();
+ outInds << "\t" << steps.year;
+ }
+#endif
+ outInds << endl;
+ } // end of writeInd condition
+ }
+}
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+// Write records to genetics file
+void Population::outGenetics(const int rep, const int year, const int landNr)
+{
+
+ simParams sim = paramsSim->getSim();
+
+ if (landNr >= 0) { // open file
+ Genome* pGenome;
+ genomeData gen = pSpecies->getGenomeData();
+ if (gen.trait1Chromosome) {
+ pGenome = new Genome(pSpecies->getNChromosomes(), pSpecies->getNLoci(0),
+ pSpecies->isDiploid());
+ }
+ else {
+ pGenome = new Genome(pSpecies);
+ }
+ pGenome->outGenHeaders(rep, landNr, sim.outGenXtab);
+ delete pGenome;
+ return;
+ }
+
+ if (landNr == -999) { // close file
+ Genome* pGenome = new Genome();
+ pGenome->outGenHeaders(rep, landNr, sim.outGenXtab);
+ delete pGenome;
+ return;
+ }
+
+ short spNum = pSpecies->getSpNum();
+ short nstages = 1;
+ if (pSpecies->stageStructured()) {
+ stageParams sstruct = pSpecies->getStage();
+ nstages = sstruct.nStages;
+ }
+
+ int ninds = (int)inds.size();
+ for (int i = 0; i < ninds; i++) {
+ indStats ind = inds[i]->getStats();
+ if (year == 0 || sim.outGenType == 1
+ || (sim.outGenType == 0 && ind.stage == 0)
+ || (sim.outGenType == 2 && ind.stage == nstages - 1)) {
+ inds[i]->outGenetics(rep, year, spNum, landNr, sim.outGenXtab);
+ }
+ }
+
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+
diff --git a/src/RScore/Population.h b/src/RScore/Population.h
new file mode 100644
index 00000000..fd1fa660
--- /dev/null
+++ b/src/RScore/Population.h
@@ -0,0 +1,245 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 Population
+
+Implements the Population class
+
+There is ONE instance of a Population for each Species within each SubCommunity
+(including the matrix). The Population holds a list of all the Individuals in
+the Population.
+
+The matrix Population(s) hold(s) Individuals which are currently in the process
+of transfer through the matrix.
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Peer G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 22 January 2022 by Steve Palmer
+
+------------------------------------------------------------------------------*/
+
+#ifndef PopulationH
+#define PopulationH
+
+#include
+#include
+using namespace std;
+
+#include "Parameters.h"
+#include "Individual.h"
+#include "Species.h"
+#include "Landscape.h"
+#include "Patch.h"
+#include "Cell.h"
+
+//---------------------------------------------------------------------------
+
+struct popStats {
+ Species *pSpecies; Patch *pPatch; int spNum,nInds,nNonJuvs,nAdults; bool breeding;
+};
+struct disperser {
+ Individual *pInd; Cell *pCell; bool yes;
+};
+struct traitsums { // sums of trait genes for dispersal
+ int ninds[NSEXES]; // no. of individuals
+ double sumD0[NSEXES]; // sum of maximum emigration probability
+ double ssqD0[NSEXES]; // sum of squares of maximum emigration probability
+ double sumAlpha[NSEXES]; // sum of slope of emigration dens-dep reaction norm
+ double ssqAlpha[NSEXES]; // sum of squares of slope of emigration den-dep reaction norm
+ double sumBeta[NSEXES]; // sum of inflection point of emigration reaction norm
+ double ssqBeta[NSEXES]; // sum of squares of inflection point of emigration reaction norm
+ double sumDist1[NSEXES]; // sum of kernel I mean
+ double ssqDist1[NSEXES]; // sum of squares of kernel I mean
+ double sumDist2[NSEXES]; // sum of kernel II mean
+ double ssqDist2[NSEXES]; // sum of squares of kernel II mean
+ double sumProp1[NSEXES]; // sum of propn using kernel I
+ double ssqProp1[NSEXES]; // sum of squares of propn using kernel I
+ double sumDP[NSEXES]; // sum of SMS directional persistence
+ double ssqDP[NSEXES]; // sum of squares of SMS directional persistence
+ double sumGB[NSEXES]; // sum of SMS goal bias
+ double ssqGB[NSEXES]; // sum of squares of SMS goal bias
+ double sumAlphaDB[NSEXES]; // sum of SMS dispersal bias decay rate
+ double ssqAlphaDB[NSEXES]; // sum of squares of SMS dispersal bias decay rate
+ double sumBetaDB[NSEXES]; // sum of SMS dispersal bias decay infl. pt.
+ double ssqBetaDB[NSEXES]; // sum of squares of SMS dispersal bias decay infl. pt.
+ double sumStepL[NSEXES]; // sum of CRW step length
+ double ssqStepL[NSEXES]; // sum of squares of CRW step length
+ double sumRho[NSEXES]; // sum of CRW correlation coefficient
+ double ssqRho[NSEXES]; // sum of squares of CRW correlation coefficient
+ double sumS0[NSEXES]; // sum of maximum settlement probability
+ double ssqS0[NSEXES]; // sum of squares of maximum settlement probability
+ double sumAlphaS[NSEXES]; // sum of slope of settlement den-dep reaction norm
+ double ssqAlphaS[NSEXES]; // sum of squares of slope of settlement den-dep reaction norm
+ double sumBetaS[NSEXES]; // sum of inflection point of settlement reaction norm
+ double ssqBetaS[NSEXES]; // sum of squares of inflection point of settlement reaction norm
+};
+
+class Population {
+
+public:
+ Population(void); // default constructor
+ Population( // constructor for a Population of a specified size
+ Species*, // pointer to Species
+ Patch*, // pointer to Patch
+ int, // no. of Individuals
+ int // Landscape resolution
+ );
+ ~Population(void);
+ traitsums getTraits(Species*);
+ popStats getStats(void);
+ Species* getSpecies(void);
+ int getNInds(void);
+ int totalPop(void);
+ int stagePop( // return no. of Individuals in a specified stage
+ int // stage
+ );
+ void extirpate(void); // Remove all individuals
+ void reproduction(
+ const float, // local carrying capacity
+ const float, // effect of environmental gradient and/or stochasticty
+ const int // Landscape resolution
+ );
+ // Following reproduction of ALL species, add juveniles to the population
+ void fledge(void);
+ void emigration( // Determine which individuals will disperse
+ float // local carrying capacity
+ );
+ void allEmigrate(void); // All individuals emigrate after patch destruction
+ // If an individual has been identified as an emigrant, remove it from the Population
+ disperser extractDisperser(
+ int // index no. to the Individual in the inds vector
+ );
+ // For an individual identified as being in the matrix population:
+ // if it is a settler, return its new location and remove it from the current population
+ // otherwise, leave it in the matrix population for possible reporting before deletion
+ disperser extractSettler(
+ int // index no. to the Individual in the inds vector
+ );
+ void recruit( // Add a specified individual to the population
+ Individual* // pointer to Individual
+ );
+#if RS_RCPP
+ int transfer( // Executed for the Population(s) in the matrix only
+ Landscape*, // pointer to Landscape
+ short, // landscape change index
+ short // year
+ );
+ // Determine whether there is a potential mate present in a patch which a potential
+ // settler has reached
+ bool matePresent(
+ Cell*, // pointer to the Cell which the potential settler has reached
+ short // sex of the required mate (0 = female, 1 = male)
+ );
+#else
+ int transfer( // Executed for the Population(s) in the matrix only
+ Landscape*, // pointer to Landscape
+ short // landscape change index
+ );
+ // Determine whether there is a potential mate present in a patch which a potential
+ // settler has reached
+ bool matePresent(
+ Cell*, // pointer to the Cell which the potential settler has reached
+ short // sex of the required mate (0 = female, 1 = male)
+ );
+#endif // RS_RCPP
+ // Determine survival and development and record in individual's status code
+ // Changes are NOT applied to the Population at this stage
+ void survival0(
+ float, // local carrying capacity
+ short, // option0: 0 - stage 0 (juveniles) only
+ // 1 - all stages
+ // 2 - stage 1 and above (all non-juveniles)
+ short // option1: 0 - development only (when survival is annual)
+ // 1 - development and survival
+ // 2 - survival only (when survival is annual)
+ );
+ void survival1(void); // Apply survival changes to the population
+ void ageIncrement(void);
+ bool outPopHeaders( // Open population file and write header record
+ int, // Landscape number (-999 to close the file)
+ bool // TRUE for a patch-based model, FALSE for a cell-based model
+ );
+ void outPopulation( // Write record to population file
+ int, // replicate
+ int, // year
+ int, // generation
+ float, // epsilon - global stochasticity value
+ bool, // TRUE for a patch-based model, FALSE for a cell-based model
+ bool, // TRUE to write environmental data
+ bool // TRUE if there is a gradient in carrying capacity
+ );
+
+ void outIndsHeaders( // Open individuals file and write header record
+ int, // replicate
+ int, // Landscape number (-999 to close the file)
+ bool // TRUE for a patch-based model, FALSE for a cell-based model
+ );
+ void outIndividual( // Write records to individuals file
+ Landscape*, // pointer to Landscape
+ int, // replicate
+ int, // year
+ int, // generation
+ int // Patch number
+ );
+ void outGenetics( // Write records to genetics file
+ const int, // replicate
+ const int, // year
+ const int // landscape number
+ );
+ void clean(void); // Remove zero pointers to dead or dispersed individuals
+
+private:
+ short nStages;
+ short nSexes;
+ Species *pSpecies; // pointer to the species
+ Patch *pPatch; // pointer to the patch
+ int nInds[NSTAGES][NSEXES]; // no. of individuals in each stage/sex
+
+ std::vector inds; // all individuals in population except ...
+ std::vector juvs; // ... juveniles until reproduction of ALL species
+ // has been completed
+
+};
+
+//---------------------------------------------------------------------------
+
+extern paramGrad *paramsGrad;
+extern paramStoch *paramsStoch;
+extern paramInit *paramsInit;
+extern paramSim *paramsSim;
+extern RSrandom *pRandom;
+
+#if RSDEBUG
+extern ofstream DEBUGLOG;
+#endif
+
+//---------------------------------------------------------------------------
+#endif
+
diff --git a/src/RScore/README.md b/src/RScore/README.md
new file mode 100644
index 00000000..3056fe0c
--- /dev/null
+++ b/src/RScore/README.md
@@ -0,0 +1,72 @@
+# RangeShifter core code
+
+This repo contains the core simulation code for RangeShifter v2.0 and is not meant to be compiled or run on its own.
+
+
+
+If you are only interested in using RangeShifter, you can ignore this and head to the repo of one of the interfaces:
+
+- [WIP] RangeShifter GUI
+
+- [RangeShiftR](https://github.com/RangeShifter/RangeShiftR-pkg)
+
+- [RangeShifter-batch](https://github.com/RangeShifter/RangeShifter_batch)
+
+## Usage: git subtree
+
+In order to ensure that the same version of RangeShifter's core code is used by all three interfaces (RangeShiftR, RangeShifter-batch and the GUI), each interface repo keeps a copy of RScore as a git subtree. In this section, we describe how to use the git subtrees to update the subfolder and copy this repo anew.
+
+First, in a local clone of one of the interface repos, add a remote named `RScore` pointing to the RScore repo. This will be convenient as a shortcut for git subtree commands.
+
+```bash
+git remote add RScore https://github.com/RangeShifter/RScore.git
+```
+
+### Pulling new changes
+
+To update the RScore subfolder with new changes made to the RScore repo, one can use the `git subtree pull` command:
+
+```bash
+git subtree pull --prefix RScore
+```
+
+Note the path must match the location of the RScore subfolder, and the branch must match the one the subtree was originally added from (by default, this should be `main`).
+
+e.g. for RangeShifter-batch, use:
+
+```bash
+git subtree pull --prefix src/RScore RScore main
+```
+
+while for RangeShiftR, use:
+
+```bash
+git subtree pull --prefix RangeShiftR/src/RScore RScore main
+```
+
+### Pushing new changes to RScore
+
+We haven't yet found a way to push new changes made in a RScore subfolder back into the RScore repo. This is why we ask that contributions are made directly inside the RScore repo.
+
+If you know how to do this, please drop us a line!
+
+Alternatively, if you have already made changes on the subfolder, you could copy its contents into a new branch in RScore, then open a pull request.
+
+### Switching the subfolder to a new branch
+
+There is unfortunately to do so. To track a different branch of RScore, one must delete the RScore subfolder (via git) and import the subtree again:
+
+```bash
+git rm src/RScore -r
+git commit -m "switching subtree branch"
+git subtree add --prefix src/RScore RScore
+```
+
+## Contributing to RangeShifter core code
+
+See [CONTRIBUTING](https://github.com/RangeShifter/RScore/blob/main/CONTRIBUTING.md).
+
+## Maintainers
+
+- [@JetteReeg](https://github.com/JetteReeg)
+- [@TheoPannetier](https://github.com/TheoPannetier)
diff --git a/src/RScore/RS_repos.png b/src/RScore/RS_repos.png
new file mode 100644
index 00000000..b138a015
Binary files /dev/null and b/src/RScore/RS_repos.png differ
diff --git a/src/RScore/RScore_logo.png b/src/RScore/RScore_logo.png
new file mode 100644
index 00000000..dfce2675
Binary files /dev/null and b/src/RScore/RScore_logo.png differ
diff --git a/src/RScore/RSrandom.cpp b/src/RScore/RSrandom.cpp
new file mode 100644
index 00000000..1b9f5234
--- /dev/null
+++ b/src/RScore/RSrandom.cpp
@@ -0,0 +1,283 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+#include "RSrandom.h"
+
+//--------------- 2.) New version of RSrandom.cpp
+
+#if !RS_RCPP
+
+#if RSDEBUG
+#include "Parameters.h"
+extern paramSim* paramsSim;
+// ofstream RSRANDOMLOG;
+#endif
+
+int RS_random_seed = 0;
+
+// C'tor
+RSrandom::RSrandom()
+{
+#if RSDEBUG
+ // fixed seed
+ RS_random_seed = 666;
+#else
+ // random seed
+#if LINUX_CLUSTER
+ std::random_device device;
+ RS_random_seed = device(); // old versions of g++ on Windows return a constant value within a given Windows
+ // session; in this case better use time stamp
+#else
+ RS_random_seed = std::time(NULL);
+#endif
+#endif // RSDEBUG
+
+#if BATCH && RSDEBUG
+ DEBUGLOG << "RSrandom::RSrandom(): RS_random_seed=" << RS_random_seed << endl;
+#endif // RSDEBUG
+
+ // set up Mersenne Twister RNG
+ gen = new mt19937(RS_random_seed);
+
+ // Set up standard uniform distribution
+ pRandom01 = new uniform_real_distribution(0.0, 1.0);
+ // Set up standard normal distribution
+ pNormal = new normal_distribution(0.0, 1.0);
+}
+
+RSrandom::~RSrandom(void)
+{
+ delete gen;
+ if(pRandom01 != 0)
+ delete pRandom01;
+ if(pNormal != 0)
+ delete pNormal;
+}
+
+mt19937 RSrandom::getRNG(void)
+{
+ return *gen;
+}
+
+double RSrandom::Random(void)
+{
+ // return random number between 0 and 1
+ return pRandom01->operator()(*gen);
+}
+
+int RSrandom::IRandom(int min, int max)
+{
+ // return random integer in the interval min <= x <= max
+ uniform_int_distribution unif(min, max);
+ return unif(*gen);
+}
+
+int RSrandom::Bernoulli(double p)
+{
+ if (p < 0) throw runtime_error("Bernoulli's p cannot be negative.\n");
+ if (p > 1) throw runtime_error("Bernoulli's p cannot be above 1.\n");
+ return Random() < p;
+}
+
+double RSrandom::Normal(double mean, double sd)
+{
+ return mean + sd * pNormal->operator()(*gen);
+}
+
+int RSrandom::Poisson(double mean)
+{
+ poisson_distribution poiss(mean);
+ return poiss(*gen);
+}
+
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+#else // if RS_RCPP
+
+//--------------- 3.) R package version of RSrandom.cpp
+
+ #if RSDEBUG
+ #include "Parameters.h"
+ extern paramSim *paramsSim;
+ //ofstream RSRANDOMLOG;
+ #endif
+
+ std::uint32_t RS_random_seed = 0;
+
+ // C'tor
+ // if parameter seed is negative, a random seed will be generated, else it is used as seed
+ RSrandom::RSrandom(std::int64_t seed)
+ {
+ // get seed
+ std::vector random_seed(3);
+ random_seed[0] = 1967593562;
+ random_seed[1] = 3271254416;
+ if (seed < 0) {
+ // random seed
+ #if RSWIN64
+ random_seed[2] = std::time(NULL) + ( seed * (-17) );
+ #else
+ std::random_device device;
+ random_seed[2] = device();
+ #endif
+ #if BATCH && RSDEBUG
+ DEBUGLOG << "RSrandom::RSrandom(): Generated random seed = ";
+ #endif
+ }
+ else{
+ // fixed seed
+ random_seed[2] = seed;
+ #if BATCH && RSDEBUG
+ DEBUGLOG << "RSrandom::RSrandom(): Use fixed seed = ";
+ #endif
+ }
+
+ RS_random_seed = random_seed[2];
+ #if BATCH && RSDEBUG
+ DEBUGLOG << RS_random_seed << endl;
+ #endif
+
+ // set up Mersenne Twister random number generator with seed sequence
+ std::seed_seq seq(random_seed.begin(),random_seed.end());
+ gen = new mt19937(seq);
+
+ // Set up standard uniform distribution
+ pRandom01 = new uniform_real_distribution (0.0,1.0);
+ // Set up standard normal distribution
+ pNormal = new normal_distribution (0.0,1.0);
+ }
+
+ RSrandom::~RSrandom(void) {
+ delete gen;
+ if (pRandom01 != 0) delete pRandom01;
+ if (pNormal != 0) delete pNormal;
+ }
+
+ mt19937 RSrandom::getRNG(void) {
+ // return random number generator
+ return *gen;
+ }
+
+ double RSrandom::Random(void) {
+ // return random number between 0 and 1
+ return pRandom01->operator()(*gen);
+ }
+
+ int RSrandom::IRandom(int min,int max) {
+ // return random integer in the interval min <= x <= max
+ uniform_int_distribution unif(min,max);
+ return unif(*gen);
+ }
+
+ int RSrandom::Bernoulli(double p) {
+ if (p < 0) throw runtime_error("Bernoulli's p cannot be negative.\n");
+ if (p > 1) throw runtime_error("Bernoulli's p cannot be above 1.\n");
+ return Random() < p;
+ }
+
+ double RSrandom::Normal(double mean,double sd) {
+ return mean + sd * pNormal->operator()(*gen);
+ }
+
+ int RSrandom::Poisson(double mean) {
+ poisson_distribution poiss(mean);
+ return poiss(*gen);
+ }
+
+
+ /* ADDITIONAL DISTRIBUTIONS
+
+ // Beta distribution - sample from two gamma distributions
+ double RSrandom::Beta(double p0,double p1) {
+ double g0,g1,beta;
+ if (p0 > 0.0 && p1 > 0.0) { // valid beta parameters
+ gamma_distribution gamma0(p0,1.0);
+ gamma_distribution gamma1(p1,1.0);
+ g0 = gamma0(*gen);
+ g1 = gamma1(*gen);
+ beta = g0 / (g0 + g1);
+ }
+ else { // return invalid value
+ beta = -666.0;
+ }
+ return beta;
+ }
+
+ // Gamma distribution
+ double RSrandom::Gamma(double p0,double p1) { // using shape (=p0) and scale (=p1)
+ double p2,gamma;
+ if (p0 > 0.0 && p1 > 0.0) { // valid gamma parameters
+ p2 = 1.0 / p1;
+ gamma_distribution gamma0(p0,p2); // using shape/alpha (=p0) and rate/beta (=p2=1/p1)
+ gamma = gamma0(*gen);
+ }
+ else { // return invalid value
+ gamma = -666.0;
+ }
+ return gamma;
+ }
+
+ // Cauchy distribution
+ double RSrandom::Cauchy(double loc, double scale) {
+ double res;
+ if (scale > 0.0) { // valid scale parameter
+ cauchy_distribution cauchy(loc,scale);
+ res = cauchy(*gen);
+ }
+ else { // return invalid value
+ res = -666.0;
+ }
+ return res;
+ }
+
+
+ */
+
+#endif // RS_RCPP
+
+
+#if RSDEBUG
+ void testRSrandom() {
+
+ {
+ // Bernoulli distribution
+ // Abuse cases
+ assert_error("Bernoulli's p cannot be negative.\n", []{
+ RSrandom rsr;
+ rsr.Bernoulli(-0.3);
+ });
+ assert_error("Bernoulli's p cannot be above 1.\n", [] {
+ RSrandom rsr;
+ rsr.Bernoulli(1.1);
+ });
+ // Use cases
+ RSrandom rsr;
+ assert(rsr.Bernoulli(0) == 0);
+ assert(rsr.Bernoulli(1) == 1);
+ int bern_trial = rsr.Bernoulli(0.5);
+ assert(bern_trial == 0 || bern_trial == 1);
+ }
+ }
+#endif // RSDEBUG
+//---------------------------------------------------------------------------
diff --git a/src/RScore/RSrandom.h b/src/RScore/RSrandom.h
new file mode 100644
index 00000000..97672456
--- /dev/null
+++ b/src/RScore/RSrandom.h
@@ -0,0 +1,131 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 RSrandom
+
+Implements the RSrandom class
+
+Authors: Steve Palmer, University of Aberdeen
+ Anne-Kathleen Malchow, Potsdam University
+
+Last updated: 12 January 2021 by Steve Palmer
+
+------------------------------------------------------------------------------*/
+
+#ifndef RSrandomH
+#define RSrandomH
+
+#include
+#include
+#include
+#include "Utils.h"
+
+using namespace std;
+
+#if RSDEBUG
+extern ofstream DEBUGLOG;
+#endif
+
+#if !RS_RCPP
+//--------------- 2.) New version of RSrandom.cpp
+ #include
+ #include
+ #if !LINUX_CLUSTER
+ #include
+ #endif
+
+ class RSrandom
+ {
+
+ public:
+ RSrandom(void);
+ ~RSrandom(void);
+ double Random(void);
+ int IRandom(int, int);
+ int Bernoulli(double);
+ double Normal(double, double);
+ int Poisson(double);
+ mt19937 getRNG(void);
+
+ private:
+ mt19937* gen;
+ std::uniform_real_distribution<>* pRandom01;
+ std::normal_distribution<>* pNormal;
+ };
+
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+
+
+//--------------- 3.) R package version of RSrandom.cpp
+
+
+#else // if RS_RCPP
+
+
+ #include
+ #include
+ #if RSWIN64
+ #include
+ #endif
+
+ class RSrandom {
+
+ public:
+ RSrandom(std::int64_t); // if int is negative, a random seed will be generated, else it is used as seed
+ ~RSrandom(void);
+ mt19937 getRNG(void);
+ double Random(void);
+ int IRandom(int,int);
+ int Bernoulli(double);
+ double Normal(double,double);
+ int Poisson(double);
+ /* ADDITIONAL DISTRIBUTIONS
+ double Beta(double,double);
+ double Gamma(double,double); // !! make sure correct definition is used: using shape and scale (as defined here) OR using shape/alpha and rate/beta (=1/scale)
+ double Cauchy(double,double);
+ */
+
+ private:
+ mt19937 *gen;
+ std::uniform_real_distribution<> *pRandom01;
+ std::normal_distribution<> *pNormal;
+ };
+
+
+
+#endif // !RS_RCPP
+
+#if RSDEBUG
+ void testRSrandom();
+#endif // RSDEBUG
+
+//---------------------------------------------------------------------------
+
+#endif // RSrandomH
+
+
+
diff --git a/src/RScore/RandomCheck.cpp b/src/RScore/RandomCheck.cpp
new file mode 100644
index 00000000..e18aeaaa
--- /dev/null
+++ b/src/RScore/RandomCheck.cpp
@@ -0,0 +1,93 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+//---------------------------------------------------------------------------
+
+#include "RandomCheck.h"
+//---------------------------------------------------------------------------
+
+ifstream inRandom;
+ofstream outRandom;
+ofstream outBernoulli;
+ofstream outNormal;
+ofstream outPoisson;
+ofstream outIRandom;
+
+void randomCheck(void)
+{
+
+int samplesize,irandMin,irandMax;
+double bernMean,normMean,normSD,poisMean;
+string name,header;
+simParams sim = paramsSim->getSim();
+
+ name = paramsSim->getDir(1) + "RandomCheck.txt";
+ inRandom.open(name.c_str());
+ if (!inRandom.is_open()) {
+ #if !RS_RCPP
+ cout << endl << "***** Error opening input file RandomCheck.txt" << endl;
+ #endif
+ inRandom.clear();
+ return;
+ }
+ for (int i = 0; i < 7; i++) {
+ inRandom >> header;
+ }
+ inRandom >> samplesize >> bernMean >> normMean >> normSD >> poisMean >> irandMin >> irandMax;
+
+ name = paramsSim->getDir(2) + "Random.txt";
+ outRandom.open(name.c_str());
+ name = paramsSim->getDir(2) + "Bernoulli.txt";
+ outBernoulli.open(name.c_str());
+ name = paramsSim->getDir(2) + "Normal.txt";
+ outNormal.open(name.c_str());
+ name = paramsSim->getDir(2) + "Poisson.txt";
+ outPoisson.open(name.c_str());
+ name = paramsSim->getDir(2) + "IRandom.txt";
+ outIRandom.open(name.c_str());
+
+ for (int i = 0; i < samplesize; i++) {
+ outRandom << pRandom->Random() << endl;
+ outBernoulli << pRandom->Bernoulli(bernMean) << endl;
+ outNormal << pRandom->Normal(normMean,normSD) << endl;
+ outPoisson << pRandom->Poisson(poisMean) << endl;
+ outIRandom << pRandom->IRandom(irandMin,irandMax) << endl;
+ }
+
+ inRandom.close();
+ inRandom.clear();
+ outRandom.close();
+ outRandom.clear();
+ outBernoulli.close();
+ outBernoulli.clear();
+ outNormal.close();
+ outNormal.clear();
+ outPoisson.close();
+ outPoisson.clear();
+ outIRandom.close();
+ outIRandom.clear();
+
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
diff --git a/src/RScore/RandomCheck.h b/src/RScore/RandomCheck.h
new file mode 100644
index 00000000..b4992d25
--- /dev/null
+++ b/src/RScore/RandomCheck.h
@@ -0,0 +1,40 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+//---------------------------------------------------------------------------
+
+#ifndef RandomCheckH
+#define RandomCheckH
+
+#include
+using namespace std;
+
+#include "Parameters.h"
+#include "RSrandom.h"
+
+void randomCheck(void);
+
+extern paramSim *paramsSim;
+extern RSrandom *pRandom;
+
+//---------------------------------------------------------------------------
+#endif
diff --git a/src/RScore/Species.cpp b/src/RScore/Species.cpp
new file mode 100644
index 00000000..0be29ca4
--- /dev/null
+++ b/src/RScore/Species.cpp
@@ -0,0 +1,1365 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+ //---------------------------------------------------------------------------
+
+#include "Species.h"
+//---------------------------------------------------------------------------
+
+Species::Species(void)
+{
+ // initialise demographic parameters
+ repType = 0; nStages = 2;
+ stageStruct = false;
+ propMales = 0.5; harem = 1.0; bc = 1.0; lambda = 1.5; probRep = 1.0;
+ repSeasons = 1;
+ repInterval = 0; maxAge = 1000; survival = 1;
+ fecDens = false; fecStageDens = false;
+ devDens = false; devStageDens = false;
+ survDens = false; survStageDens = false;
+ disperseOnLoss = false;
+ for (int i = 0; i < NSTAGES; i++) {
+ for (int j = 0; j < NSEXES; j++) {
+ fec[i][j] = 0.0; dev[i][j] = 0.0; surv[i][j] = 0.0;
+ minAge[i][j] = 0;
+ }
+ }
+ devCoeff = survCoeff = 1.0;
+ ddwtFec = ddwtDev = ddwtSurv = 0; ddwtFecDim = ddwtDevDim = ddwtSurvDim = 0;
+ habK = 0; habDimK = 0;
+ minRK = 1.0; maxRK = 2.0;
+
+ // initialise genome attributes
+ nChromosomes = nTraits = 0;
+ emigTrait[0] = 0; emigTrait[1] = 0;
+ movtTrait[0] = 0; movtTrait[1] = 0;
+ settTrait[0] = 0; settTrait[1] = 0;
+ diploid = true;
+ neutralMarkers = false;
+ pleiotropic = false;
+ trait1Chromosome = true;
+ probMutn = 0.0001f;
+ probCrossover = 0.0001f;
+ alleleSD = mutationSD = 0.1f;
+ nNLoci = 0;
+ nLoci = NULL;
+ traitdata = NULL;
+ traitnames = NULL;
+ nTraitNames = 0;
+
+ // initialise emigration parameters
+ densDepEmig = false; stgDepEmig = false; sexDepEmig = false; indVarEmig = false;
+ emigStage = 0;
+ for (int i = 0; i < NSTAGES; i++) {
+ for (int j = 0; j < NSEXES; j++) {
+ d0[i][j] = 0.0; alphaEmig[i][j] = 0.0; betaEmig[i][j] = 1.0;
+ }
+ }
+ for (int j = 0; j < NSEXES; j++) {
+ d0Mean[0][j] = 0.0; alphaMean[0][j] = 0.0; betaMean[0][j] = 1.0;
+ d0SD[0][j] = 0.0; alphaSD[0][j] = 0.0; betaSD[0][j] = 1.0;
+ }
+ d0Scale = alphaScale = betaScale = 0.0;
+
+ // initialise transfer parameters
+ moveModel = false; stgDepTrfr = false; sexDepTrfr = false; distMort = false;
+ indVarTrfr = false;
+ twinKern = false;
+ habMort = false;
+ costMap = false;
+ moveType = 1;
+ for (int i = 0; i < NSTAGES; i++) {
+ for (int j = 0; j < NSEXES; j++) {
+ meanDist1[i][j] = 100.0f; meanDist2[i][j] = 1000.0f; probKern1[i][j] = 0.99f;
+ }
+ }
+ for (int j = 0; j < NSEXES; j++) {
+ dist1Mean[0][j] = 100.0; dist1SD[0][j] = 10.0;
+ dist2Mean[0][j] = 1000.0; dist2SD[0][j] = 100.0;
+ PKern1Mean[0][j] = 0.9f; PKern1SD[0][j] = 0.01f;
+ stepLgthMean[0][j] = 10.0; stepLgthSD[0][j] = 1.0;
+ rhoMean[0][j] = 0.9f; rhoSD[0][j] = 0.01f;
+ dpMean[0][j] = 1.0; dpSD[0][j] = 0.1f;
+ gbMean[0][j] = 1.0; gbSD[0][j] = 0.1f;
+ alphaDBMean[0][j] = 1.0; alphaDBSD[0][j] = 0.1f;
+ betaDBMean[0][j] = 10.0; betaDBSD[0][j] = 1.0;
+ }
+ pr = 1; prMethod = 1; memSize = 1; goalType = 0;
+ dp = 1.0; gb = 1.0; alphaDB = 1.0; betaDB = 100000;
+ stepMort = 0.0; stepLength = 10.0; rho = 0.9f;
+ habStepMort = 0; habCost = 0;
+ fixedMort = 0.0; mortAlpha = 0.0; mortBeta = 1.0;
+ dist1Scale = dist2Scale = PKern1Scale = stepLScale = rhoScale = 0.0;
+ dpScale = 0.1f; gbScale = 0.1f; alphaDBScale = 0.1f; betaDBScale = 1.0;
+ habDimTrfr = 0;
+ straigtenPath = false;
+ fullKernel = false;
+
+ // initialise settlement parameters
+ stgDepSett = false; sexDepSett = false; indVarSett = false;
+ minSteps = 0; maxSteps = 99999999;
+ for (int i = 0; i < NSTAGES; i++) {
+ for (int j = 0; j < NSEXES; j++) {
+ densDepSett[i][j] = false; wait[i][j] = false; go2nbrLocn[i][j] = false; findMate[i][j] = false;
+ maxStepsYr[i][j] = 99999999;
+ s0[i][j] = 1.0; alphaS[i][j] = 0.0; betaS[i][j] = 1.0;
+ }
+ }
+ for (int j = 0; j < NSEXES; j++) {
+ alphaSMean[0][j] = 0.0; alphaSSD[0][j] = 0.0;
+ betaSMean[0][j] = 0.0; betaSSD[0][j] = 0.0;
+ s0Mean[0][j] = 0.0; s0SD[0][j] = 0.0;
+ }
+ alphaSScale = 0.0; betaSScale = 0.0; s0Scale = 0.0;
+
+ // initialise attributes
+ spNum = 0;
+
+}
+
+Species::~Species() {
+ // demographic parameters
+ if (habK != NULL) deleteHabK();
+ if (ddwtFec != 0) deleteDDwtFec();
+ if (ddwtDev != 0) deleteDDwtDev();
+ if (ddwtSurv != 0) deleteDDwtSurv();
+ // transfer parameters
+ if (habCost != 0 || habStepMort != 0) deleteHabCostMort();
+ if (nLoci != NULL) deleteLoci();
+ if (traitdata != NULL) deleteTraitData();
+ if (traitnames != NULL) deleteTraitNames();
+}
+
+short Species::getSpNum(void) { return spNum; }
+
+//---------------------------------------------------------------------------
+
+// Demographic functions
+
+void Species::setDemogr(const demogrParams d) {
+ if (d.repType >= 0 && d.repType <= 2) repType = d.repType;
+ if (d.repSeasons >= 1) repSeasons = d.repSeasons;
+ stageStruct = d.stageStruct;
+ if (d.propMales > 0.0 && d.propMales < 1.0) propMales = d.propMales;
+ if (d.harem > 0.0) harem = d.harem;
+ if (d.bc > 0.0) bc = d.bc;
+ if (d.lambda > 0.0) lambda = d.lambda;
+}
+
+demogrParams Species::getDemogr(void) {
+ demogrParams d;
+ d.repType = repType;
+ d.repSeasons = repSeasons;
+ d.stageStruct = stageStruct;
+ d.propMales = propMales;
+ d.harem = harem;
+ d.bc = bc;
+ d.lambda = lambda;
+ return d;
+}
+
+short Species::getRepType(void) { return repType; }
+
+bool Species::stageStructured(void) { return stageStruct; }
+
+void Species::createHabK(short nhab) {
+ if (nhab >= 0) {
+ habDimK = nhab;
+ if (habK != 0) deleteHabK();
+ habK = new float[nhab];
+ for (int i = 0; i < nhab; i++) habK[i] = 0.0;
+ }
+}
+
+void Species::setHabK(short hx, float k) {
+ if (hx >= 0 && hx < habDimK) {
+ if (k >= 0.0) habK[hx] = k;
+ }
+}
+
+float Species::getHabK(short hx) {
+ float k = 0.0;
+ if (hx >= 0 && hx < habDimK) k = habK[hx];
+ return k;
+}
+
+float Species::getMaxK(void) {
+ float k = 0.0;
+ for (int i = 0; i < habDimK; i++) {
+ if (habK[i] > k) k = habK[i];
+ }
+ return k;
+}
+
+void Species::deleteHabK(void) {
+ if (habK != 0) {
+ delete[] habK; habK = 0;
+ }
+}
+
+void Species::setStage(const stageParams s) {
+ if (s.nStages > 1) nStages = s.nStages;
+ if (s.repInterval >= 0) repInterval = s.repInterval;
+ if (s.maxAge >= 1) maxAge = s.maxAge;
+ if (s.survival >= 0 && s.survival <= 2) survival = s.survival;
+ if (s.probRep > 0.0 && s.probRep <= 1.0) probRep = s.probRep;
+ fecDens = s.fecDens; fecStageDens = s.fecStageDens;
+ devDens = s.devDens; devStageDens = s.devStageDens;
+ survDens = s.survDens; survStageDens = s.survStageDens;
+ disperseOnLoss = s.disperseOnLoss;
+}
+
+stageParams Species::getStage(void) {
+ stageParams s;
+ s.nStages = nStages; s.repInterval = repInterval; s.maxAge = maxAge;
+ s.survival = survival; s.probRep = probRep;
+ s.fecDens = fecDens; s.fecStageDens = fecStageDens;
+ s.devDens = devDens; s.devStageDens = devStageDens;
+ s.survDens = survDens; s.survStageDens = survStageDens;
+ s.disperseOnLoss = disperseOnLoss;
+ return s;
+}
+
+void Species::setFec(short stg, short sex, float f) {
+ // NB fecundity for stage 0 must always be zero
+ if (stg > 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES && f >= 0)
+ fec[stg][sex] = f;
+}
+
+float Species::getFec(short stg, short sex) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES)
+ return fec[stg][sex];
+ else return 0.0;
+}
+
+float Species::getMaxFec(void) {
+ float maxfec = 0.0;
+ if (stageStruct) {
+ for (int stg = 1; stg < NSTAGES; stg++) {
+ if (fec[stg][0] > maxfec) maxfec = fec[stg][0];
+ }
+ }
+ else maxfec = lambda;
+ return maxfec;
+}
+
+void Species::setDev(short stg, short sex, float d) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES && d >= 0)
+ dev[stg][sex] = d;
+}
+
+float Species::getDev(short stg, short sex) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES)
+ return dev[stg][sex];
+ else return 0.0;
+}
+
+void Species::setSurv(short stg, short sex, float s) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES && s >= 0)
+ surv[stg][sex] = s;
+}
+
+float Species::getSurv(short stg, short sex) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES)
+ return surv[stg][sex];
+ else return 0.0;
+}
+
+void Species::setMinAge(short stg, short sex, int age) {
+ // NB min age for stages 0 & 1 must always be zero
+ if (stg > 1 && stg < NSTAGES && sex >= 0 && sex < NSEXES && age >= 0)
+ minAge[stg][sex] = age;
+}
+
+short Species::getMinAge(short stg, short sex) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES)
+ return minAge[stg][sex];
+ else return 0;
+}
+
+void Species::setDensDep(float d, float s) {
+ if (d > 0.0) devCoeff = d;
+ if (s > 0.0) survCoeff = s;
+}
+
+densDepParams Species::getDensDep(void) {
+ densDepParams d;
+ d.devCoeff = devCoeff; d.survCoeff = survCoeff;
+ return d;
+}
+
+void Species::createDDwtFec(short mSize) {
+ if (mSize >= 0 && mSize < (NSTAGES * NSEXES)) {
+ if (ddwtFec != 0) deleteDDwtFec();
+ ddwtFecDim = mSize;
+ ddwtFec = new float* [mSize];
+ for (int i = 0; i < mSize; i++) {
+ ddwtFec[i] = new float[mSize];
+ for (int j = 0; j < mSize; j++) ddwtFec[i][j] = 1.0;
+ }
+ }
+}
+
+void Species::setDDwtFec(short row, short col, float f) {
+ if (row >= 0 && row < ddwtFecDim && col >= 0 && col < ddwtFecDim)
+ ddwtFec[row][col] = f;
+}
+
+float Species::getDDwtFec(short row, short col) {
+ if (row >= 0 && row < ddwtFecDim && col >= 0 && col < ddwtFecDim)
+ return ddwtFec[row][col];
+ else return 0.0;
+}
+
+void Species::deleteDDwtFec(void) {
+ if (ddwtFec != 0) {
+ for (int i = 0; i < ddwtFecDim; i++) if (ddwtFec[i] != 0) {
+ delete[] ddwtFec[i];
+ }
+ delete[] ddwtFec; ddwtFec = 0;
+ }
+}
+
+void Species::createDDwtDev(short mSize) {
+ if (mSize >= 0 && mSize < (NSTAGES * NSEXES)) {
+ if (ddwtDev != 0) deleteDDwtDev();
+ ddwtDevDim = mSize;
+ ddwtDev = new float* [mSize];
+ for (int i = 0; i < mSize; i++) {
+ ddwtDev[i] = new float[mSize];
+ for (int j = 0; j < mSize; j++) ddwtDev[i][j] = 1.0;
+ }
+ }
+}
+
+void Species::setDDwtDev(short row, short col, float f) {
+ if (row >= 0 && row < ddwtDevDim && col >= 0 && col < ddwtDevDim)
+ ddwtDev[row][col] = f;
+}
+
+float Species::getDDwtDev(short row, short col) {
+ if (row >= 0 && row < ddwtDevDim && col >= 0 && col < ddwtDevDim)
+ return ddwtDev[row][col];
+ else return 0.0;
+}
+
+void Species::deleteDDwtDev(void) {
+ if (ddwtDev != 0) {
+ for (int i = 0; i < ddwtDevDim; i++) if (ddwtDev[i] != 0) {
+ delete[] ddwtDev[i];
+ }
+ delete[] ddwtDev; ddwtDev = 0;
+ }
+}
+
+void Species::createDDwtSurv(short mSize) {
+ if (mSize >= 0 && mSize < (NSTAGES * NSEXES)) {
+ if (ddwtSurv != 0) deleteDDwtSurv();
+ ddwtSurvDim = mSize;
+ ddwtSurv = new float* [mSize];
+ for (int i = 0; i < mSize; i++) {
+ ddwtSurv[i] = new float[mSize];
+ for (int j = 0; j < mSize; j++) ddwtSurv[i][j] = 1.0;
+ }
+ }
+}
+
+void Species::setDDwtSurv(short row, short col, float f) {
+ if (row >= 0 && row < ddwtSurvDim && col >= 0 && col < ddwtSurvDim)
+ ddwtSurv[row][col] = f;
+}
+
+float Species::getDDwtSurv(short row, short col) {
+ if (row >= 0 && row < ddwtSurvDim && col >= 0 && col < ddwtSurvDim)
+ return ddwtSurv[row][col];
+ else return 0.0;
+}
+
+void Species::deleteDDwtSurv(void) {
+ if (ddwtSurv != 0) {
+ for (int i = 0; i < ddwtSurvDim; i++) if (ddwtSurv[i] != 0) {
+ delete[] ddwtSurv[i];
+ }
+ delete[] ddwtSurv; ddwtSurv = 0;
+ }
+}
+
+// Functions to handle min/max R or K (under environmental stochasticity)
+void Species::setMinMax(float min, float max) {
+ if (min >= 0.0 && max > min) {
+ minRK = min; maxRK = max;
+ }
+}
+float Species::getMinMax(short opt) {
+ if (opt == 0) return minRK;
+ else return maxRK;
+}
+
+//---------------------------------------------------------------------------
+
+// Genome functions
+
+void Species::setGenomeData(genomeData d) {
+ diploid = d.diploid;
+ neutralMarkers = d.neutralMarkers;
+ trait1Chromosome = d.trait1Chromosome;
+ if (trait1Chromosome) {
+ if (d.nLoci > 0) nLoci[0] = d.nLoci;
+ }
+ if (d.probMutn >= 0.0 && d.probMutn <= 1.0) probMutn = d.probMutn;
+ if (d.probCrossover >= 0.0 && d.probCrossover <= 1.0) probCrossover = d.probCrossover;
+ if (d.alleleSD > 0.0) alleleSD = d.alleleSD;
+ if (d.mutationSD > 0.0) mutationSD = d.mutationSD;
+}
+
+genomeData Species::getGenomeData(void) {
+ genomeData d;
+ d.diploid = diploid;
+ d.neutralMarkers = neutralMarkers;
+ d.pleiotropic = pleiotropic;
+ d.trait1Chromosome = trait1Chromosome;
+ if (nLoci != NULL) d.nLoci = nLoci[0];
+ else d.nLoci = 0;
+ d.probMutn = probMutn;
+ d.probCrossover = probCrossover;
+ d.alleleSD = alleleSD;
+ d.mutationSD = mutationSD;
+ return d;
+}
+
+bool Species::isDiploid(void) { return diploid; }
+
+// Chromosome functions
+
+void Species::setNChromosomes(int c) {
+ if (nLoci != NULL) deleteLoci();
+ if (c > 0) {
+ nChromosomes = nNLoci = c;
+ nLoci = new short[c];
+ for (int i = 0; i < nNLoci; i++) nLoci[i] = 0;
+ }
+ else nChromosomes = nNLoci = 0;
+}
+
+int Species::getNChromosomes(void) { return nChromosomes; }
+
+void Species::setNLoci(const short chr, const short nloc) {
+ if (chr >= 0 && chr < nNLoci) {
+ if (nloc > 0) nLoci[chr] = nloc;
+ else nLoci[chr] = 0;
+ }
+}
+
+int Species::getNLoci(const short chr) {
+ if (chr >= 0 && chr < nChromosomes) return nLoci[chr];
+ else return 0;
+}
+
+void Species::deleteLoci(void) {
+ if (nLoci != NULL) { delete[] nLoci; nLoci = NULL; }
+}
+
+// Trait functions
+
+// Set 1:1 mapping of trait to chromosome
+void Species::set1ChromPerTrait(const int nloc) {
+ nChromosomes = nTraits;
+ if (nLoci != NULL) deleteLoci();
+ nLoci = new short[1];
+ if (nloc > 0) nLoci[0] = nloc;
+ else nLoci[0] = 1;
+}
+
+bool Species::has1ChromPerTrait(void) { return trait1Chromosome; }
+
+// Set trait attributes for the species
+void Species::setTraits(void) {
+
+ emigTrait[0] = 0; emigTrait[1] = 0;
+ movtTrait[0] = 0; movtTrait[1] = 0;
+ settTrait[0] = 0; settTrait[1] = 0;
+ nTraits = 0;
+#if RSDEBUG
+ DebugGUI("Species::setTraits(): 0000 nChromosomes=" + Int2Str(nChromosomes)
+ + " nTraits=" + Int2Str(nTraits)
+ + " indVarEmig=" + Int2Str((int)indVarEmig)
+ + " indVarTrfr=" + Int2Str((int)indVarTrfr)
+ + " indVarSett=" + Int2Str((int)indVarSett)
+ );
+#endif
+
+ if (indVarEmig) {
+ if (sexDepEmig) {
+ if (densDepEmig) nTraits += 6; else nTraits += 2;
+ }
+ else {
+ if (densDepEmig) nTraits += 3; else nTraits += 1;
+ }
+ emigTrait[0] = 0; emigTrait[1] = nTraits;
+ }
+
+ int movttraits = 0;
+ if (indVarTrfr) {
+ if (moveModel) {
+ if (moveType == 1) { // SMS
+ movttraits = 1; // in contain batch 2
+ if (goalType == 2) movttraits += 3; //in contain batch 2
+ }
+ if (moveType == 2) movttraits = 2;
+ }
+ else {
+ if (sexDepTrfr) {
+ if (twinKern) movttraits = 6; else movttraits = 2;
+ }
+ else {
+ if (twinKern) movttraits = 3; else movttraits = 1;
+ }
+ }
+ movtTrait[0] = nTraits; movtTrait[1] = movttraits;
+ nTraits += movttraits;
+ }
+
+ int setttraits = 0;
+ if (indVarSett) {
+ if (sexDepSett) setttraits = 6; else setttraits = 3;
+ settTrait[0] = nTraits; settTrait[1] = setttraits;
+ nTraits += setttraits;
+ }
+
+ setTraitNames();
+
+#if RSDEBUG
+ DebugGUI("Species::setTraits(): 9999 nChromosomes=" + Int2Str(nChromosomes)
+ + " nTraits=" + Int2Str(nTraits));
+#endif
+
+}
+
+void Species::setTraitNames(void) {
+ deleteTraitNames();
+ nTraitNames = nTraits;
+ traitnames = new string[nTraitNames];
+ int trait = 0;
+ if (indVarEmig) {
+ if (sexDepEmig) {
+ if (densDepEmig) {
+ traitnames[trait++] = "d0_F";
+ traitnames[trait++] = "d0_M";
+ traitnames[trait++] = "alpha_F";
+ traitnames[trait++] = "alpha_M";
+ traitnames[trait++] = "beta_F";
+ traitnames[trait++] = "beta_M";
+ }
+ else {
+ traitnames[trait++] = "d0_F";
+ traitnames[trait++] = "d0_M";
+ }
+ }
+ else {
+ traitnames[trait++] = "d0";
+ if (densDepEmig) {
+ traitnames[trait++] = "alpha";
+ traitnames[trait++] = "beta";
+ }
+ }
+ }
+
+ if (indVarTrfr) {
+ if (moveModel) {
+ if (moveType == 1) { // SMS
+ traitnames[trait++] = "DP";
+ if (goalType == 2) {
+ traitnames[trait++] = "GB";
+ traitnames[trait++] = "alphaDB";
+ traitnames[trait++] = "betaDB";
+ }
+ }
+ if (moveType == 2) { // CRW
+ traitnames[trait++] = "stepL";
+ traitnames[trait++] = "rho";
+ }
+ }
+ else {
+ if (sexDepTrfr) {
+ if (twinKern)
+ {
+ traitnames[trait++] = "meanDistI_F";
+ traitnames[trait++] = "meanDistI_M";
+ traitnames[trait++] = "meanDistII_F";
+ traitnames[trait++] = "meanDistII_M";
+ traitnames[trait++] = "probKernI_F";
+ traitnames[trait++] = "probKernI_M";
+ }
+ else {
+ traitnames[trait++] = "meanDistI_F";
+ traitnames[trait++] = "meanDistI_M";
+ }
+ }
+ else {
+ traitnames[trait++] = "meanDistI";
+ if (twinKern)
+ {
+ traitnames[trait++] = "meanDistII";
+ traitnames[trait++] = "probKernI";
+ }
+ }
+ }
+ }
+
+ if (indVarSett) {
+ if (sexDepSett) {
+ traitnames[trait++] = "s0_F";
+ traitnames[trait++] = "s0_M";
+ traitnames[trait++] = "alphaS_F";
+ traitnames[trait++] = "alphaS_M";
+ traitnames[trait++] = "betaS_F";
+ traitnames[trait++] = "betaS_M";
+ }
+ else {
+ traitnames[trait++] = "s0";
+ traitnames[trait++] = "alphaS";
+ traitnames[trait++] = "betaS";
+ }
+ }
+}
+
+void Species::deleteTraitNames(void) {
+ if (traitnames != NULL) {
+ delete[] traitnames;
+ traitnames = NULL;
+ }
+}
+
+string Species::getTraitName(const int trait) {
+ string name = "not used";
+ if (traitnames != NULL) {
+ if (trait >= 0 && trait < nTraits) {
+ name = traitnames[trait];
+ }
+ }
+ return name;
+}
+
+int Species::getNTraits(void) { return nTraits; }
+
+void Species::setTraitData(const int ntraits) {
+ deleteTraitData();
+ traitdata = new traitData;
+ if (ntraits > 0) {
+ traitdata->nTraitMaps = ntraits;
+ traitdata->traitmaps = new traitMap * [ntraits];
+ for (int i = 0; i < ntraits; i++) {
+ traitdata->traitmaps[i] = new traitMap;
+ }
+ }
+ else { // neutral markers only
+ traitdata->nTraitMaps = 0;
+ }
+ traitdata->neutralloci = new traitMap;
+ traitdata->neutralloci->nAlleles = 0;
+}
+
+void Species::deleteTraitData(void) {
+ if (traitdata != NULL) {
+ for (int i = 0; i < traitdata->nTraitMaps; i++) {
+ if (traitdata->traitmaps[i]->traitalleles != 0) {
+ for (int j = 0; j < traitdata->traitmaps[i]->nAlleles; j++) {
+ delete traitdata->traitmaps[i]->traitalleles[j];
+ }
+ }
+ delete[] traitdata->traitmaps[i];
+ }
+ deleteNeutralLoci();
+ delete traitdata;
+ traitdata = NULL;
+ }
+}
+
+int Species::getNTraitMaps(void) {
+ if (traitdata == NULL) return 0;
+ else return traitdata->nTraitMaps;
+}
+
+void Species::setTraitMap(const short trait, const short nalleles) {
+ traitdata->traitmaps[trait]->nAlleles = nalleles;
+ traitdata->traitmaps[trait]->traitalleles = new traitAllele * [nalleles];
+ for (int i = 0; i < nalleles; i++) {
+ traitdata->traitmaps[trait]->traitalleles[i] = new traitAllele;
+ }
+}
+
+int Species::getNTraitAlleles(const int trait) {
+ int nalleles = 0;
+ if (traitdata != NULL) {
+ if (trait >= 0 && trait < traitdata->nTraitMaps) {
+ nalleles = traitdata->traitmaps[trait]->nAlleles;
+ }
+ }
+ return nalleles;
+}
+
+void Species::setTraitAllele(const short trait, const short allele,
+ const short chr, const short loc)
+{
+ traitdata->traitmaps[trait]->traitalleles[allele] = new traitAllele;
+ if (chr >= 0 && loc >= 0) {
+ traitdata->traitmaps[trait]->traitalleles[allele]->chromo = chr;
+ traitdata->traitmaps[trait]->traitalleles[allele]->locus = loc;
+ }
+ else {
+ traitdata->traitmaps[trait]->traitalleles[allele]->chromo = 0;
+ traitdata->traitmaps[trait]->traitalleles[allele]->locus = 0;
+ }
+}
+
+traitAllele Species::getTraitAllele(const short trait, const short allele) {
+ traitAllele a; a.chromo = 0; a.locus = 0;
+ if (traitdata != NULL) {
+ if (trait >= 0 && trait < traitdata->nTraitMaps) {
+ if (allele >= 0 && allele < traitdata->traitmaps[trait]->nAlleles) {
+ a = *traitdata->traitmaps[trait]->traitalleles[allele];
+ }
+ }
+ }
+ return a;
+}
+
+// Neutral loci functions
+
+// Identify neutral loci and determine whether there is pleiotropy
+void Species::setNeutralLoci(bool neutralMarkersOnly) {
+ bool neutral;
+ int nneutral = 0;
+ // find minimum of no. of defined / applied traits
+ int ntraits;
+ if (traitdata == 0) ntraits = 0;
+ else ntraits = traitdata->nTraitMaps;
+ if (ntraits > nTraits) ntraits = nTraits;
+
+// determine no. of neutral loci
+ deleteNeutralLoci();
+ for (int i = 0; i < nNLoci; i++) { // each chromosome
+ for (int j = 0; j < nLoci[i]; j++) { // each locus
+ neutral = true;
+ for (int t = 0; t < ntraits; t++) { // each trait
+ for (int a = 0; a < traitdata->traitmaps[t]->nAlleles; a++) {
+ if (i == traitdata->traitmaps[t]->traitalleles[a]->chromo
+ && j == traitdata->traitmaps[t]->traitalleles[a]->locus) {
+ neutral = false; // as locus contributes to a trait
+ a = 999999;
+ }
+ }
+ if (!neutral) t = 999999;
+ }
+ if (neutral) nneutral++;
+ }
+ }
+
+ traitdata->neutralloci = new traitMap;
+ traitdata->neutralloci->nAlleles = nneutral;
+ if (nneutral < 1) return;
+
+ // record neutral markers
+ traitdata->neutralloci->traitalleles = new traitAllele * [nneutral];
+ nneutral = 0;
+ for (int i = 0; i < nNLoci; i++) { // each chromosome
+ for (int j = 0; j < nLoci[i]; j++) { // each locus
+ neutral = true;
+ for (int t = 0; t < ntraits; t++) { // each trait
+ for (int a = 0; a < traitdata->traitmaps[t]->nAlleles; a++) {
+ if (i == traitdata->traitmaps[t]->traitalleles[a]->chromo
+ && j == traitdata->traitmaps[t]->traitalleles[a]->locus) {
+ neutral = false; // as locus contributes to a trait
+ a = 999999;
+ }
+ }
+ if (!neutral) t = 999999;
+ }
+ if (neutral) {
+ traitdata->neutralloci->traitalleles[nneutral] = new traitAllele;
+ traitdata->neutralloci->traitalleles[nneutral]->chromo = i;
+ traitdata->neutralloci->traitalleles[nneutral]->locus = j;
+ nneutral++;
+ }
+ }
+ }
+
+ pleiotropic = false;
+ if (neutralMarkersOnly) return; // pleiotropy cannot apply
+
+ // determine whether there is pleiotropy
+ int chr, loc;
+ int nloci = 0; // maximum no. of loci on any one chromosome
+ for (int i = 0; i < nNLoci; i++) {
+ if (nloci < nLoci[i]) nloci = nLoci[i];
+ }
+ int*** locfreq;
+ locfreq = new int** [nNLoci];
+ for (int i = 0; i < nNLoci; i++) {
+ locfreq[i] = new int* [nloci];
+ for (int j = 0; j < nloci; j++) {
+ locfreq[i][j] = new int[ntraits];
+ for (int t = 0; t < ntraits; t++) locfreq[i][j][t] = 0;
+ }
+ }
+ for (int t = 0; t < ntraits; t++) { // each trait
+ for (int a = 0; a < traitdata->traitmaps[t]->nAlleles; a++) {
+ chr = traitdata->traitmaps[t]->traitalleles[a]->chromo;
+ loc = traitdata->traitmaps[t]->traitalleles[a]->locus;
+ locfreq[chr][loc][t]++;
+ }
+ }
+ for (int i = 0; i < nNLoci; i++) {
+ for (int j = 0; j < nloci; j++) {
+ // remove multiple contributions of a locus to a particular trait
+ // (i.e. prevent recording of pseudo-pleiotropy)
+ for (int t = 0; t < ntraits; t++) {
+ if (locfreq[i][j][t] > 0) locfreq[i][j][t] = 1;
+ }
+ // sum at level of chromosome/locus
+ for (int t = 1; t < ntraits; t++) {
+ locfreq[i][j][0] += locfreq[i][j][t];
+ }
+ if (locfreq[i][j][0] > 1) pleiotropic = true;
+ }
+ }
+ for (int i = 0; i < nNLoci; i++) {
+ for (int j = 0; j < nloci; j++) {
+ delete[] locfreq[i][j];
+ }
+ delete[] locfreq[i];
+ }
+ delete[] locfreq;
+
+}
+
+void Species::deleteNeutralLoci(void) {
+ if (traitdata->neutralloci != NULL) {
+ for (int i = 0; i < traitdata->neutralloci->nAlleles; i++) {
+ delete traitdata->neutralloci->traitalleles[i];
+ }
+ delete[] traitdata->neutralloci;
+ }
+ traitdata->neutralloci = NULL;
+}
+
+int Species::getNNeutralLoci(void) {
+ int nn = 0;
+ if (traitdata != NULL) {
+ if (traitdata->neutralloci != NULL) {
+ nn = traitdata->neutralloci->nAlleles;
+ }
+ }
+ return nn;
+}
+
+traitAllele Species::getNeutralAllele(const short allele) {
+ traitAllele a; a.chromo = 0; a.locus = 0;
+ if (traitdata != NULL) {
+ if (allele >= 0 && allele < traitdata->neutralloci->nAlleles) {
+ a = *traitdata->neutralloci->traitalleles[allele];
+ }
+ }
+ return a;
+}
+
+//---------------------------------------------------------------------------
+
+// Emigration functions
+
+void Species::setEmig(const emigRules e) {
+ densDepEmig = e.densDep; stgDepEmig = e.stgDep; sexDepEmig = e.sexDep;
+ indVarEmig = e.indVar;
+ if (e.emigStage >= 0) emigStage = e.emigStage;
+}
+
+emigRules Species::getEmig(void) {
+ emigRules e;
+ e.densDep = densDepEmig; e.stgDep = stgDepEmig; e.sexDep = sexDepEmig;
+ e.indVar = indVarEmig; e.emigStage = emigStage;
+ e.emigTrait[0] = emigTrait[0]; e.emigTrait[1] = emigTrait[1];
+ return e;
+}
+
+void Species::setEmigTraits(const short stg, const short sex, const emigTraits e) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ if (e.d0 >= 0.0 && e.d0 <= 1.0) d0[stg][sex] = e.d0;
+ alphaEmig[stg][sex] = e.alpha; betaEmig[stg][sex] = e.beta;
+ }
+}
+
+emigTraits Species::getEmigTraits(short stg, short sex) {
+ emigTraits e;
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ e.d0 = d0[stg][sex]; e.alpha = alphaEmig[stg][sex]; e.beta = betaEmig[stg][sex];
+ }
+ else {
+ e.d0 = e.alpha = e.beta = 0.0;
+ }
+ return e;
+}
+
+float Species::getEmigD0(short stg, short sex) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ return d0[stg][sex];
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void Species::setEmigParams(const short stg, const short sex, const emigParams e) {
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < NSEXES) // implemented for stage 0 only
+ {
+ if (e.d0Mean >= 0.0 && e.d0Mean < 1.0) d0Mean[stg][sex] = e.d0Mean;
+ if (e.d0SD > 0.0 && e.d0SD < 1.0) d0SD[stg][sex] = e.d0SD;
+ alphaMean[stg][sex] = e.alphaMean;
+ if (e.alphaSD > 0.0) alphaSD[stg][sex] = e.alphaSD;
+ betaMean[stg][sex] = e.betaMean;
+ if (e.betaSD > 0.0) betaSD[stg][sex] = e.betaSD;
+ }
+}
+
+emigParams Species::getEmigParams(short stg, short sex) {
+ emigParams e;
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < NSEXES) // implemented for stage 0 only
+ {
+ e.d0Mean = d0Mean[stg][sex]; e.d0SD = d0SD[stg][sex];
+ e.d0Scale = d0Scale;
+ e.alphaMean = alphaMean[stg][sex]; e.alphaSD = alphaSD[stg][sex];
+ e.alphaScale = alphaScale;
+ e.betaMean = betaMean[stg][sex]; e.betaSD = betaSD[stg][sex];
+ e.betaScale = betaScale;
+ }
+ else {
+ e.d0Mean = e.alphaMean = e.betaMean = e.d0SD = e.alphaSD = e.betaSD = 0.0;
+ e.d0Scale = d0Scale;
+ e.alphaScale = alphaScale;
+ e.betaScale = betaScale;
+ }
+ return e;
+}
+
+void Species::setEmigScales(const emigScales s) {
+ if (s.d0Scale >= 0.0 && s.d0Scale < 1.0) d0Scale = s.d0Scale;
+ if (s.alphaScale >= 0.0) alphaScale = s.alphaScale;
+ if (s.betaScale >= 0.0) betaScale = s.betaScale;
+}
+
+emigScales Species::getEmigScales(void) {
+ emigScales s;
+ s.d0Scale = d0Scale; s.alphaScale = alphaScale; s.betaScale = betaScale;
+ return s;
+}
+
+//---------------------------------------------------------------------------
+
+// Transfer functions
+
+void Species::setTrfr(const trfrRules t) {
+ moveModel = t.moveModel; stgDepTrfr = t.stgDep; sexDepTrfr = t.sexDep;
+ distMort = t.distMort; indVarTrfr = t.indVar;
+ twinKern = t.twinKern;
+ habMort = t.habMort;
+ moveType = t.moveType; costMap = t.costMap;
+}
+
+trfrRules Species::getTrfr(void) {
+ trfrRules t;
+ t.moveModel = moveModel; t.stgDep = stgDepTrfr; t.sexDep = sexDepTrfr;
+ t.distMort = distMort; t.indVar = indVarTrfr;
+ t.twinKern = twinKern;
+ t.habMort = habMort;
+ t.moveType = moveType; t.costMap = costMap;
+ t.movtTrait[0] = movtTrait[0]; t.movtTrait[1] = movtTrait[1];
+ return t;
+}
+
+void Species::setFullKernel(bool k) {
+ fullKernel = k;
+}
+
+bool Species::useFullKernel(void) { return fullKernel; }
+
+void Species::setKernTraits(const short stg, const short sex,
+ const trfrKernTraits k, const int resol)
+{
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ if (k.meanDist1 > 0.0 && k.meanDist1 >= (float)resol) meanDist1[stg][sex] = k.meanDist1;
+ if (k.meanDist2 >= (float)resol) meanDist2[stg][sex] = k.meanDist2;
+ if (k.probKern1 > 0.0 && k.probKern1 < 1.0) probKern1[stg][sex] = k.probKern1;
+ }
+}
+
+trfrKernTraits Species::getKernTraits(short stg, short sex) {
+ trfrKernTraits k;
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ k.meanDist1 = meanDist1[stg][sex];
+ k.meanDist2 = meanDist2[stg][sex];
+ k.probKern1 = probKern1[stg][sex];
+ }
+ else {
+ k.meanDist1 = 0.0; k.meanDist2 = 0.0; k.probKern1 = 1.0;
+ }
+ return k;
+}
+
+void Species::setMortParams(const trfrMortParams m) {
+ if (m.fixedMort >= 0.0 && m.fixedMort < 1.0) fixedMort = m.fixedMort;
+ mortAlpha = m.mortAlpha;
+ mortBeta = m.mortBeta;
+}
+
+trfrMortParams Species::getMortParams(void) {
+ trfrMortParams m;
+ m.fixedMort = fixedMort; m.mortAlpha = mortAlpha; m.mortBeta = mortBeta;
+ return m;
+}
+
+void Species::setMovtTraits(const trfrMovtTraits m) {
+ if (m.pr >= 1) pr = m.pr;
+ if (m.prMethod >= 1 && m.prMethod <= 3) prMethod = m.prMethod;
+ if (m.memSize >= 1 && m.memSize <= 14) memSize = m.memSize;
+ if (m.goalType >= 0 && m.goalType <= 2) goalType = m.goalType;
+ if (m.dp >= 1.0) dp = m.dp;
+ if (m.gb >= 1.0) gb = m.gb;
+ if (m.alphaDB > 0.0) alphaDB = m.alphaDB;
+ if (m.betaDB > 0) betaDB = m.betaDB;
+ if (m.stepMort >= 0.0 && m.stepMort < 1.0) stepMort = m.stepMort;
+ if (m.stepLength > 0.0) stepLength = m.stepLength;
+ if (m.rho > 0.0 && m.rho < 1.0) rho = m.rho;
+ straigtenPath = m.straigtenPath;
+}
+
+trfrMovtTraits Species::getMovtTraits(void) {
+ trfrMovtTraits m;
+ m.pr = pr; m.prMethod = prMethod; m.memSize = memSize; m.goalType = goalType;
+ m.dp = dp; m.gb = gb; m.alphaDB = alphaDB; m.betaDB = betaDB;
+ m.stepMort = stepMort; m.stepLength = stepLength; m.rho = rho;
+ return m;
+}
+
+trfrCRWTraits Species::getCRWTraits(void) {
+ trfrCRWTraits m;
+ m.stepMort = stepMort; m.stepLength = stepLength; m.rho = rho;
+ m.straigtenPath = straigtenPath;
+ return m;
+}
+
+trfrSMSTraits Species::getSMSTraits(void) {
+ trfrSMSTraits m;
+ m.pr = pr; m.prMethod = prMethod; m.memSize = memSize; m.goalType = goalType;
+ m.dp = dp; m.gb = gb; m.alphaDB = alphaDB; m.betaDB = betaDB; m.stepMort = stepMort;
+ m.straigtenPath = straigtenPath;
+ return m;
+}
+
+void Species::setKernParams(const short stg, const short sex,
+ const trfrKernParams k, const double resol)
+{
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < NSEXES) // implemented for stage 0 only
+ {
+ if (k.dist1Mean > 0.0 && k.dist1Mean >= resol && k.dist1SD > 0.0) {
+ dist1Mean[stg][sex] = k.dist1Mean; dist1SD[stg][sex] = k.dist1SD;
+ }
+ if (k.dist2Mean > 0.0 && k.dist2Mean >= resol && k.dist2SD > 0.0) {
+ dist2Mean[stg][sex] = k.dist2Mean; dist2SD[stg][sex] = k.dist2SD;
+ }
+ if (k.PKern1Mean > 0.0 && k.PKern1Mean < 1.0 && k.PKern1SD > 0.0 && k.PKern1SD < 1.0) {
+ PKern1Mean[stg][sex] = k.PKern1Mean; PKern1SD[stg][sex] = k.PKern1SD;
+ }
+ }
+}
+
+trfrKernParams Species::getKernParams(short stg, short sex) {
+ trfrKernParams k;
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < NSEXES) // implemented for stage 0 only
+ {
+ k.dist1Mean = dist1Mean[stg][sex]; k.dist1SD = dist1SD[stg][sex];
+ k.dist2Mean = dist2Mean[stg][sex]; k.dist2SD = dist2SD[stg][sex];
+ k.PKern1Mean = PKern1Mean[stg][sex]; k.PKern1SD = PKern1SD[stg][sex];
+ k.dist1Scale = dist1Scale; k.dist2Scale = dist2Scale; k.PKern1Scale = PKern1Scale;
+ }
+ else {
+ k.dist1Mean = 100000.0; k.dist1SD = 0.001f; k.dist1Scale = 1.0;
+ k.dist2Mean = 100000.0; k.dist2SD = 0.001f; k.dist2Scale = 1.0;
+ k.PKern1Mean = 0.5; k.PKern1SD = 0.1f; k.PKern1Scale = 0.1f;
+ }
+ return k;
+}
+
+void Species::setSMSParams(const short stg, const short sex, const trfrSMSParams s) {
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < 1) // implemented for stage 0 & sex 0 only
+ {
+ if (s.dpMean >= 1.0 && s.dpSD > 0.0) {
+ dpMean[stg][sex] = s.dpMean; dpSD[stg][sex] = s.dpSD;
+ }
+ if (s.gbMean >= 1.0 && s.gbSD > 0.0) {
+ gbMean[stg][sex] = s.gbMean; gbSD[stg][sex] = s.gbSD;
+ }
+ if (s.alphaDBMean > 0.0 && s.alphaDBSD > 0.0) {
+ alphaDBMean[stg][sex] = s.alphaDBMean; alphaDBSD[stg][sex] = s.alphaDBSD;
+ }
+ if (s.betaDBMean >= 1.0 && s.betaDBSD > 0.0) {
+ betaDBMean[stg][sex] = s.betaDBMean; betaDBSD[stg][sex] = s.betaDBSD;
+ }
+ }
+}
+
+trfrSMSParams Species::getSMSParams(short stg, short sex) {
+ trfrSMSParams s;
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < 1) // implemented for stage 0 & sex 0 only
+ {
+ s.dpMean = dpMean[stg][sex]; s.dpSD = dpSD[stg][sex];
+ s.gbMean = gbMean[stg][sex]; s.gbSD = gbSD[stg][sex];
+ s.alphaDBMean = alphaDBMean[stg][sex]; s.alphaDBSD = alphaDBSD[stg][sex];
+ s.betaDBMean = betaDBMean[stg][sex]; s.betaDBSD = betaDBSD[stg][sex];
+ s.dpScale = dpScale; s.gbScale = gbScale;
+ s.alphaDBScale = alphaDBScale; s.betaDBScale = betaDBScale;
+ }
+ else {
+ s.dpMean = 1.0; s.dpSD = 0.1f; s.dpScale = 0.1f;
+ s.gbMean = 1.0; s.gbSD = 0.1f; s.gbScale = 0.1f;
+ s.alphaDBMean = 1.0; s.alphaDBSD = 0.1f; s.alphaDBScale = 0.1f;
+ s.betaDBMean = 10.0; s.betaDBSD = 1.0; s.betaDBScale = 1.0;
+ }
+ return s;
+}
+
+void Species::setCRWParams(const short stg, const short sex, const trfrCRWParams m) {
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < 1) // implemented for stage 0 & sex 0 only
+ {
+ if (m.stepLgthMean > 0.0 && m.stepLgthSD > 0.0) {
+ stepLgthMean[stg][sex] = m.stepLgthMean; stepLgthSD[stg][sex] = m.stepLgthSD;
+ }
+ if (m.rhoMean > 0.0 && m.rhoMean < 1.0 && m.rhoSD > 0.0 && m.rhoSD < 1.0) {
+ rhoMean[stg][sex] = m.rhoMean; rhoSD[stg][sex] = m.rhoSD;
+ }
+ }
+}
+
+trfrCRWParams Species::getCRWParams(short stg, short sex) {
+ trfrCRWParams m;
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < 1) // implemented for stage 0 & sex 0 only
+ {
+ m.stepLgthMean = stepLgthMean[stg][sex]; m.stepLgthSD = stepLgthSD[stg][sex];
+ m.rhoMean = rhoMean[stg][sex]; m.rhoSD = rhoSD[stg][sex];
+ m.stepLScale = stepLScale; m.rhoScale = rhoScale;
+ }
+ else {
+ m.stepLgthMean = 1.0; m.stepLgthSD = 0.1f; m.stepLScale = 0.1f;
+ m.rhoMean = 0.5; m.rhoSD = 0.1f; m.rhoScale = 0.1f;
+ }
+ return m;
+}
+
+void Species::setTrfrScales(const trfrScales s) {
+ if (s.dist1Scale >= 0.0) dist1Scale = s.dist1Scale;
+ if (s.dist2Scale >= 0.0) dist2Scale = s.dist2Scale;
+ if (s.PKern1Scale > 0.0 && s.PKern1Scale < 1.0) PKern1Scale = s.PKern1Scale;
+ if (s.dpScale > 0.0) dpScale = s.dpScale;
+ if (s.gbScale > 0.0) gbScale = s.gbScale;
+ if (s.alphaDBScale > 0.0) alphaDBScale = s.alphaDBScale;
+ if (s.betaDBScale > 0.0) betaDBScale = s.betaDBScale;
+ if (s.stepLScale > 0.0) stepLScale = s.stepLScale;
+ if (s.rhoScale > 0.0 && s.rhoScale < 1.0) rhoScale = s.rhoScale;
+}
+
+trfrScales Species::getTrfrScales(void) {
+ trfrScales s;
+ s.dist1Scale = dist1Scale; s.dist2Scale = dist2Scale; s.PKern1Scale = PKern1Scale;
+ s.dpScale = dpScale; s.gbScale = gbScale;
+ s.alphaDBScale = alphaDBScale; s.betaDBScale = betaDBScale;
+ s.stepLScale = stepLScale; s.rhoScale = rhoScale;
+ return s;
+}
+
+short Species::getMovtHabDim() { return habDimTrfr; }
+
+void Species::createHabCostMort(short nhab) {
+ if (nhab >= 0) {
+ habDimTrfr = nhab;
+ if (habCost != 0 || habStepMort != 0) deleteHabCostMort();
+ habCost = new int[nhab];
+ habStepMort = new double[nhab];
+ for (int i = 0; i < nhab; i++) {
+ habCost[i] = 1; habStepMort[i] = 0.0;
+ }
+ }
+}
+
+void Species::setHabCost(short hab, int cost) {
+ if (hab >= 0 && hab < habDimTrfr) {
+ if (cost >= 1) habCost[hab] = cost;
+ }
+}
+
+void Species::setHabMort(short hab, double mort) {
+ if (hab >= 0 && hab < habDimTrfr) {
+ if (mort >= 0.0 && mort < 1.0) habStepMort[hab] = mort;
+ }
+}
+
+int Species::getHabCost(short hab) {
+ int cost = 0;
+ if (hab >= 0 && hab < habDimTrfr) cost = habCost[hab];
+ return cost;
+}
+
+double Species::getHabMort(short hab) {
+ double pmort = 0.0;
+ if (hab >= 0 && hab < habDimTrfr) pmort = habStepMort[hab];
+ return pmort;
+}
+
+void Species::deleteHabCostMort(void) {
+ if (habCost != 0) {
+ delete[] habCost; habCost = 0;
+ }
+ if (habStepMort != 0) {
+ delete[] habStepMort; habStepMort = 0;
+ }
+}
+
+//---------------------------------------------------------------------------
+
+// Settlement functions
+
+void Species::setSettle(const settleType s) {
+ stgDepSett = s.stgDep; sexDepSett = s.sexDep; indVarSett = s.indVar;
+}
+
+settleType Species::getSettle(void) {
+ settleType s;
+ s.stgDep = stgDepSett; s.sexDep = sexDepSett; s.indVar = indVarSett;
+ s.settTrait[0] = settTrait[0]; s.settTrait[1] = settTrait[1];
+ return s;
+}
+
+void Species::setSettRules(const short stg, const short sex, const settleRules s) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ densDepSett[stg][sex] = s.densDep; wait[stg][sex] = s.wait;
+ go2nbrLocn[stg][sex] = s.go2nbrLocn; findMate[stg][sex] = s.findMate;
+ }
+}
+
+settleRules Species::getSettRules(short stg, short sex) {
+ settleRules s;
+ s.densDep = false;
+ s.findMate = false;
+ s.go2nbrLocn = false;
+ s.wait = false;
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ s.densDep = densDepSett[stg][sex]; s.wait = wait[stg][sex];
+ s.go2nbrLocn = go2nbrLocn[stg][sex]; s.findMate = findMate[stg][sex];
+ }
+ return s;
+}
+
+void Species::setSteps(const short stg, const short sex, const settleSteps s) {
+ if (stg == 0 && sex == 0) {
+ if (s.minSteps >= 0) minSteps = s.minSteps;
+ else minSteps = 0;
+ if (s.maxSteps >= 1) maxSteps = s.maxSteps;
+ else maxSteps = 99999999;
+ }
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ if (s.maxStepsYr >= 1) maxStepsYr[stg][sex] = s.maxStepsYr;
+ else maxStepsYr[stg][sex] = 99999999;
+ }
+}
+
+settleSteps Species::getSteps(short stg, short sex) {
+ settleSteps s;
+ s.minSteps = minSteps;
+ s.maxSteps = maxSteps;
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) s.maxStepsYr = maxStepsYr[stg][sex];
+ else s.maxStepsYr = 99999999;
+ return s;
+}
+
+void Species::setSettTraits(const short stg, const short sex, const settleTraits dd) {
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ if (dd.s0 > 0.0 && dd.s0 <= 1.0) s0[stg][sex] = dd.s0;
+ alphaS[stg][sex] = dd.alpha; betaS[stg][sex] = dd.beta;
+ }
+}
+
+settleTraits Species::getSettTraits(short stg, short sex) {
+ settleTraits dd;
+ if (stg >= 0 && stg < NSTAGES && sex >= 0 && sex < NSEXES) {
+ dd.s0 = s0[stg][sex]; dd.alpha = alphaS[stg][sex]; dd.beta = betaS[stg][sex];
+ }
+ else { dd.s0 = 1.0; dd.alpha = dd.beta = 0.0; }
+ return dd;
+}
+
+void Species::setSettParams(const short stg, const short sex, const settParams s) {
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < NSEXES) // implemented for stage 0 only
+ {
+ if (s.s0Mean >= 0.0 && s.s0Mean < 1.0) s0Mean[stg][sex] = s.s0Mean;
+ if (s.s0SD > 0.0 && s.s0SD < 1.0) s0SD[stg][sex] = s.s0SD;
+ alphaSMean[stg][sex] = s.alphaSMean;
+ if (s.alphaSSD > 0.0) alphaSSD[stg][sex] = s.alphaSSD;
+ betaSMean[stg][sex] = s.betaSMean;
+ if (s.betaSSD > 0.0) betaSSD[stg][sex] = s.betaSSD;
+ if (sex == 0) {
+ if (s.s0Scale > 0.0 && s.s0Scale < 1.0) s0Scale = s.s0Scale;
+ if (s.alphaSScale > 0.0) alphaSScale = s.alphaSScale;
+ if (s.betaSScale > 0.0) betaSScale = s.betaSScale;
+ }
+ }
+}
+
+settParams Species::getSettParams(short stg, short sex) {
+ settParams s;
+ if (stg >= 0 && stg < 1 && sex >= 0 && sex < NSEXES) // implemented for stage 0 only
+ {
+ s.s0Mean = s0Mean[stg][sex]; s.s0SD = s0SD[stg][sex];
+ s.alphaSMean = alphaSMean[stg][sex]; s.alphaSSD = alphaSSD[stg][sex];
+ s.betaSMean = betaSMean[stg][sex]; s.betaSSD = betaSSD[stg][sex];
+ }
+ else {
+ s.s0Mean = s.alphaSMean = s.betaSMean = s.s0SD = s.alphaSSD = s.betaSSD = 0.0;
+ }
+ s.s0Scale = s0Scale;
+ s.alphaSScale = alphaSScale;
+ s.betaSScale = betaSScale;
+ return s;
+}
+
+void Species::setSettScales(const settScales s) {
+ if (s.s0Scale >= 0.0 && s.s0Scale < 1.0) s0Scale = s.s0Scale;
+ if (s.alphaSScale >= 0.0) alphaSScale = s.alphaSScale;
+ if (s.betaSScale >= 0.0) betaSScale = s.betaSScale;
+}
+
+settScales Species::getSettScales(void) {
+ settScales s;
+ s.s0Scale = s0Scale; s.alphaSScale = alphaSScale; s.betaSScale = betaSScale;
+ return s;
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
diff --git a/src/RScore/Species.h b/src/RScore/Species.h
new file mode 100644
index 00000000..3a004a26
--- /dev/null
+++ b/src/RScore/Species.h
@@ -0,0 +1,748 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+ /*------------------------------------------------------------------------------
+
+ RangeShifter v2.0 Species
+
+ Implements the Species class
+
+ There is ONE instance of a Species for each species within the Community
+ AND THIS IS CURRENTLY LIMITED TO A SINGLE SPECIES.
+ The class holds all the demographic and dispersal parameters of the species.
+
+ For full details of RangeShifter, please see:
+ Bocedi G., Palmer S.C.F., Pe’er G., Heikkinen R.K., Matsinos Y.G., Watts K.
+ and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+ eco-evolutionary dynamics and species’ responses to environmental changes.
+ Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+ Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+ Last updated: 28 July 2021 by Greta Bocedi
+
+ ------------------------------------------------------------------------------*/
+
+#ifndef SpeciesH
+#define SpeciesH
+
+#include "Parameters.h"
+
+// structures for demographic parameters
+
+struct demogrParams {
+ short repType;
+ short repSeasons;
+ float propMales; float harem; float bc; float lambda;
+ bool stageStruct;
+};
+struct stageParams {
+ short nStages; short repInterval; short maxAge; short survival;
+ float probRep;
+ bool fecDens; bool fecStageDens; bool devDens; bool devStageDens;
+ bool survDens; bool survStageDens; bool disperseOnLoss;
+};
+struct densDepParams {
+ float devCoeff; float survCoeff;
+};
+
+// structures for genetics
+
+struct genomeData {
+ int nLoci;
+ bool diploid; bool neutralMarkers; bool pleiotropic; bool trait1Chromosome;
+ double probMutn, probCrossover, alleleSD, mutationSD;
+};
+
+struct traitAllele {
+ short chromo; short locus;
+};
+
+struct traitMap {
+ short nAlleles;
+ traitAllele** traitalleles;
+};
+
+struct traitData {
+ short nTraitMaps;
+ traitMap** traitmaps;
+ traitMap* neutralloci;
+};
+
+// structures for emigration parameters
+
+struct emigRules {
+ bool densDep; bool stgDep; bool sexDep; bool indVar;
+ short emigStage;
+ short emigTrait[2];
+};
+struct emigTraits {
+ float d0; float alpha; float beta;
+};
+struct emigParams {
+ double d0Mean; double d0SD; double d0Scale;
+ double alphaMean; double alphaSD; double alphaScale;
+ double betaMean; double betaSD; double betaScale;
+};
+struct emigScales {
+ double d0Scale; double alphaScale; double betaScale;
+};
+
+// structures for transfer parameters
+
+struct trfrRules {
+ bool moveModel; bool stgDep; bool sexDep;
+ bool distMort; bool indVar;
+ bool twinKern;
+ bool habMort;
+ short moveType; bool costMap;
+ short movtTrait[2];
+};
+struct trfrKernTraits {
+ float meanDist1; float meanDist2; float probKern1;
+};
+struct trfrMortParams {
+ float fixedMort; float mortAlpha; float mortBeta;
+};
+struct trfrMovtTraits {
+ short pr; short prMethod; short memSize; short goalType;
+ float dp; float gb; float alphaDB; int betaDB;
+ float stepMort; float stepLength; float rho;
+ bool straigtenPath;
+};
+struct trfrCRWTraits {
+ float stepMort; float stepLength; float rho; bool straigtenPath;
+};
+struct trfrSMSTraits {
+ short pr; short prMethod; short memSize; short goalType;
+ float dp; float gb; float alphaDB; int betaDB; float stepMort;
+ bool straigtenPath;
+};
+struct trfrKernParams {
+ double dist1Mean; double dist1SD; double dist1Scale;
+ double dist2Mean; double dist2SD; double dist2Scale;
+ double PKern1Mean; double PKern1SD; double PKern1Scale;
+};
+struct trfrSMSParams {
+ double dpMean; double dpSD; double gbMean; double gbSD;
+ double alphaDBMean; double alphaDBSD; double betaDBMean; double betaDBSD;
+ double dpScale; double gbScale; double alphaDBScale; double betaDBScale;
+};
+struct trfrCRWParams {
+ double stepLgthMean; double stepLgthSD; double stepLScale;
+ double rhoMean; double rhoSD; double rhoScale;
+};
+struct trfrScales {
+ float dist1Scale; float dist2Scale; float PKern1Scale;
+ float dpScale; float gbScale; float alphaDBScale; float betaDBScale;
+ float stepLScale; float rhoScale;
+};
+
+// structures for settlement parameters
+
+struct settleType {
+ bool stgDep; bool sexDep; bool indVar;
+ short settTrait[2];
+};
+struct settleRules {
+ bool densDep; bool wait; bool go2nbrLocn; bool findMate;
+};
+struct settleSteps {
+ int minSteps; int maxSteps; int maxStepsYr;
+};
+struct settleTraits {
+ float s0; float alpha; float beta;
+};
+struct settParams {
+ double s0Mean; double s0SD; double s0Scale;
+ double alphaSMean; double alphaSSD; double alphaSScale;
+ double betaSMean; double betaSSD; double betaSScale;
+};
+struct settScales {
+ double s0Scale; double alphaSScale; double betaSScale;
+};
+
+
+//---------------------------------------------------------------------------
+
+class Species {
+
+public:
+ Species(void);
+ ~Species(void);
+ short getSpNum(void);
+
+ // demographic parameter functions
+
+ void createHabK( // Create habitat carrying capacity table
+ short // no. of habitats
+ );
+ void setHabK(
+ short, // habitat index no. (NB may differ from habitat no. supplied by user)
+ float // carrying capacity (inds/cell)
+ );
+ float getHabK(
+ short // habitat index no. (NB may differ from habitat no. supplied by user)
+ );
+ float getMaxK(void); // return highest carrying capacity over all habitats
+ void deleteHabK(void); // Delete habitat carrying capacity table
+ void setStage( // Set stage structure parameters
+ const stageParams // structure holding stage structure parameters
+ );
+ stageParams getStage(void); // Get stage structure parameters
+ void setDemogr( // Set general demographic parameters
+ const demogrParams // structure holding general demographic parameters
+ );
+ demogrParams getDemogr(void); // Get general demographic parameters
+ short getRepType(void);
+ bool stageStructured(void);
+ void setDensDep( // Set demographic density dependence coefficients
+ float, // development coefficient
+ float // survival coefficient
+ );
+ densDepParams getDensDep(void); // Get development and survival coefficients
+
+ void setFec( // Set fecundity
+ short, // stage (must be > 0)
+ short, // sex
+ float // fecundity
+ );
+ float getFec( // Get fecundity
+ short, // stage
+ short // sex
+ );
+ void setDev( // Set development probability
+ short, // stage
+ short, // sex
+ float // development probability
+ );
+ float getDev( // Get development probability
+ short, // stage
+ short // sex
+ );
+ void setSurv( // Set survival probability
+ short, // stage
+ short, // sex
+ float // survival probability
+ );
+ float getSurv( // Get survival probability
+ short, // stage
+ short // sex
+ );
+
+ float getMaxFec(void); // Get highest fecundity of any stage
+ void setMinAge( // Set minimum age
+ short, // stage
+ short, // sex
+ int // minimum age (years) (must be zero for stages 0 and 1)
+ );
+ short getMinAge( // Get minimum age
+ short, // stage
+ short // sex
+ );
+ void createDDwtFec( // Create fecundity weights matrix
+ short // matrix dimension - no. of stages * no. of sexes
+ );
+ void setDDwtFec( // Set fecundity weights matrix element
+ short, // row
+ short, // column
+ float // weight
+ );
+ float getDDwtFec( // Get fecundity weights matrix element
+ short, // row
+ short // column
+ );
+ void deleteDDwtFec(void); // Delete fecundity weights matrix
+ void createDDwtDev( // Create development weights matrix
+ short // matrix dimension - no. of stages * no. of sexes
+ );
+ void setDDwtDev( // Set development weights matrix element
+ short, // row
+ short, // column
+ float // weight
+ );
+ float getDDwtDev( // Get development weights matrix element
+ short, // row
+ short // column
+ );
+ void deleteDDwtDev(void); // Delete development weights matrix
+ void createDDwtSurv( // Create survival weights matrix
+ short // matrix dimension - no. of stages * no. of sexes
+ );
+ void setDDwtSurv( // Set survival weights matrix element
+ short, // row
+ short, // column
+ float // weight
+ );
+ float getDDwtSurv( // Get survival weights matrix element
+ short, // row
+ short // column
+ );
+ void deleteDDwtSurv(void); // Delete survival weights matrix
+ // Functions to handle min/max R or K (under environmental stochasticity)
+ void setMinMax( // Set min and max values
+ float, // min
+ float // max
+ );
+ float getMinMax( // Get min/max value
+ short // option: 0 = return minimum, otherwise = return maximum
+ );
+
+
+ // genome functions
+
+ void setGenomeData(genomeData);
+ genomeData getGenomeData(void);
+ bool isDiploid(void);
+ void setNChromosomes( // Set no. of chromosomes
+ int // no. of chromosomes
+ );
+ int getNChromosomes(void);
+ void setNLoci(
+ const short, // chromosome no.
+ const short // locus no.
+ );
+ int getNLoci(
+ const short // chromosome no.
+ );
+ void deleteLoci(void);
+ void set1ChromPerTrait( // Set 1:1 mapping of trait to chromosome
+ const int // no. of loci on each chromosome
+ );
+ bool has1ChromPerTrait(void);
+ void setTraits(void); // Set trait attributes for the species
+ void setTraitNames(void);
+ void deleteTraitNames(void);
+ string getTraitName(
+ const int // trait no.
+ );
+ int getNTraits(void);
+ void setTraitData(
+ const int // no. of traits
+ );
+ void deleteTraitData(void);
+ int getNTraitMaps(void);
+ void setTraitMap(
+ const short, // trait no.
+ const short // no. of alleles
+ );
+ int getNTraitAlleles(
+ const int // trait no.
+ );
+ void setTraitAllele(
+ const short, // trait no.
+ const short, // trait allele no.
+ const short, // chromosome no.
+ const short // chromosome locus no.
+ );
+ traitAllele getTraitAllele(
+ const short, // trait no.
+ const short // trait allele no.
+ );
+ void setNeutralLoci(bool);
+ void deleteNeutralLoci(void);
+ int getNNeutralLoci(void);
+ traitAllele getNeutralAllele(
+ const short // allele no.
+ );
+
+ // emigration parameter functions
+
+ void setEmig( // Set emigration rules
+ const emigRules // structure holding emigration rules
+ );
+ emigRules getEmig(void); // Get emigration rules
+ void setEmigTraits( // Set emigration trait parameters
+ const short, // stage
+ const short, // sex
+ const emigTraits // structure holding emigration trait parameters
+ );
+ emigTraits getEmigTraits( // Get emigration trait parameters
+ short, // stage
+ short // sex
+ );
+ float getEmigD0( // Get (maximum) emigration probability
+ short, // stage
+ short // sex
+ );
+ void setEmigParams( // Set emigration initialisation parameters
+ const short, // stage (NB implemented for stage 0 only)
+ const short, // sex
+ const emigParams // structure holding parameters
+ );
+ emigParams getEmigParams( // Get emigration initialisation parameters
+ short, // stage (NB implemented for stage 0 only)
+ short // sex
+ );
+ void setEmigScales( // Set emigration mutation parameters
+ const emigScales // structure holding emigration mutation parameters
+ );
+ emigScales getEmigScales(void); // Get emigration mutation parameters
+
+ // transfer parameter functions
+
+ void setTrfr( // Set transfer rules
+ const trfrRules // structure holding transfer rules
+ );
+ trfrRules getTrfr(void); // Get transfer rules
+ void setFullKernel( // Set fullKernel condition
+ bool // fullKernel value
+ );
+ bool useFullKernel(void);
+ void setKernTraits( // Set transfer by kernel parameters
+ const short, // stage
+ const short, // sex
+ const trfrKernTraits, // structure holding transfer by kernel parameters
+ const int // Landscape resolution
+ );
+ trfrKernTraits getKernTraits( // Get transfer by kernel parameters
+ short, // stage
+ short // sex
+ );
+ void setMortParams( // Set transfer mortality parameters
+ const trfrMortParams // structure holding transfer mortality parameters
+ );
+ trfrMortParams getMortParams(void); // Get transfer mortality parameters
+ void setMovtTraits( // Set transfer movement model parameters
+ const trfrMovtTraits // structure holding transfer movement model parameters
+ );
+ trfrMovtTraits getMovtTraits(void); // Get transfer movement model traits
+ trfrCRWTraits getCRWTraits(void); // Get CRW traits
+ trfrSMSTraits getSMSTraits(void); // Get SMS traits
+ void setKernParams( // Set initial transfer by kernel parameter limits
+ const short, // stage (NB implemented for stage 0 only)
+ const short, // sex
+ const trfrKernParams, // structure holding min and max values
+ const double // Landscape resolution
+ );
+ trfrKernParams getKernParams( // Get initial transfer by kernel parameter limits
+ short, // stage (NB implemented for stage 0 only)
+ short // sex
+ );
+ void setSMSParams( // Set initial transfer by SMS parameter limits
+ const short, // stage (NB implemented for stage 0 only)
+ const short, // sex (NB implemented for sex 0 only)
+ const trfrSMSParams // structure holding min and max values
+ );
+ trfrSMSParams getSMSParams( // Get initial transfer by SMS parameter limits
+ short, // stage (NB implemented for stage 0 only)
+ short // sex (NB implemented for sex 0 only)
+ );
+ void setCRWParams( // Set initial transfer by CRW parameter limits
+ const short, // stage (NB implemented for stage 0 only)
+ const short, // sex (NB implemented for sex 0 only)
+ const trfrCRWParams // structure holding min and max values
+ );
+ trfrCRWParams getCRWParams( // Get initial transfer by CRW parameter limits
+ short, // stage (NB implemented for stage 0 only)
+ short // sex (NB implemented for sex 0 only)
+ );
+ void setTrfrScales( // Set transfer mutation parameters
+ const trfrScales // structure holding transfer mutation parameters
+ );
+ trfrScales getTrfrScales(void); // Get transfer mutation parameters
+ // Return dimension of habitat-dependent step mortality and costs matrices
+ short getMovtHabDim(void);
+ void createHabCostMort( // Create habitat-dependent costs and mortality matrices
+ short // no. of habitats
+ );
+ void setHabCost( // Set habitat-dependent cost
+ short, // habitat index no.
+ int // cost value
+ );
+ void setHabMort( // Set habitat-dependent per-step mortality
+ short, // habitat index no.
+ double // mortality rate
+ );
+ int getHabCost( // Get habitat-dependent cost
+ short // habitat index no.
+ );
+ double getHabMort( // Get habitat-dependent per-step mortality
+ short // habitat index no.
+ );
+ void deleteHabCostMort(void); // Delete habitat-dependent costs and mortality matrices
+
+ // settlement parameter functions
+
+ void setSettle( // Set settlement type
+ const settleType // structure holding settlement type (stage- and/or sex-dependent)
+ );
+ settleType getSettle(void); // Get settlement type
+ void setSettRules( // Set settlement rules
+ const short, // stage
+ const short, // sex
+ const settleRules // structure holding settlement rules
+ );
+ settleRules getSettRules( // Get settlement rules
+ short, // stage
+ short // sex
+ );
+ void setSteps( // Set path step limit parameters
+ const short, // stage
+ const short, // sex
+ const settleSteps // structure holding path step limit parameters
+ );
+ settleSteps getSteps( // Set path step limit parameters
+ short, // stage
+ short // sex
+ );
+ void setSettTraits( // Set settlement density dependence traits
+ const short, // stage
+ const short, // sex
+ const settleTraits // structure holding density dependence traits
+ );
+ settleTraits getSettTraits( // Get settlement density dependence traits
+ short, // stage
+ short // sex
+ );
+ void setSettParams( // Set settlement initialisation parameters
+ const short, // stage (NB implemented for stage 0 only)
+ const short, // sex
+ const settParams // structure holding parameters
+ );
+ settParams getSettParams( // Get settlement initialisation parameters
+ short, // stage (NB implemented for stage 0 only)
+ short // sex
+ );
+ void setSettScales( // Set settlement mutation parameters
+ const settScales // structure holding settlement mutation parameters
+ );
+ settScales getSettScales(void); // Get settlement mutation parameters
+
+private:
+
+ // NOTE: SEQUENCE OF PARAMETER VARIABLES MAY NEED TO BE ALTERED FOR EFFICIENTCY ...
+ // ... but that is of low importance, as there will only be one (or a few) instance(s)
+
+ // demographic parameters
+
+ short repType; // 0 = asexual, 1 = simple two sex, 2 = complex two sex
+ short nStages; // no. of stages (incl. juveniles) in structured population
+ float propMales; // proportion of males at birth in sexual model
+ float harem; // max harem size in complex sexual model
+ float bc; // competition coefficient for non-structured population
+ float lambda; // max intrinsic growth rate for non-structured population
+ float probRep; // probability of reproducing in subsequent seasons
+ short repSeasons; // no. of reproductive seasons per year
+ short repInterval; // no. of reproductive seasons between subsequent reproductions
+ short maxAge; // max age in structured population
+ short survival; // survival timing: 0 = at reprodn, 1 = between reprodns, 2 = anually
+ bool stageStruct;
+ bool fecDens;
+ bool fecStageDens;
+ bool devDens;
+ bool devStageDens;
+ bool survDens;
+ bool survStageDens;
+ bool disperseOnLoss; // individuals disperse on complete loss of patch
+ // (otherwise they die)
+ short habDimK; // dimension of carrying capacities matrix
+ float* habK; // habitat-specific carrying capacities (inds/cell)
+ float devCoeff; // density-dependent development coefficient
+ float survCoeff; // density-dependent survival coefficient
+ float** ddwtFec; // density-dependent weights matrix for fecundity
+ float** ddwtDev; // density-dependent weights matrix for development
+ float** ddwtSurv; // density-dependent weights matrix for survival
+ // NB for the following arrays, sex 0 is females, sex 1 is males
+ float fec[NSTAGES][NSEXES]; // fecundities
+ float dev[NSTAGES][NSEXES]; // development probabilities
+ float surv[NSTAGES][NSEXES]; // survival probabilities
+ short minAge[NSTAGES][NSEXES]; // minimum age to enter stage
+ // NOTE - IN THEORY, NEXT 3 VARIABLES COULD BE COMMON, BUT WE WOULD NEED TO ENSURE THAT
+ // ALL MATRICES ARE DELETED IF THERE IS A CHANGE IN NO. OF STAGES OR REPRODUCTION TYPE
+ // ***** TO BE RECONSIDERED LATER *****
+ short ddwtFecDim; // dimension of density-dependent weights matrix for fecundity
+ short ddwtDevDim; // dimension of density-dependent weights matrix for fecundity
+ short ddwtSurvDim; // dimension of density-dependent weights matrix for fecundity
+ float minRK; // minimum ) growth rate OR carrying capacity
+ float maxRK; // maximum ) (under environmental stochasticity)
+
+ // genome parameters
+
+ short nTraits; // no. of inheritable traits
+ short emigTrait[2]; // to record first and no. of emigration traits
+ short movtTrait[2]; // to record first and no. of transfer traits
+ short settTrait[2]; // to record first and no. of settlement traits
+ bool diploid;
+ bool neutralMarkers; // neutral markers in absence of any adaptive traits
+ bool pleiotropic;
+ bool trait1Chromosome; // 1:1 mapping of chromosome to trait
+ short nChromosomes; // no. of chromosomes
+ double probMutn; // allelic mutation probability
+ double probCrossover; // crossover probability at meiosis
+ double alleleSD; // s.d. of initial allelic values around phenotypic value
+ double mutationSD; // s.d. of mutation magnitude
+ short nNLoci; // no. of nLoci set
+ short* nLoci; // no. of loci per chromosome
+ short nTraitNames; // no. of trait names set
+ traitData* traitdata; // for mapping of chromosome loci to traits
+ string* traitnames; // trait names for parameter output
+
+ // emigration parameters
+
+ bool densDepEmig; // density-dependent emigration
+ bool stgDepEmig; // stage-dependent emigration
+ bool sexDepEmig; // sex-dependent emigration
+ bool indVarEmig; // individual variation in emigration
+ short emigStage; // stage which emigrates (used for stage-strucutred population
+ // having individual variability in emigration probability)
+// NB for the following arrays, sex 0 is females, sex 1 is males
+ float d0[NSTAGES][NSEXES]; // maximum emigration probability
+ float alphaEmig[NSTAGES][NSEXES]; // slope of density-dependent reaction norm
+ float betaEmig[NSTAGES][NSEXES]; // inflection point of reaction norm (in terms of N/K)
+ // NB Initialisation parameters are made double to avoid conversion errors (reason unclear)
+ // on traits maps using FloatToStr()
+ // As evolving traits are not stage-dependent, no. of rows can be 1
+ // Indeed, they could be 1-D arrays
+ double d0Mean[1][NSEXES];
+ double d0SD[1][NSEXES];
+ double alphaMean[1][NSEXES];
+ double alphaSD[1][NSEXES];
+ double betaMean[1][NSEXES];
+ double betaSD[1][NSEXES];
+ double d0Scale; // scaling factor for d0
+ double alphaScale; // scaling factor for alpha
+ double betaScale; // scaling factor for beta
+
+ // transfer parameters
+
+ bool moveModel;
+ bool stgDepTrfr;
+ bool sexDepTrfr;
+ bool distMort;
+ bool indVarTrfr;
+ bool twinKern;
+ bool habMort; // habitat-dependent mortality
+ float meanDist1[NSTAGES][NSEXES]; // mean of 1st dispersal kernel (m)
+ float meanDist2[NSTAGES][NSEXES]; // mean of 2nd dispersal kernel (m)
+ float probKern1[NSTAGES][NSEXES]; // probability of dispersing with the 1st kernel
+ // NB INITIAL limits are made double to avoid conversion errors (reason unclear)
+ // on traits maps using FloatToStr()
+ // As evolving traits are are not stage-dependent, no. of rows can be 1
+ // Indeed, as they are INITIAL limits, which may subsequently be exceeded, they could be
+ // 1-D arrays
+ double dist1Mean[1][NSEXES]; // mean of initial mean of the 1st dispersal kernel (m)
+ double dist1SD[1][NSEXES]; // s.d. of initial mean of the 1st dispersal kernel (m)
+ double dist2Mean[1][NSEXES]; // mean of initial mean of the 2nd dispersal kernel (m)
+ double dist2SD[1][NSEXES]; // s.d. of initial mean of the 2nd dispersal kernel (m)
+ double PKern1Mean[1][NSEXES]; // mean of initial prob. of dispersing with 1st kernel
+ double PKern1SD[1][NSEXES]; // s.d. of initial prob. of dispersing with 1st kernel
+ float dist1Scale; // scaling factor for mean of 1st dispersal kernel (m)
+ float dist2Scale; // scaling factor for mean of 2nd dispersal kernel (m)
+ float PKern1Scale; // scaling factor for prob. of dispersing with 1st kernel
+ float fixedMort; // constant mortality probability
+ float mortAlpha; // slope for mortality distance dependence function
+ float mortBeta; // inflection point for mortality distance dependence function
+ short moveType; // 1 = SMS, 2 = CRW
+ short pr; // SMS perceptual range (cells)
+ short prMethod; // SMS perceptual range evaluation method:
+ // 1 = arith. mean, 2 = harmonic mean, 3 = inverse weighted arith. mean
+ short memSize; // SMS memory size (1-14 steps)
+ short goalType; // SMS goal bias type: 0 = none, 1 = towards goal, 2 = dispersal bias
+ float dp; // SMS directional persistence
+ float gb; // SMS goal bias
+ float alphaDB; // SMS dispersal bias decay rate
+ int betaDB; // SMS dispersal bias decay inflection point (no. of steps)
+ float stepMort; // constant per-step mortality probability for movement models
+ double* habStepMort; // habitat-dependent per-step mortality probability
+ float stepLength; // CRW step length (m)
+ float rho; // CRW correlation coefficient
+ double dpMean[1][NSEXES]; // mean of initial SMS directional persistence
+ double dpSD[1][NSEXES]; // s.d. of initial SMS directional persistence
+ double gbMean[1][NSEXES]; // mean of initial SMS goal bias
+ double gbSD[1][NSEXES]; // s.d. of initial SMS goal bias
+ double alphaDBMean[1][NSEXES]; // mean of initial SMS dispersal bias decay rate
+ double alphaDBSD[1][NSEXES]; // s.d. of initial SMS dispersal bias decay rate
+ double betaDBMean[1][NSEXES]; // mean of initial SMS dispersal bias decay infl. pt.
+ double betaDBSD[1][NSEXES]; // s.d. of initial SMS dispersal bias decay infl. pt.
+ float dpScale; // scaling factor for SMS directional persistence
+ float gbScale; // scaling factor for SMS goal bias
+ float alphaDBScale; // scaling factor for SMS dispersal bias decay rate
+ float betaDBScale; // scaling factor for SMS dispersal bias decay infl. pt.
+ double stepLgthMean[1][NSEXES]; // mean of initial step length (m)
+ double stepLgthSD[1][NSEXES]; // s.d. of initial step length (m)
+ double rhoMean[1][NSEXES]; // mean of initial correlation coefficient
+ double rhoSD[1][NSEXES]; // s.d. of initial correlation coefficient
+ float stepLScale; // scaling factor for step length (m)
+ float rhoScale; // scaling factor for correlation coefficient
+ short habDimTrfr; // dimension of habitat-dependent step mortality and costs matrices
+ int* habCost; // habitat costs
+ bool costMap; // import cost map from file?
+ bool straigtenPath; // straighten path after decision not to settle
+ bool fullKernel; // used to indicate special case when density-independent emigration
+ // is 1.0, and kernel-based movement within the natal cell is used
+ // to determine philopatry
+
+// settlement parameters
+
+ bool stgDepSett;
+ bool sexDepSett;
+ bool indVarSett; // individual variation in settlement
+ bool densDepSett[NSTAGES][NSEXES];
+ bool wait[NSTAGES][NSEXES]; // wait to continue moving next season (stage-structured model only)
+ bool go2nbrLocn[NSTAGES][NSEXES]; // settle in neighbouring cell/patch if available (ditto)
+ bool findMate[NSTAGES][NSEXES];
+ int minSteps; // minimum no. of steps
+ int maxSteps; // maximum total no. of steps
+ int maxStepsYr[NSTAGES][NSEXES]; // maximum no. of steps in any one dispersal period
+ float s0[NSTAGES][NSEXES]; // maximum settlement probability
+ float alphaS[NSTAGES][NSEXES]; // slope of the settlement reaction norm to density
+ float betaS[NSTAGES][NSEXES]; // inflection point of the settlement reaction norm to density
+ double s0Mean[1][NSEXES]; // mean of initial maximum settlement probability
+ double s0SD[1][NSEXES]; // s.d. of initial maximum settlement probability
+ double alphaSMean[1][NSEXES]; // mean of initial settlement reaction norm slope
+ double alphaSSD[1][NSEXES]; // s.d. of initial settlement reaction norm slope
+ double betaSMean[1][NSEXES]; // mean of initial settlement reaction norm inflection point
+ double betaSSD[1][NSEXES]; // s.d. of initial settlement reaction norm inflection point
+ float s0Scale; // scaling factor for maximum settlement probability
+ float alphaSScale; // scaling factor for settlement reaction norm slope
+ float betaSScale; // scaling factor for settlement reaction norm inflection point
+
+ // other attributes
+
+ int spNum;
+
+};
+
+/* IMPORTANT NOTE:
+At the time of writing (24/4/14) the stage- and sex-dependent parameters for emigration
+and dispersal (e.g. d0[NSTAGES][NSEXES]) are set according to the appropriate stage- and
+sex-dependent settings; thus a species could be structured and sexual, but parameter values
+are set for elements [0][0] only if emigration/transfer is stage- and sex-independent.
+However, the parameters for settlement are set for ALL stages and sexes appropriate to the
+species, regardless of settlement dependency. The rationale for this is that settlement
+parameters need to be accessed many more times for a movement model (at each step) than
+emigration or transfer parameters, and therefore there will be a performance gain in
+avoiding nested if statements in Individual::moveStep() which would otherwise be required
+to get the correct parameter values from the settlement arrays. Whether that particular
+rationale is justified remains to be tested!
+*/
+
+//---------------------------------------------------------------------------
+
+#if RSDEBUG
+//extern ofstream DEBUGLOG;
+extern void DebugGUI(string);
+#endif
+
+//---------------------------------------------------------------------------
+#endif
diff --git a/src/RScore/SubCommunity.cpp b/src/RScore/SubCommunity.cpp
new file mode 100644
index 00000000..d908892a
--- /dev/null
+++ b/src/RScore/SubCommunity.cpp
@@ -0,0 +1,1008 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+ //---------------------------------------------------------------------------
+
+#include "SubCommunity.h"
+//---------------------------------------------------------------------------
+
+ofstream outtraits;
+
+//---------------------------------------------------------------------------
+
+SubCommunity::SubCommunity(Patch* pPch, int num) {
+ subCommNum = num;
+ pPatch = pPch;
+ // record the new sub-community no. in the patch
+ pPatch->setSubComm((intptr)this);
+ initial = false;
+ occupancy = 0;
+}
+
+SubCommunity::~SubCommunity() {
+ pPatch->setSubComm(0);
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ delete popns[i];
+ }
+ popns.clear();
+ if (occupancy != 0) delete[] occupancy;
+}
+
+intptr SubCommunity::getNum(void) { return subCommNum; }
+
+Patch* SubCommunity::getPatch(void) { return pPatch; }
+
+locn SubCommunity::getLocn(void) {
+ locn loc = pPatch->getCellLocn(0);
+ return loc;
+}
+
+void SubCommunity::setInitial(bool b) { initial = b; }
+
+void SubCommunity::initialise(Landscape* pLandscape, Species* pSpecies)
+{
+ int ncells;
+ landParams ppLand = pLandscape->getLandParams();
+ initParams init = paramsInit->getInit();
+ // determine size of initial population
+ int nInds = 0;
+ if (subCommNum == 0 // matrix patch
+ || !initial) // not in initial region or distribution
+ nInds = 0;
+ else {
+ float k = pPatch->getK();
+ if (k > 0.0) { // patch is currently suitable for this species
+ switch (init.initDens) {
+ case 0: // at carrying capacity
+ nInds = (int)k;
+ break;
+ case 1: // at half carrying capacity
+ nInds = (int)(k / 2.0);
+ break;
+ case 2: // specified no. per cell or density
+ ncells = pPatch->getNCells();
+ if (ppLand.patchModel) {
+ nInds = (int)(init.indsHa * (float)(ncells * ppLand.resol * ppLand.resol) / 10000.0);
+ }
+ else {
+ nInds = init.indsCell * ncells;
+ }
+ break;
+ }
+ }
+ else nInds = 0;
+ }
+ // create new population only if it is non-zero or the matrix popn
+ if (subCommNum == 0 || nInds > 0) {
+ newPopn(pLandscape, pSpecies, pPatch, nInds);
+ }
+}
+
+// initialise a specified individual
+void SubCommunity::initialInd(Landscape* pLandscape, Species* pSpecies,
+ Patch* pPatch, Cell* pCell, int ix)
+{
+
+ demogrParams dem = pSpecies->getDemogr();
+ stageParams sstruct = pSpecies->getStage();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ genomeData gen = pSpecies->getGenomeData();
+ short stg, age, repInt;
+ Individual* pInd;
+ float probmale;
+
+ // create new population if not already in existence
+ int npopns = (int)popns.size();
+ if (npopns < 1) {
+ newPopn(pLandscape, pSpecies, pPatch, 0);
+ }
+
+ // create new individual
+ initInd iind = paramsInit->getInitInd(ix);
+ if (dem.stageStruct) {
+ stg = iind.stage; age = iind.age; repInt = sstruct.repInterval;
+ }
+ else {
+ age = stg = 1; repInt = 0;
+ }
+ if (dem.repType == 0) {
+ probmale = 0.0;
+ }
+ else {
+ if (iind.sex == 1) probmale = 1.0; else probmale = 0.0;
+ }
+ pInd = new Individual(pCell, pPatch, stg, age, repInt, probmale, trfr.moveModel, trfr.moveType);
+
+ // add new individual to the population
+ // NB THIS WILL NEED TO BE CHANGED FOR MULTIPLE SPECIES...
+ popns[0]->recruit(pInd);
+
+ if (emig.indVar || trfr.indVar || sett.indVar || gen.neutralMarkers)
+ {
+ // individual variation - set up genetics
+ landData land = pLandscape->getLandData();
+ pInd->setGenes(pSpecies, land.resol);
+ }
+
+}
+
+// Create a new population, and return its address
+Population* SubCommunity::newPopn(Landscape* pLandscape, Species* pSpecies,
+ Patch* pPatch, int nInds)
+{
+ landParams land = pLandscape->getLandParams();
+ int npopns = (int)popns.size();
+ popns.push_back(new Population(pSpecies, pPatch, nInds, land.resol));
+ return popns[npopns];
+}
+
+popStats SubCommunity::getPopStats(void) {
+ popStats p, pop;
+ p.pSpecies = 0; p.spNum = 0; p.nInds = p.nAdults = p.nNonJuvs = 0; p.breeding = false;
+ p.pPatch = pPatch;
+ // FOR SINGLE SPECIES IMPLEMENTATION, THERE IS ONLY ONE POPULATION IN THE PATCH
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ pop = popns[i]->getStats();
+ p.pSpecies = pop.pSpecies;
+ p.spNum = pop.spNum;
+ p.nInds += pop.nInds;
+ p.nNonJuvs += pop.nNonJuvs;
+ p.nAdults += pop.nAdults;
+ p.breeding = pop.breeding;
+ }
+ return p;
+}
+
+void SubCommunity::resetPopns(void) {
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ delete popns[i];
+ }
+ popns.clear();
+ // clear the list of populations in the corresponding patch
+ pPatch->resetPopn();
+}
+
+void SubCommunity::resetPossSettlers(void) {
+ if (subCommNum == 0) return; // not applicable in the matrix
+ pPatch->resetPossSettlers();
+}
+
+// Extirpate all populations according to
+// option 0 - random local extinction probability
+// option 1 - local extinction probability gradient
+// NB only applied for cell-based model
+void SubCommunity::localExtinction(int option) {
+ double pExtinct = 0.0;
+ if (option == 0) {
+ envStochParams env = paramsStoch->getStoch();
+ if (env.localExt) pExtinct = env.locExtProb;
+ }
+ else {
+ envGradParams grad = paramsGrad->getGradient();
+ Cell* pCell = pPatch->getRandomCell(); // get only cell in the patch
+ // extinction prob is complement of cell gradient value plus any non-zero prob at the optimum
+ pExtinct = 1.0 - pCell->getEnvVal() + grad.extProbOpt;
+ if (pExtinct > 1.0) pExtinct = 1.0;
+ }
+ if (pRandom->Bernoulli(pExtinct)) {
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ popns[i]->extirpate();
+ }
+ }
+}
+
+// Action in event of patch becoming unsuitable owing to landscape change
+void SubCommunity::patchChange(void) {
+ if (subCommNum == 0) return; // no reproduction in the matrix
+ Species* pSpecies;
+ float localK = 0.0;
+ int npops = (int)popns.size();
+ // THE FOLLOWING MAY BE MORE EFFICIENT WHILST THERE IS ONLY ONE SPECIES ...
+ if (npops < 1) return;
+ localK = pPatch->getK();
+ if (localK <= 0.0) { // patch in dynamic landscape has become unsuitable
+ for (int i = 0; i < npops; i++) { // all populations
+ pSpecies = popns[i]->getSpecies();
+ demogrParams dem = pSpecies->getDemogr();
+ if (dem.stageStruct) {
+ stageParams sstruct = pSpecies->getStage();
+ if (sstruct.disperseOnLoss) popns[i]->allEmigrate();
+ else popns[i]->extirpate();
+ }
+ else { // non-stage-structured species is destroyed
+ popns[i]->extirpate();
+ }
+ }
+ }
+}
+
+void SubCommunity::reproduction(int resol, float epsGlobal, short rasterType, bool patchModel)
+{
+ if (subCommNum == 0) return; // no reproduction in the matrix
+ float localK, envval;
+ Cell* pCell;
+ envGradParams grad = paramsGrad->getGradient();
+ envStochParams env = paramsStoch->getStoch();
+
+ int npops = (int)popns.size();
+ // THE FOLLOWING MAY BE MORE EFFICIENT WHILST THERE IS ONLY ONE SPECIES ...
+ if (npops < 1) return;
+
+ localK = pPatch->getK();
+ if (localK > 0.0) {
+ if (patchModel) {
+ envval = 1.0; // environmental gradient is currently not applied for patch-based model
+ }
+ else { // cell-based model
+ if (grad.gradient && grad.gradType == 2)
+ { // gradient in fecundity
+ Cell* pCell = pPatch->getRandomCell(); // locate the only cell in the patch
+ envval = pCell->getEnvVal();
+ }
+ else envval = 1.0;
+ }
+ if (env.stoch && !env.inK) { // stochasticity in fecundity
+ if (env.local) {
+ if (!patchModel) { // only permitted for cell-based model
+ pCell = pPatch->getRandomCell();
+ if (pCell != 0) envval += pCell->getEps();
+ }
+ }
+ else { // global stochasticity
+ envval += epsGlobal;
+ }
+ }
+ for (int i = 0; i < npops; i++) { // all populations
+ popns[i]->reproduction(localK, envval, resol);
+ popns[i]->fledge();
+ }
+ }
+}
+
+void SubCommunity::emigration(void)
+{
+ if (subCommNum == 0) return; // no emigration from the matrix
+ float localK;
+ int npops = (int)popns.size();
+ // THE FOLLOWING MAY BE MORE EFFICIENT WHILST THERE IS ONLY ONE SPECIES ...
+ if (npops < 1) return;
+ localK = pPatch->getK();
+ // NOTE that even if K is zero, it could have been >0 in previous time-step, and there
+ // might be emigrants if there is non-juvenile emigration
+ for (int i = 0; i < npops; i++) { // all populations
+ popns[i]->emigration(localK);
+ }
+}
+
+// Remove emigrants from their natal patch and add to patch 0 (matrix)
+void SubCommunity::initiateDispersal(SubCommunity* matrix) {
+ if (subCommNum == 0) return; // no dispersal initiation in the matrix
+ popStats pop;
+ disperser disp;
+
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ pop = popns[i]->getStats();
+ for (int j = 0; j < pop.nInds; j++) {
+ disp = popns[i]->extractDisperser(j);
+ if (disp.yes) { // disperser - has already been removed from natal population
+ // add to matrix population
+ matrix->recruit(disp.pInd, pop.pSpecies);
+ }
+ }
+ // remove pointers to emigrants
+ popns[i]->clean();
+ }
+
+}
+
+// Add an individual into the local population of its species in the patch
+void SubCommunity::recruit(Individual* pInd, Species* pSpecies) {
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ if (pSpecies == popns[i]->getSpecies()) {
+ popns[i]->recruit(pInd);
+ }
+ }
+}
+
+// Transfer through the matrix - run for the matrix sub-community only
+#if RS_RCPP
+int SubCommunity::transfer(Landscape* pLandscape, short landIx, short nextseason)
+#else
+int SubCommunity::transfer(Landscape* pLandscape, short landIx)
+#endif // RS_RCPP
+{
+ int ndispersers = 0;
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+#if RS_RCPP
+ ndispersers += popns[i]->transfer(pLandscape, landIx, nextseason);
+#else
+ ndispersers += popns[i]->transfer(pLandscape, landIx);
+#endif // RS_RCPP
+
+ }
+ return ndispersers;
+}
+
+//---------------------------------------------------------------------------
+
+// Remove emigrants from patch 0 (matrix) and transfer to sub-community
+// in which their destination co-ordinates fall
+// This function is executed for the matrix patch only
+
+void SubCommunity::completeDispersal(Landscape* pLandscape, bool connect)
+{
+ int popsize;
+ disperser settler;
+ Species* pSpecies;
+ Population* pPop;
+ Patch* pPrevPatch;
+ Patch* pNewPatch;
+ Cell* pPrevCell;
+ SubCommunity* pSubComm;
+
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ pSpecies = popns[i]->getSpecies();
+ popsize = popns[i]->getNInds();
+ for (int j = 0; j < popsize; j++) {
+ bool settled;
+ settler = popns[i]->extractSettler(j);
+ settled = settler.yes;
+ if (settled) {
+ // settler - has already been removed from matrix population
+ // find new patch
+ pNewPatch = (Patch*)settler.pCell->getPatch();
+ // find population within the patch (if there is one)
+ pPop = (Population*)pNewPatch->getPopn((intptr)pSpecies);
+ if (pPop == 0) { // settler is the first in a previously uninhabited patch
+ // create a new population in the corresponding sub-community
+ pSubComm = (SubCommunity*)pNewPatch->getSubComm();
+ pPop = pSubComm->newPopn(pLandscape, pSpecies, pNewPatch, 0);
+ }
+ pPop->recruit(settler.pInd);
+ if (connect) { // increment connectivity totals
+ int newpatch = pNewPatch->getSeqNum();
+ pPrevCell = settler.pInd->getLocn(0); // previous cell
+ intptr patch = pPrevCell->getPatch();
+ if (patch != 0) {
+ pPrevPatch = (Patch*)patch;
+ int prevpatch = pPrevPatch->getSeqNum();
+ pLandscape->incrConnectMatrix(prevpatch, newpatch);
+ }
+ }
+ }
+ else { // for group dispersal only
+ }
+ }
+ // remove pointers in the matrix popn to settlers
+ popns[i]->clean();
+ }
+
+}
+
+//---------------------------------------------------------------------------
+
+void SubCommunity::survival(short part, short option0, short option1)
+{
+ int npops = (int)popns.size();
+ if (npops < 1) return;
+ if (part == 0) {
+ float localK = pPatch->getK();
+ for (int i = 0; i < npops; i++) { // all populations
+ popns[i]->survival0(localK, option0, option1);
+ }
+ }
+ else {
+ for (int i = 0; i < npops; i++) { // all populations
+ popns[i]->survival1();
+ }
+ }
+}
+
+void SubCommunity::ageIncrement(void) {
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ popns[i]->ageIncrement();
+ }
+}
+
+// Find the population of a given species in a given patch
+Population* SubCommunity::findPop(Species* pSp, Patch* pPch) {
+#if RSDEBUG
+ DEBUGLOG << "SubCommunity::findPop(): this=" << this
+ << endl;
+#endif
+
+ Population* pPop = 0;
+ popStats pop;
+ int npops = (int)popns.size();
+
+ for (int i = 0; i < npops; i++) { // all populations
+ pop = popns[i]->getStats();
+ if (pop.pSpecies == pSp && pop.pPatch == pPch) { // population located
+ pPop = popns[i];
+ break;
+ }
+ else pPop = 0;
+ }
+ return pPop;
+}
+
+//---------------------------------------------------------------------------
+
+void SubCommunity::createOccupancy(int nrows) {
+ if (occupancy != 0) deleteOccupancy();
+ if (nrows > 0) {
+ occupancy = new int[nrows];
+ for (int i = 0; i < nrows; i++) occupancy[i] = 0;
+ }
+}
+
+void SubCommunity::updateOccupancy(int row) {
+ popStats pop;
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) {
+ pop = popns[i]->getStats();
+ if (pop.nInds > 0 && pop.breeding) {
+ occupancy[row]++;
+ i = npops;
+ }
+ }
+}
+
+int SubCommunity::getOccupancy(int row) {
+ if (row >= 0) return occupancy[row];
+ else return 0;
+}
+
+void SubCommunity::deleteOccupancy(void) {
+ delete[] occupancy;
+ occupancy = 0;
+}
+
+//---------------------------------------------------------------------------
+// Open population file and write header record
+bool SubCommunity::outPopHeaders(Landscape* pLandscape, Species* pSpecies, int option)
+{
+ bool fileOK;
+ Population* pPop;
+ landParams land = pLandscape->getLandParams();
+
+ if (option == -999) { // close the file
+ // as all populations may have been deleted, set up a dummy one
+ // species is not necessary
+ pPop = new Population();
+ fileOK = pPop->outPopHeaders(-999, land.patchModel);
+ delete pPop;
+ }
+ else { // open the file
+ // as no population has yet been created, set up a dummy one
+ // species is necessary, as columns depend on stage and sex structure
+ pPop = new Population(pSpecies, pPatch, 0, land.resol);
+ fileOK = pPop->outPopHeaders(land.landNum, land.patchModel);
+ delete pPop;
+ }
+ return fileOK;
+}
+
+// Write records to population file
+void SubCommunity::outPop(Landscape* pLandscape, int rep, int yr, int gen)
+{
+ landParams land = pLandscape->getLandParams();
+ envGradParams grad = paramsGrad->getGradient();
+ envStochParams env = paramsStoch->getStoch();
+ bool writeEnv = false;
+ bool gradK = false;
+ if (grad.gradient) {
+ writeEnv = true;
+ if (grad.gradType == 1) gradK = true; // ... carrying capacity
+ }
+ if (env.stoch) writeEnv = true;
+
+ // generate output for each population within the sub-community (patch)
+ // provided that the patch is suitable (i.e. non-zero carrying capacity)
+ // or the population is above zero (possible if there is stochasticity or a moving gradient)
+ // or it is the matrix patch in a patch-based model
+ int npops = (int)popns.size();
+ int patchnum;
+ Cell* pCell;
+ float localK;
+ float eps = 0.0;
+ if (env.stoch) {
+ if (env.local) {
+ pCell = pPatch->getRandomCell();
+ if (pCell != 0) eps = pCell->getEps();
+ }
+ else {
+ eps = pLandscape->getGlobalStoch(yr);
+ }
+ }
+
+ patchnum = pPatch->getPatchNum();
+ for (int i = 0; i < npops; i++) { // all populations
+ localK = pPatch->getK();
+ if (localK > 0.0 || (land.patchModel && patchnum == 0)) {
+ popns[i]->outPopulation(rep, yr, gen, eps, land.patchModel, writeEnv, gradK);
+ }
+ else {
+ if (popns[i]->totalPop() > 0) {
+ popns[i]->outPopulation(rep, yr, gen, eps, land.patchModel, writeEnv, gradK);
+ }
+ }
+ }
+}
+
+// Write records to individuals file
+void SubCommunity::outInds(Landscape* pLandscape, int rep, int yr, int gen, int landNr) {
+ landParams ppLand = pLandscape->getLandParams();
+ if (landNr >= 0) { // open the file
+ popns[0]->outIndsHeaders(rep, landNr, ppLand.patchModel);
+ return;
+ }
+ if (landNr == -999) { // close the file
+ popns[0]->outIndsHeaders(rep, -999, ppLand.patchModel);
+ return;
+ }
+ // generate output for each population within the sub-community (patch)
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ popns[i]->outIndividual(pLandscape, rep, yr, gen, pPatch->getPatchNum());
+ }
+}
+
+// Write records to individuals file
+void SubCommunity::outGenetics(int rep, int yr, int gen, int landNr)
+{
+ if (landNr >= 0) { // open the file
+ popns[0]->outGenetics(rep, yr, landNr);
+ return;
+ }
+ if (landNr == -999) { // close the file
+ popns[0]->outGenetics(rep, yr, landNr);
+ return;
+ }
+ // generate output for each population within the sub-community (patch)
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ popns[i]->outGenetics(rep, yr, landNr);
+ }
+}
+
+// Population size of a specified stage
+int SubCommunity::stagePop(int stage) {
+ int popsize = 0;
+ int npops = (int)popns.size();
+ for (int i = 0; i < npops; i++) { // all populations
+ popsize += popns[i]->stagePop(stage);
+ }
+ return popsize;
+}
+
+// Open traits file and write header record
+bool SubCommunity::outTraitsHeaders(Landscape* pLandscape, Species* pSpecies, int landNr)
+{
+ landParams land = pLandscape->getLandParams();
+ if (landNr == -999) { // close file
+ if (outtraits.is_open()) outtraits.close();
+ outtraits.clear();
+ return true;
+ }
+
+ string name;
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ simParams sim = paramsSim->getSim();
+
+ string DirOut = paramsSim->getDir(2);
+ if (sim.batchMode) {
+ if (land.patchModel) {
+ name = DirOut
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation) + "_Land" + Int2Str(landNr)
+ + "_TraitsXpatch.txt";
+ }
+ else {
+ name = DirOut
+ + "Batch" + Int2Str(sim.batchNum) + "_"
+ + "Sim" + Int2Str(sim.simulation) + "_Land" + Int2Str(landNr)
+ + "_TraitsXcell.txt";
+ }
+ }
+ else {
+ if (land.patchModel) {
+ name = DirOut + "Sim" + Int2Str(sim.simulation) + "_TraitsXpatch.txt";
+ }
+ else {
+ name = DirOut + "Sim" + Int2Str(sim.simulation) + "_TraitsXcell.txt";
+ }
+ }
+ outtraits.open(name.c_str());
+
+ outtraits << "Rep\tYear\tRepSeason";
+ if (land.patchModel) outtraits << "\tPatchID";
+ else
+ outtraits << "\tx\ty";
+
+ if (emig.indVar) {
+ if (emig.sexDep) {
+ if (emig.densDep) {
+ outtraits << "\tF_meanD0\tF_stdD0\tM_meanD0\tM_stdD0";
+ outtraits << "\tF_meanAlpha\tF_stdAlpha\tM_meanAlpha\tM_stdAlpha";
+ outtraits << "\tF_meanBeta\tF_stdBeta\tM_meanBeta\tM_stdBeta";
+ }
+ else {
+ outtraits << "\tF_meanEP\tF_stdEP\tM_meanEP\tM_stdEP";
+ }
+ }
+ else {
+ if (emig.densDep) {
+ outtraits << "\tmeanD0\tstdD0\tmeanAlpha\tstdAlpha";
+ outtraits << "\tmeanBeta\tstdBeta";
+ }
+ else {
+ outtraits << "\tmeanEP\tstdEP";
+ }
+ }
+ }
+ if (trfr.indVar) {
+ if (trfr.moveModel) {
+ if (trfr.moveType == 1) {
+ outtraits << "\tmeanDP\tstdDP\tmeanGB\tstdGB";
+ outtraits << "\tmeanAlphaDB\tstdAlphaDB\tmeanBetaDB\tstdBetaDB";
+ }
+ if (trfr.moveType == 2) {
+ outtraits << "\tmeanStepLength\tstdStepLength\tmeanRho\tstdRho";
+ }
+ }
+ else {
+ if (trfr.sexDep) {
+ outtraits << "\tF_mean_distI\tF_std_distI\tM_mean_distI\tM_std_distI";
+ if (trfr.twinKern)
+ outtraits << "\tF_mean_distII\tF_std_distII\tM_mean_distII\tM_std_distII"
+ << "\tF_meanPfirstKernel\tF_stdPfirstKernel"
+ << "\tM_meanPfirstKernel\tM_stdPfirstKernel";
+ }
+ else {
+ outtraits << "\tmean_distI\tstd_distI";
+ if (trfr.twinKern)
+ outtraits << "\tmean_distII\tstd_distII\tmeanPfirstKernel\tstdPfirstKernel";
+ }
+ }
+ }
+ if (sett.indVar) {
+ if (sett.sexDep) {
+ outtraits << "\tF_meanS0\tF_stdS0\tM_meanS0\tM_stdS0";
+ outtraits << "\tF_meanAlphaS\tF_stdAlphaS\tM_meanAlphaS\tM_stdAlphaS";
+ outtraits << "\tF_meanBetaS\tF_stdBetaS\tM_meanBetaS\tM_stdBetaS";
+ }
+ else {
+ outtraits << "\tmeanS0\tstdS0";
+ outtraits << "\tmeanAlphaS\tstdAlphaS";
+ outtraits << "\tmeanBetaS\tstdBetaS";
+ }
+ }
+ outtraits << endl;
+
+ return outtraits.is_open();
+}
+
+// Write records to traits file and return aggregated sums
+traitsums SubCommunity::outTraits(traitCanvas tcanv,
+ Landscape* pLandscape, int rep, int yr, int gen, bool commlevel)
+{
+ int popsize, ngenes;
+ landParams land = pLandscape->getLandParams();
+ simParams sim = paramsSim->getSim();
+ bool writefile = false;
+ if (sim.outTraitsCells && yr % sim.outIntTraitCell == 0 && !commlevel)
+ writefile = true;
+ traitsums ts, poptraits;
+ for (int i = 0; i < NSEXES; i++) {
+ ts.ninds[i] = 0;
+ ts.sumD0[i] = ts.ssqD0[i] = 0.0;
+ ts.sumAlpha[i] = ts.ssqAlpha[i] = 0.0; ts.sumBeta[i] = ts.ssqBeta[i] = 0.0;
+ ts.sumDist1[i] = ts.ssqDist1[i] = 0.0; ts.sumDist2[i] = ts.ssqDist2[i] = 0.0;
+ ts.sumProp1[i] = ts.ssqProp1[i] = 0.0;
+ ts.sumDP[i] = ts.ssqDP[i] = 0.0;
+ ts.sumGB[i] = ts.ssqGB[i] = 0.0;
+ ts.sumAlphaDB[i] = ts.ssqAlphaDB[i] = 0.0;
+ ts.sumBetaDB[i] = ts.ssqBetaDB[i] = 0.0;
+ ts.sumStepL[i] = ts.ssqStepL[i] = 0.0; ts.sumRho[i] = ts.ssqRho[i] = 0.0;
+ ts.sumS0[i] = ts.ssqS0[i] = 0.0;
+ ts.sumAlphaS[i] = ts.ssqAlphaS[i] = 0.0; ts.sumBetaS[i] = ts.ssqBetaS[i] = 0.0;
+ }
+
+ // generate output for each population within the sub-community (patch)
+ // provided that the patch is suitable (i.e. non-zero carrying capacity)
+ int npops = (int)popns.size();
+ Species* pSpecies;
+ float localK;
+
+ for (int i = 0; i < npops; i++) { // all populations
+ localK = pPatch->getK();
+ if (localK > 0.0 && popns[i]->getNInds() > 0) {
+ pSpecies = popns[i]->getSpecies();
+ demogrParams dem = pSpecies->getDemogr();
+ emigRules emig = pSpecies->getEmig();
+ trfrRules trfr = pSpecies->getTrfr();
+ settleType sett = pSpecies->getSettle();
+ poptraits = popns[i]->getTraits(pSpecies);
+
+ if (writefile) {
+ outtraits << rep << "\t" << yr << "\t" << gen;
+ if (land.patchModel) {
+ outtraits << "\t" << pPatch->getPatchNum();
+ }
+ else {
+ locn loc = pPatch->getCellLocn(0);
+ outtraits << "\t" << loc.x << "\t" << loc.y;
+ }
+ }
+
+ if (emig.indVar) {
+ if (emig.sexDep) { // must be a sexual species
+ ngenes = 2;
+ }
+ else {
+ if (dem.repType == 0) { // asexual reproduction
+ ngenes = 1;
+ }
+ else { // sexual reproduction
+ ngenes = 1;
+ }
+ }
+ double mnD0[2], mnAlpha[2], mnBeta[2], sdD0[2], sdAlpha[2], sdBeta[2];
+ for (int g = 0; g < ngenes; g++) {
+ mnD0[g] = mnAlpha[g] = mnBeta[g] = sdD0[g] = sdAlpha[g] = sdBeta[g] = 0.0;
+ // individuals may have been counted by sex if there was
+ // sex dependency in another dispersal phase
+ if (ngenes == 2) popsize = poptraits.ninds[g];
+ else popsize = poptraits.ninds[0] + poptraits.ninds[1];
+ if (popsize > 0) {
+ mnD0[g] = poptraits.sumD0[g] / (double)popsize;
+ mnAlpha[g] = poptraits.sumAlpha[g] / (double)popsize;
+ mnBeta[g] = poptraits.sumBeta[g] / (double)popsize;
+ if (popsize > 1) {
+ sdD0[g] = poptraits.ssqD0[g] / (double)popsize - mnD0[g] * mnD0[g];
+ if (sdD0[g] > 0.0) sdD0[g] = sqrt(sdD0[g]); else sdD0[g] = 0.0;
+ sdAlpha[g] = poptraits.ssqAlpha[g] / (double)popsize - mnAlpha[g] * mnAlpha[g];
+ if (sdAlpha[g] > 0.0) sdAlpha[g] = sqrt(sdAlpha[g]); else sdAlpha[g] = 0.0;
+ sdBeta[g] = poptraits.ssqBeta[g] / (double)popsize - mnBeta[g] * mnBeta[g];
+ if (sdBeta[g] > 0.0) sdBeta[g] = sqrt(sdBeta[g]); else sdBeta[g] = 0.0;
+ }
+ else {
+ sdD0[g] = sdAlpha[g] = sdBeta[g] = 0.0;
+ }
+ }
+ }
+ if (writefile) {
+ if (emig.sexDep) {
+ outtraits << "\t" << mnD0[0] << "\t" << sdD0[0];
+ outtraits << "\t" << mnD0[1] << "\t" << sdD0[1];
+ if (emig.densDep) {
+ outtraits << "\t" << mnAlpha[0] << "\t" << sdAlpha[0];
+ outtraits << "\t" << mnAlpha[1] << "\t" << sdAlpha[1];
+ outtraits << "\t" << mnBeta[0] << "\t" << sdBeta[0];
+ outtraits << "\t" << mnBeta[1] << "\t" << sdBeta[1];
+ }
+ }
+ else { // sex-independent
+ outtraits << "\t" << mnD0[0] << "\t" << sdD0[0];
+ if (emig.densDep) {
+ outtraits << "\t" << mnAlpha[0] << "\t" << sdAlpha[0];
+ outtraits << "\t" << mnBeta[0] << "\t" << sdBeta[0];
+ }
+ }
+ }
+ }
+
+ if (trfr.indVar) {
+ if (trfr.moveModel) {
+ // CURRENTLY INDIVIDUAL VARIATION CANNOT BE SEX-DEPENDENT
+ ngenes = 1;
+ }
+ else {
+ if (trfr.sexDep) { // must be a sexual species
+ ngenes = 2;
+ }
+ else {
+ ngenes = 1;
+ }
+ }
+ double mnDist1[2], mnDist2[2], mnProp1[2], mnStepL[2], mnRho[2];
+ double sdDist1[2], sdDist2[2], sdProp1[2], sdStepL[2], sdRho[2];
+ double mnDP[2], mnGB[2], mnAlphaDB[2], mnBetaDB[2];
+ double sdDP[2], sdGB[2], sdAlphaDB[2], sdBetaDB[2];
+ for (int g = 0; g < ngenes; g++) {
+ mnDist1[g] = mnDist2[g] = mnProp1[g] = mnStepL[g] = mnRho[g] = 0.0;
+ sdDist1[g] = sdDist2[g] = sdProp1[g] = sdStepL[g] = sdRho[g] = 0.0;
+ mnDP[g] = mnGB[g] = mnAlphaDB[g] = mnBetaDB[g] = 0.0;
+ sdDP[g] = sdGB[g] = sdAlphaDB[g] = sdBetaDB[g] = 0.0;
+ // individuals may have been counted by sex if there was
+ // sex dependency in another dispersal phase
+ if (ngenes == 2) popsize = poptraits.ninds[g];
+ else popsize = poptraits.ninds[0] + poptraits.ninds[1];
+ if (popsize > 0) {
+ mnDist1[g] = poptraits.sumDist1[g] / (double)popsize;
+ mnDist2[g] = poptraits.sumDist2[g] / (double)popsize;
+ mnProp1[g] = poptraits.sumProp1[g] / (double)popsize;
+ mnStepL[g] = poptraits.sumStepL[g] / (double)popsize;
+ mnRho[g] = poptraits.sumRho[g] / (double)popsize;
+ mnDP[g] = poptraits.sumDP[g] / (double)popsize;
+ mnGB[g] = poptraits.sumGB[g] / (double)popsize;
+ mnAlphaDB[g] = poptraits.sumAlphaDB[g] / (double)popsize;
+ mnBetaDB[g] = poptraits.sumBetaDB[g] / (double)popsize;
+ if (popsize > 1) {
+ sdDist1[g] = poptraits.ssqDist1[g] / (double)popsize - mnDist1[g] * mnDist1[g];
+ if (sdDist1[g] > 0.0) sdDist1[g] = sqrt(sdDist1[g]); else sdDist1[g] = 0.0;
+ sdDist2[g] = poptraits.ssqDist2[g] / (double)popsize - mnDist2[g] * mnDist2[g];
+ if (sdDist2[g] > 0.0) sdDist2[g] = sqrt(sdDist2[g]); else sdDist2[g] = 0.0;
+ sdProp1[g] = poptraits.ssqProp1[g] / (double)popsize - mnProp1[g] * mnProp1[g];
+ if (sdProp1[g] > 0.0) sdProp1[g] = sqrt(sdProp1[g]); else sdProp1[g] = 0.0;
+ sdStepL[g] = poptraits.ssqStepL[g] / (double)popsize - mnStepL[g] * mnStepL[g];
+ if (sdStepL[g] > 0.0) sdStepL[g] = sqrt(sdStepL[g]); else sdStepL[g] = 0.0;
+ sdRho[g] = poptraits.ssqRho[g] / (double)popsize - mnRho[g] * mnRho[g];
+ if (sdRho[g] > 0.0) sdRho[g] = sqrt(sdRho[g]); else sdRho[g] = 0.0;
+ sdDP[g] = poptraits.ssqDP[g] / (double)popsize - mnDP[g] * mnDP[g];
+ if (sdDP[g] > 0.0) sdDP[g] = sqrt(sdDP[g]); else sdDP[g] = 0.0;
+ sdGB[g] = poptraits.ssqGB[g] / (double)popsize - mnGB[g] * mnGB[g];
+ if (sdGB[g] > 0.0) sdGB[g] = sqrt(sdGB[g]); else sdGB[g] = 0.0;
+ sdAlphaDB[g] = poptraits.ssqAlphaDB[g] / (double)popsize - mnAlphaDB[g] * mnAlphaDB[g];
+ if (sdAlphaDB[g] > 0.0) sdAlphaDB[g] = sqrt(sdAlphaDB[g]); else sdAlphaDB[g] = 0.0;
+ sdBetaDB[g] = poptraits.ssqBetaDB[g] / (double)popsize - mnBetaDB[g] * mnBetaDB[g];
+ if (sdBetaDB[g] > 0.0) sdBetaDB[g] = sqrt(sdBetaDB[g]); else sdBetaDB[g] = 0.0;
+ }
+ }
+ }
+ if (writefile) {
+ if (trfr.moveModel) {
+ if (trfr.moveType == 1) {
+ outtraits << "\t" << mnDP[0] << "\t" << sdDP[0];
+ outtraits << "\t" << mnGB[0] << "\t" << sdGB[0];
+ outtraits << "\t" << mnAlphaDB[0] << "\t" << sdAlphaDB[0];
+ outtraits << "\t" << mnBetaDB[0] << "\t" << sdBetaDB[0];
+ }
+ if (trfr.moveType == 2) {
+ outtraits << "\t" << mnStepL[0] << "\t" << sdStepL[0];
+ outtraits << "\t" << mnRho[0] << "\t" << sdRho[0];
+ }
+ }
+ else {
+ if (trfr.sexDep) {
+ outtraits << "\t" << mnDist1[0] << "\t" << sdDist1[0];
+ outtraits << "\t" << mnDist1[1] << "\t" << sdDist1[1];
+ if (trfr.twinKern)
+ {
+ outtraits << "\t" << mnDist2[0] << "\t" << sdDist2[0];
+ outtraits << "\t" << mnDist2[1] << "\t" << sdDist2[1];
+ outtraits << "\t" << mnProp1[0] << "\t" << sdProp1[0];
+ outtraits << "\t" << mnProp1[1] << "\t" << sdProp1[1];
+ }
+ }
+ else { // sex-independent
+ outtraits << "\t" << mnDist1[0] << "\t" << sdDist1[0];
+ if (trfr.twinKern)
+ {
+ outtraits << "\t" << mnDist2[0] << "\t" << sdDist2[0];
+ outtraits << "\t" << mnProp1[0] << "\t" << sdProp1[0];
+ }
+ }
+ }
+ }
+ }
+
+ if (sett.indVar) {
+ if (sett.sexDep) { // must be a sexual species
+ ngenes = 2;
+ }
+ else {
+ if (dem.repType == 0) { // asexual reproduction
+ ngenes = 1;
+ }
+ else { // sexual reproduction
+ ngenes = 1;
+ }
+ }
+ // CURRENTLY INDIVIDUAL VARIATION CANNOT BE SEX-DEPENDENT
+ double mnS0[2], mnAlpha[2], mnBeta[2], sdS0[2], sdAlpha[2], sdBeta[2];
+ for (int g = 0; g < ngenes; g++) {
+ mnS0[g] = mnAlpha[g] = mnBeta[g] = sdS0[g] = sdAlpha[g] = sdBeta[g] = 0.0;
+ // individuals may have been counted by sex if there was
+ // sex dependency in another dispersal phase
+ if (ngenes == 2) popsize = poptraits.ninds[g];
+ else popsize = poptraits.ninds[0] + poptraits.ninds[1];
+ if (popsize > 0) {
+ mnS0[g] = poptraits.sumS0[g] / (double)popsize;
+ mnAlpha[g] = poptraits.sumAlphaS[g] / (double)popsize;
+ mnBeta[g] = poptraits.sumBetaS[g] / (double)popsize;
+ if (popsize > 1) {
+ sdS0[g] = poptraits.ssqS0[g] / (double)popsize - mnS0[g] * mnS0[g];
+ if (sdS0[g] > 0.0) sdS0[g] = sqrt(sdS0[g]); else sdS0[g] = 0.0;
+ sdAlpha[g] = poptraits.ssqAlphaS[g] / (double)popsize - mnAlpha[g] * mnAlpha[g];
+ if (sdAlpha[g] > 0.0) sdAlpha[g] = sqrt(sdAlpha[g]); else sdAlpha[g] = 0.0;
+ sdBeta[g] = poptraits.ssqBetaS[g] / (double)popsize - mnBeta[g] * mnBeta[g];
+ if (sdBeta[g] > 0.0) sdBeta[g] = sqrt(sdBeta[g]); else sdBeta[g] = 0.0;
+ }
+ else {
+ sdS0[g] = sdAlpha[g] = sdBeta[g] = 0.0;
+ }
+ }
+ }
+ if (writefile) {
+ if (sett.sexDep) {
+ outtraits << "\t" << mnS0[0] << "\t" << sdS0[0];
+ outtraits << "\t" << mnS0[1] << "\t" << sdS0[1];
+ outtraits << "\t" << mnAlpha[0] << "\t" << sdAlpha[0];
+ outtraits << "\t" << mnAlpha[1] << "\t" << sdAlpha[1];
+ outtraits << "\t" << mnBeta[0] << "\t" << sdBeta[0];
+ outtraits << "\t" << mnBeta[1] << "\t" << sdBeta[1];
+ }
+ else { // sex-independent
+ outtraits << "\t" << mnS0[0] << "\t" << sdS0[0];
+ outtraits << "\t" << mnAlpha[0] << "\t" << sdAlpha[0];
+ outtraits << "\t" << mnBeta[0] << "\t" << sdBeta[0];
+ }
+ }
+ }
+
+ if (writefile) outtraits << endl;
+
+ for (int s = 0; s < NSEXES; s++) {
+ ts.ninds[s] += poptraits.ninds[s];
+ ts.sumD0[s] += poptraits.sumD0[s]; ts.ssqD0[s] += poptraits.ssqD0[s];
+ ts.sumAlpha[s] += poptraits.sumAlpha[s]; ts.ssqAlpha[s] += poptraits.ssqAlpha[s];
+ ts.sumBeta[s] += poptraits.sumBeta[s]; ts.ssqBeta[s] += poptraits.ssqBeta[s];
+ ts.sumDist1[s] += poptraits.sumDist1[s]; ts.ssqDist1[s] += poptraits.ssqDist1[s];
+ ts.sumDist2[s] += poptraits.sumDist2[s]; ts.ssqDist2[s] += poptraits.ssqDist2[s];
+ ts.sumProp1[s] += poptraits.sumProp1[s]; ts.ssqProp1[s] += poptraits.ssqProp1[s];
+ ts.sumDP[s] += poptraits.sumDP[s]; ts.ssqDP[s] += poptraits.ssqDP[s];
+ ts.sumGB[s] += poptraits.sumGB[s]; ts.ssqGB[s] += poptraits.ssqGB[s];
+ ts.sumAlphaDB[s] += poptraits.sumAlphaDB[s]; ts.ssqAlphaDB[s] += poptraits.ssqAlphaDB[s];
+ ts.sumBetaDB[s] += poptraits.sumBetaDB[s]; ts.ssqBetaDB[s] += poptraits.ssqBetaDB[s];
+ ts.sumStepL[s] += poptraits.sumStepL[s]; ts.ssqStepL[s] += poptraits.ssqStepL[s];
+ ts.sumRho[s] += poptraits.sumRho[s]; ts.ssqRho[s] += poptraits.ssqRho[s];
+ ts.sumS0[s] += poptraits.sumS0[s]; ts.ssqS0[s] += poptraits.ssqS0[s];
+ ts.sumAlphaS[s] += poptraits.sumAlphaS[s]; ts.ssqAlphaS[s] += poptraits.ssqAlphaS[s];
+ ts.sumBetaS[s] += poptraits.sumBetaS[s]; ts.ssqBetaS[s] += poptraits.ssqBetaS[s];
+ }
+ }
+ }
+ return ts;
+}
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+
diff --git a/src/RScore/SubCommunity.h b/src/RScore/SubCommunity.h
new file mode 100644
index 00000000..3eef73a1
--- /dev/null
+++ b/src/RScore/SubCommunity.h
@@ -0,0 +1,207 @@
+/*----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 Greta Bocedi, Stephen C.F. Palmer, Justin M.J. Travis, Anne-Kathleen Malchow, Damaris Zurell
+ *
+ * This file is part of RangeShifter.
+ *
+ * RangeShifter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RangeShifter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RangeShifter. If not, see .
+ *
+ --------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+
+RangeShifter v2.0 SubCommunity
+
+Implements the SubCommunity class
+
+There is ONE instance of a SubCommunity for each Patch in the Landscape
+(including the matrix). The SubCommunity holds a number of Populations, one for
+each Species represented in the simulation.
+CURRENTLY the number of Populations withn a SubCommunity is LIMITED TO ONE.
+
+For full details of RangeShifter, please see:
+Bocedi G., Palmer S.C.F., Pe’er G., Heikkinen R.K., Matsinos Y.G., Watts K.
+and Travis J.M.J. (2014). RangeShifter: a platform for modelling spatial
+eco-evolutionary dynamics and species’ responses to environmental changes.
+Methods in Ecology and Evolution, 5, 388-396. doi: 10.1111/2041-210X.12162
+
+Authors: Greta Bocedi & Steve Palmer, University of Aberdeen
+
+Last updated: 26 October 2021 by Steve Palmer
+
+------------------------------------------------------------------------------*/
+
+#ifndef SubCommunityH
+#define SubCommunityH
+
+#include
+#include
+using namespace std;
+
+#include "Parameters.h"
+#include "Landscape.h"
+#include "Population.h"
+
+//---------------------------------------------------------------------------
+
+struct traitCanvas { // canvases for drawing variable traits
+ int *pcanvas[NTRAITS]; // dummy variables for batch version
+};
+
+class SubCommunity {
+
+public:
+ SubCommunity(Patch*,int);
+ ~SubCommunity(void);
+ intptr getNum(void);
+ Patch* getPatch(void);
+ locn getLocn(void);
+
+ // functions to manage populations occurring in the SubCommunity
+ popStats getPopStats(void);
+ void setInitial(bool);
+ void initialise(Landscape*,Species*);
+ void initialInd(Landscape*,Species*,Patch*,Cell*,int);
+ Population* newPopn( // Create a new population, and return its address
+ Landscape*, // pointer to Landscape
+ Species*, // pointer to Species
+ Patch*, // pointer to Patch
+ int // no. of Individuals
+ );
+ void resetPopns(void);
+ void resetPossSettlers(void);
+ void localExtinction( // Extirpate all populations
+ int // option: 0 - random local extinction probability
+ // 1 - local extinction probability gradient
+ );
+ void patchChange(void);
+ void reproduction(
+ int, // Landscape resolution
+ float, // epsilon - global stochasticity value
+ short, // raster type (see Landscape)
+ bool // TRUE for a patch-based model, FALSE for a cell-based model
+ );
+ void emigration(void);
+ // Remove emigrants from their natal patch and add to patch 0 (matrix)
+ void initiateDispersal(
+ SubCommunity* // pointer to matrix SubCommunity
+ );
+// Add an individual into the local population of its species in the patch
+ void recruit(
+ Individual*, // pointer to Individual
+ Species* // pointer to Species
+ );
+#if RS_RCPP
+ int transfer( // Transfer through matrix - run for matrix SubCommunity only
+ Landscape*, // pointer to Landscape
+ short, // landscape change index
+ short // season / year
+ );
+#else
+ int transfer( // Transfer through matrix - run for matrix SubCommunity only
+ Landscape*, // pointer to Landscape
+ short // landscape change index
+ );
+#endif // RS_RCPP
+ // Remove emigrants from patch 0 (matrix) and transfer to SubCommunity in which
+ // their destination co-ordinates fall (executed for the matrix patch only)
+ void completeDispersal(
+ Landscape*, // pointer to Landscape
+ bool // TRUE to increment connectivity totals
+ );
+ void survival(
+ short, // part: 0 = determine survival & development,
+ // 1 = apply survival changes to the population
+ short, // option0: 0 = stage 0 (juveniles) only )
+ // 1 = all stages ) used by part 0 only
+ // 2 = stage 1 and above (all non-juvs) )
+ short // option1: 0 - development only (when survival is annual)
+ // 1 - development and survival
+ );
+ void ageIncrement(void);
+ // Find the population of a given species in a given patch
+ Population* findPop(Species*,Patch*);
+ void createOccupancy(
+ int // no. of rows = (no. of years / interval) + 1
+ );
+ void updateOccupancy(
+ int // row = (no. of years / interval)
+ );
+ int getOccupancy(
+ int // row = (no. of years / interval)
+ );
+ void deleteOccupancy(void);
+
+ bool outPopHeaders( // Open population file and write header record
+ Landscape*, // pointer to Landscape
+ Species*, // pointer to Species
+ int // option: -999 to close the file
+ );
+ void outPop( // Write records to population file
+ Landscape*, // pointer to Landscape
+ int, // replicate
+ int, // year
+ int // generation
+ );
+
+ void outInds( // Write records to individuals file
+ Landscape*, // pointer to Landscape
+ int, // replicate
+ int, // year
+ int, // generation
+ int // Landscape number (>= 0 to open the file, -999 to close the file
+ // -1 to write data records)
+ );
+ void outGenetics( // Write records to genetics file
+ int, // replicate
+ int, // year
+ int, // generation
+ int // Landscape number (>= 0 to open the file, -999 to close the file
+ // -1 to write data records)
+ );
+ bool outTraitsHeaders( // Open traits file and write header record
+ Landscape*, // pointer to Landscape
+ Species*, // pointer to Species
+ int // Landscape number (-999 to close the file)
+ );
+ traitsums outTraits( // Write records to traits file and return aggregated sums
+ traitCanvas, // pointers to canvases for drawing variable traits
+ // in the batch version, these are replaced by integers set to zero
+ Landscape*, // pointer to Landscape
+ int, // replicate
+ int, // year
+ int, // generation
+ bool // true if called to summarise data at community level
+ );
+ int stagePop( // Population size of a specified stage
+ int // stage
+ );
+
+private:
+ intptr subCommNum; // SubCommunity number
+ // 0 is reserved for the SubCommunity in the inter-patch matrix
+ Patch *pPatch;
+ int *occupancy; // pointer to occupancy array
+ std::vector popns;
+ bool initial; // WILL NEED TO BE CHANGED FOR MULTIPLE SPECIES ...
+
+};
+
+extern paramGrad *paramsGrad;
+extern paramStoch *paramsStoch;
+extern paramInit *paramsInit;
+
+//---------------------------------------------------------------------------
+#endif
diff --git a/src/RScore/Utils.cpp b/src/RScore/Utils.cpp
new file mode 100644
index 00000000..9d36b920
--- /dev/null
+++ b/src/RScore/Utils.cpp
@@ -0,0 +1,26 @@
+#include "Utils.h"
+
+const string Int2Str(const int x)
+{
+ ostringstream o;
+ if (!(o << x)) return "ERROR";
+ return o.str();
+}
+const string Float2Str(const float x) {
+ ostringstream o;
+ if (!(o << x)) return "ERROR";
+ return o.str();
+}
+const string Double2Str(const double x) {
+ ostringstream o;
+ if (!(o << x)) return "ERROR";
+ return o.str();
+}
+
+// Evaluate a lambda and assert we get the correct error
+void assert_error(const string& exptd_err_msg, void (*lambda)(void)) {
+ string err_msg{ "No error.\n" };
+ try { lambda(); } // evaluate
+ catch (exception& e) { err_msg = e.what(); }
+ assert(err_msg == exptd_err_msg);
+}
\ No newline at end of file
diff --git a/src/RScore/Utils.h b/src/RScore/Utils.h
new file mode 100644
index 00000000..34854a76
--- /dev/null
+++ b/src/RScore/Utils.h
@@ -0,0 +1,18 @@
+#ifndef UtilsH
+#define UtilsH
+
+#include
+#include
+#include
+
+#include
+using namespace std;
+
+const string Int2Str(const int x);
+const string Float2Str(const float x);
+const string Double2Str(const double x);
+
+// Evaluate a lambda and assert we get the correct error
+void assert_error(const string& exptd_err_msg, void (*x)(void));
+
+#endif // UtilsH
diff --git a/src/RScore/branches.png b/src/RScore/branches.png
new file mode 100644
index 00000000..12e3a96e
Binary files /dev/null and b/src/RScore/branches.png differ
diff --git a/src/RScore/git_cheatsheet.md b/src/RScore/git_cheatsheet.md
new file mode 100644
index 00000000..53ca1750
--- /dev/null
+++ b/src/RScore/git_cheatsheet.md
@@ -0,0 +1,107 @@
+# Git Cheatsheet
+
+Quick reference on Git usage for RangeShifter contributors
+
+#### Creating a local copy of this repo
+
+```bash
+git clone https://github.com/RangeShifter/RScore.git
+```
+
+#### Enquire about the current state of changes
+
+```
+git status
+```
+This will display whether the local branch is up-to-date with its GitHub counterpart, what files have been changed and if they are staged for commit or not.
+
+#### Updating the active branch with latest changes (pulling)
+
+```bash
+git pull
+```
+
+#### Updating the active branch with another branch (merging)
+
+```bash
+git merge
+```
+
+Merging may trigger a merge conflict is the same lines have been changed on both branches. See Solving Merge Conflict below.
+
+#### Staging changes to be committed
+Changes to local files must first be added to the commit queue ("staged") before being committed.
+
+```bash
+git add # single file
+git add . # entire active folder
+```
+
+#### Creating a commit
+
+```bash
+git commit -m "commit message"
+```
+
+A good commit message is concise, but descriptive.
+
+#### Uploading local commits to GitHub (pushing)
+
+```bash
+git push
+```
+
+#### Switching to an existing branch
+
+```bash
+git checkout
+```
+Switching does not update the new active branch with GitHub automatically, so make sure to pull after switching!
+
+#### Creating a new branch from active branch
+
+```bash
+git branch
+```
+You will also need to set the corresponding branch on `origin` (GitHub) before you can push:
+
+```bash
+git push --set-upstream origin
+```
+
+New branches can also be created on GitHub (drop-down button in the top-left corner of the main page).
+New branches on GitHub are brought to the local copy with the next pull.
+
+#### Deleting a branch locally
+
+```bash
+git branch -d
+```
+
+#### Instruct Git to not track some files
+
+Open `.gitignore` and add the path to the files or folders to exclude from the git history.
+Check with `git status` that the files are indeed not tracked by git anymore.
+
+#### Solving a merge conflict
+Merge conflicts can arise when multiple contributors simulatneously change the same line of code.
+In such cases, git is incapable of deciding which version should be kept and asks for human input.
+Git tells you which files are affected by the conflict.
+Open each file and resolve **each** section that looks like this:
+
+```
+After opening the box, we can affirm that
+<<<<<<<<<<< HEAD # delete this line
+Shroedinger's cat is alive. # delete either this...
+================ # delete this line
+Shroedinger's cat is dead. # ... or this (or keep both, or none, or a different solution)
+>>>>>>>>>>> SHA # delete this line
+What an insightful result!
+```
+
+Ctrl+F "HEAD" is really helpful for finding the conflicts in large files.
+When you are done, create a commit stating e.g. "solved merge conflict" and push.
+
+## Git subtrees
+
+See [Git subtrees](https://github.com/RangeShifter/RScore/tree/development-guidelines#usage-git-subtree) section in README.
| | |