diff --git a/data/input/fishTryRealBV_CC.xml b/data/input/fishTryRealBV_CC.xml index e5224a8d6ae123952b942bec9a2aee70fb036ff3..8a72c6b87ddc1198e4db87a7acb3c4226f1f9a4b 100644 --- a/data/input/fishTryRealBV_CC.xml +++ b/data/input/fishTryRealBV_CC.xml @@ -1,124 +1,138 @@ <list> - <species.DiadromousFishGroup> - <name>species A</name> - <color> - <red>255</red> - <green>0</green> - <blue>0</blue> - <alpha>255</alpha> - </color> - <linfVonBert>60.0</linfVonBert> - <dMaxDisp>0.0</dMaxDisp> - <lFirstMaturity>40.0</lFirstMaturity> - <fileNameInputForInitialObservation>data/input/reality/Obs1900.csv</fileNameInputForInitialObservation> + <species.DiadromousFishGroup> + <name>species A</name> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + <alpha>255</alpha> + </color> + <linfVonBert>60.0</linfVonBert> + <dMaxDisp>0.0</dMaxDisp> + <lFirstMaturity>40.0</lFirstMaturity> + <fileNameInputForInitialObservation>data/input/reality/Obs1900.csv</fileNameInputForInitialObservation> + <outputPath>data/output/</outputPath> - <processes> - <processesAtBegin> - <species.PopulateBasinNetworkWithANorthLimit> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - <nbSIPerBasin>200</nbSIPerBasin> - <initialLength>2.0</initialLength> - <nbFishPerSI>2500</nbFishPerSI> - <northLimitLatitude>43.54</northLimitLatitude> - </species.PopulateBasinNetworkWithANorthLimit> - </processesAtBegin> + <processes> + <processesAtBegin> + <species.PopulateBasinNetworkWithANorthLimit> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <nbSIPerBasin>200</nbSIPerBasin> + <initialLength>2.0</initialLength> + <nbFishPerSI>2500</nbFishPerSI> + <northLimitLatitude>43.54</northLimitLatitude> + </species.PopulateBasinNetworkWithANorthLimit> + </processesAtBegin> - <processesEachStep> - <environment.InformTime> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - </environment.InformTime> - <species.PlopProcess> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - <temporisation>0</temporisation> - </species.PlopProcess> + <processesEachStep> + <environment.InformTime> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + </environment.InformTime> + <species.PlopProcess> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <temporisation>0</temporisation> + </species.PlopProcess> - <species.Age> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - </species.Age> + <species.Age> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + </species.Age> - <species.Grow> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - <tempMinGrow>3.0</tempMinGrow> - <tempMaxGrow>26.0</tempMaxGrow> - <tempOptGrow>17.0</tempOptGrow> - <kOpt>0.3900707</kOpt> - <sigmaDeltaLVonBert>0.2</sigmaDeltaLVonBert> - </species.Grow> + <species.Grow> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <tempMinGrow>3.0</tempMinGrow> + <tempMaxGrow>26.0</tempMaxGrow> + <tempOptGrow>17.0</tempOptGrow> + <kOpt>0.3900707</kOpt> + <sigmaDeltaLVonBert>0.2</sigmaDeltaLVonBert> + </species.Grow> - <species.DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - <alpha0Rep>-2.9</alpha0Rep> - <alpha1Rep>19.7</alpha1Rep> - <alpha3Rep>0.0</alpha3Rep> - <meanBvSurface>17351</meanBvSurface> - <standardDeviationBvSurface>35594</standardDeviationBvSurface> - <meanInterDistance>300.0</meanInterDistance> - <standardDeviationInterDistance>978.0 - </standardDeviationInterDistance> - <pHomingForReachEquil>0.75</pHomingForReachEquil> - <pHomingAfterEquil>0.75</pHomingAfterEquil> - <NbYearForInstallPop>0</NbYearForInstallPop> - <riverMigrationSeason>SPRING</riverMigrationSeason> - <alpha2Rep>0.0</alpha2Rep> - <meanSpawnersLengthAtRepro>45.0</meanSpawnersLengthAtRepro> - <standardDeviationOfSpawnersLengthAtRepro>2.0 - </standardDeviationOfSpawnersLengthAtRepro> - <weightOfDeathBasin>0.4</weightOfDeathBasin> - </species.DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin> + <species.DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <alpha0Rep>-2.9</alpha0Rep> + <alpha1Rep>19.7</alpha1Rep> + <alpha3Rep>0.0</alpha3Rep> + <meanBvSurface>17351</meanBvSurface> + <standardDeviationBvSurface>35594</standardDeviationBvSurface> + <meanInterDistance>300.0</meanInterDistance> + <standardDeviationInterDistance>978.0 + </standardDeviationInterDistance> + <pHomingForReachEquil>0.75</pHomingForReachEquil> + <pHomingAfterEquil>0.75</pHomingAfterEquil> + <NbYearForInstallPop>0</NbYearForInstallPop> + <riverMigrationSeason>SPRING</riverMigrationSeason> + <alpha2Rep>0.0</alpha2Rep> + <meanSpawnersLengthAtRepro>45.0</meanSpawnersLengthAtRepro> + <standardDeviationOfSpawnersLengthAtRepro>2.0 + </standardDeviationOfSpawnersLengthAtRepro> + <weightOfDeathBasin>0.4</weightOfDeathBasin> + </species.DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin> - <species.Survive> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - <tempMinMortGenInRiv>10.0</tempMinMortGenInRiv> - <tempMaxMortGenInRiv>23.0</tempMaxMortGenInRiv> - <tempOptMortGenInRiv>20.0</tempOptMortGenInRiv> - <survivalProbOptGenInRiv>1.0</survivalProbOptGenInRiv> - <mortalityRateInRiver>0.4</mortalityRateInRiver> - <mortalityRateInSea>0.4</mortalityRateInSea> - <mortalityRateInOffshore>0.4</mortalityRateInOffshore> - </species.Survive> + <species.Survive> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <tempMinMortGenInRiv>10.0</tempMinMortGenInRiv> + <tempMaxMortGenInRiv>23.0</tempMaxMortGenInRiv> + <tempOptMortGenInRiv>20.0</tempOptMortGenInRiv> + <survivalProbOptGenInRiv>1.0</survivalProbOptGenInRiv> + <mortalityRateInRiver>0.4</mortalityRateInRiver> + <mortalityRateInSea>0.4</mortalityRateInSea> + <mortalityRateInOffshore>0.4</mortalityRateInOffshore> + </species.Survive> - <species.ReproduceAndSurviveAfterReproduction> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - <reproductionSeason>SPRING</reproductionSeason> - <tempMinRep>9.846984</tempMinRep> - <tempMaxRep>26.0</tempMaxRep> - <tempOptRep>20.0</tempOptRep> - <eta>2.4</eta> - <ratioS95__S50>1.9</ratioS95__S50> - <a>135000.0</a> - <delta__t>0.33</delta__t> - <survOptRep>0.0017</survOptRep> - <lambda>4.1E-4</lambda> - <initialLength>2.0</initialLength> - <sigmaRecruitment>0.2</sigmaRecruitment> - <survivalRateAfterReproduction>0.1</survivalRateAfterReproduction> - <maxNumberOfSuperIndividualPerReproduction>50.0 - </maxNumberOfSuperIndividualPerReproduction> - </species.ReproduceAndSurviveAfterReproduction> + <species.ExportLenghtAgeDistribution> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <exportSeason>SPRING</exportSeason> + <fileNameOutput>lengthAgeDistribution</fileNameOutput> + </species.ExportLenghtAgeDistribution> - <species.MigrateToSea> - <seaMigrationSeason>SUMMER</seaMigrationSeason> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - </species.MigrateToSea> + <species.ReproduceAndSurviveAfterReproductionWithDiagnose> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <reproductionSeason>SPRING</reproductionSeason> + <tempMinRep>9.846984</tempMinRep> + <tempMaxRep>26.0</tempMaxRep> + <tempOptRep>20.0</tempOptRep> + <eta>2.4</eta> + <ratioS95__S50>1.9</ratioS95__S50> + <a>135000.0</a> + <delta__t>0.33</delta__t> + <survOptRep>0.0017</survOptRep> + <lambda>4.1E-4</lambda> + <initialLength>2.0</initialLength> + <sigmaRecruitment>0.2</sigmaRecruitment> + <survivalRateAfterReproduction>0.1</survivalRateAfterReproduction> + <maxNumberOfSuperIndividualPerReproduction>50.0</maxNumberOfSuperIndividualPerReproduction> + <withDiagnose>false</withDiagnose> + </species.ReproduceAndSurviveAfterReproductionWithDiagnose> - <environment.updateTemperatureInRealBasin> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - <offshoreTemperature>12.0</offshoreTemperature> - </environment.updateTemperatureInRealBasin> - </processesEachStep> + <species.MigrateToSea> + <seaMigrationSeason>SUMMER</seaMigrationSeason> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + </species.MigrateToSea> - <processesAtEnd> - <species.IdentifyPopulation> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - </species.IdentifyPopulation> - <species.TypeTrajectoryCV> - <synchronisationMode>ASYNCHRONOUS</synchronisationMode> - <fileNameOutput>data/output/JeuParam100_2100RCP85_A - </fileNameOutput> - </species.TypeTrajectoryCV> + <environment.updateTemperatureInRealBasin> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <offshoreTemperature>12.0</offshoreTemperature> + </environment.updateTemperatureInRealBasin> + </processesEachStep> - </processesAtEnd> - </processes> - <useCemetery>false</useCemetery> - </species.DiadromousFishGroup> + <processesAtEnd> + <species.IdentifyPopulation> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <consoleDisplay>false</consoleDisplay> + <fluxesSeason>SPRING</fluxesSeason> + <years> + <long>2000</long> + <long>2100</long> + </years> + <fileNameOutput>data/output/fluxes</fileNameOutput> + </species.IdentifyPopulation> + <species.TypeTrajectoryCV> + <synchronisationMode>ASYNCHRONOUS</synchronisationMode> + <fileNameOutput>data/output/JeuParam100_2100RCP85_A_essai + </fileNameOutput> + </species.TypeTrajectoryCV> + + </processesAtEnd> + </processes> + <useCemetery>false</useCemetery> + </species.DiadromousFishGroup> </list> \ No newline at end of file diff --git a/src/main/java/environment/updateTemperatureInRealBasin.java b/src/main/java/environment/updateTemperatureInRealBasin.java index 747352451e8e2e972f74a75cb1a7907397f055fd..c57370bb29a970a956eabd39ab536786c06a81e0 100644 --- a/src/main/java/environment/updateTemperatureInRealBasin.java +++ b/src/main/java/environment/updateTemperatureInRealBasin.java @@ -11,9 +11,9 @@ import environment.Time.Season; import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; public class updateTemperatureInRealBasin extends AquaNismsGroupProcess<DiadromousFish, DiadromousFishGroup> { - + double offshoreTemperature = 12.; - + public static void main(String[] args) { System.out.println((new XStream(new DomDriver())) .toXML(new updateTemperatureInRealBasin())); } @@ -24,18 +24,23 @@ public class updateTemperatureInRealBasin extends AquaNismsGroupProcess<Diadromo if (Time.getSeason(group.getPilot()) == Season.WINTER){ Map<String, Double[]> temperaturesbasin = ((BasinNetworkReal) group.getEnvironment()).getTemperaturesBasin(Time.getYear(group.getPilot())); - for (Basin basin : group.getEnvironment().getBasins()){ - if (basin instanceof RiverBasin){ - basin.setWinterTemperature(temperaturesbasin.get(basin.getName())[0]); - basin.setSpringTemperature(temperaturesbasin.get(basin.getName())[1]); - basin.setSummerTemperature(temperaturesbasin.get(basin.getName())[2]); - basin.setFallTemperature(temperaturesbasin.get(basin.getName())[3]); - } else if (basin instanceof SeaBasin) { - basin.setWinterTemperature((offshoreTemperature + temperaturesbasin.get(group.getEnvironment().getAssociatedRiverBasin(basin).getName())[0])/2.); - basin.setSpringTemperature((offshoreTemperature + temperaturesbasin.get(group.getEnvironment().getAssociatedRiverBasin(basin).getName())[1])/2.); - basin.setSummerTemperature((offshoreTemperature + temperaturesbasin.get(group.getEnvironment().getAssociatedRiverBasin(basin).getName())[2])/2.); - basin.setFallTemperature((offshoreTemperature + temperaturesbasin.get(group.getEnvironment().getAssociatedRiverBasin(basin).getName())[3])/2.); - } + if (temperaturesbasin != null) { + for (Basin basin : group.getEnvironment().getBasins()){ + if (basin instanceof RiverBasin){ + basin.setWinterTemperature(temperaturesbasin.get(basin.getName())[0]); + basin.setSpringTemperature(temperaturesbasin.get(basin.getName())[1]); + basin.setSummerTemperature(temperaturesbasin.get(basin.getName())[2]); + basin.setFallTemperature(temperaturesbasin.get(basin.getName())[3]); + } else if (basin instanceof SeaBasin) { + basin.setWinterTemperature((offshoreTemperature + temperaturesbasin.get(group.getEnvironment().getAssociatedRiverBasin(basin).getName())[0])/2.); + basin.setSpringTemperature((offshoreTemperature + temperaturesbasin.get(group.getEnvironment().getAssociatedRiverBasin(basin).getName())[1])/2.); + basin.setSummerTemperature((offshoreTemperature + temperaturesbasin.get(group.getEnvironment().getAssociatedRiverBasin(basin).getName())[2])/2.); + basin.setFallTemperature((offshoreTemperature + temperaturesbasin.get(group.getEnvironment().getAssociatedRiverBasin(basin).getName())[3])/2.); + } + } + } + else { + System.out.println("pb with temperature at "+ Time.getYear(group.getPilot() )); } } } diff --git a/src/main/java/miscellaneous/Miscellaneous.java b/src/main/java/miscellaneous/Miscellaneous.java index 3ae367a78cd7e1b78f1e4ccdf9401fdd86dee2ee..8b364010cfc3c6b1eb17e324165dc0c8d60db048 100644 --- a/src/main/java/miscellaneous/Miscellaneous.java +++ b/src/main/java/miscellaneous/Miscellaneous.java @@ -40,7 +40,7 @@ public class Miscellaneous { if (T <= Tmin || T >= Tmax) { return 0; } else { - return (T - Tmin) * (T - Tmax) / ((T - Tmin) * (T - Tmax) - Math.pow(T - Topt, 2.)); + return (T - Tmin) * (T - Tmax) / ((T - Tmin) * (T - Tmax) - ((T - Topt) * (T-Topt))); } } } diff --git a/src/main/java/species/DiadromousFish.java b/src/main/java/species/DiadromousFish.java index bec490f285042bce16328d16acfcc692d37f9269..a3594a287efbfded65e0620ecff7ec5a22eadef6 100644 --- a/src/main/java/species/DiadromousFish.java +++ b/src/main/java/species/DiadromousFish.java @@ -19,13 +19,6 @@ public class DiadromousFish extends AquaNism<Basin, BasinNetwork> { private Gender gender; private int numberOfReproduction; - public DiadromousFish(Pilot pilot, Basin position, double initialLength, long fishAmount) { - this(pilot, position, initialLength, fishAmount, Gender.UNDIFFERENCIED); - } - - public DiadromousFish(Pilot pilot, Basin position, double initialLength) { - this(pilot, position, initialLength, 1, Gender.UNDIFFERENCIED); - } public DiadromousFish(Pilot pilot, Basin position, double initialLength, long fishAmount, Gender gender) { super(pilot, position); diff --git a/src/main/java/species/DiadromousFishGroup.java b/src/main/java/species/DiadromousFishGroup.java index b84dbb45c9f52904b942bafe1a7e3d48517e1af7..79fc81094ec7cf1b996468f834e7dbaf3016e732 100644 --- a/src/main/java/species/DiadromousFishGroup.java +++ b/src/main/java/species/DiadromousFishGroup.java @@ -36,23 +36,90 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe public String name = "species A"; public Color color = Color.RED; + + /** + * L infinity of the van Bertalanffy growth curve + * L = Linf *(1-exp(-K*(t-t0)) + * @unit cm + */ public double linfVonBert = 60.; + + /** + * ???? + * @unit + */ public double dMaxDisp = 300.; + + /** + * length at first maturity. At that length the fish become Stage.MATURE + * @unit cm + */ public double lFirstMaturity = 40.; + public String fileNameInputForInitialObservation = "data/input/reality/Obs1900.csv"; + + /** + * centile to calucale the range of species distribution + * @unit + */ public double centileForRange = 0.95; + /** + * file with the calibated parameters (from baysian approach) + * @unit + */ private String parameterSetfileName= "data/input/reality/parameterSet.csv"; + + /** + * line to use in the calibrated parameters file + * @unit + */ private int parameterSetLine =0; + /** + * year when the update of the basin should occur + * @unit + */ private long yearOfTheUpdate; + + /** + * list of the basins to be updated + * column 1: name of the basin + * column 2: Pattractive: how the bassin become attractive (0 not attractive, 1 ??? normal weight associated to catchment size) + * column 3: Paccessible: how the bassin become acesssible (0 not accessible, 1 ???normal weight to inter catchment distance ) + * @unit + */ private String basinsToUpdateFile = "data/input/reality/basinsToUpdate.csv"; private String outputPath = "data/output/"; + /** + * map + * <key> basin name + * <value> Duo + * <first> pAttractive + * <second> pAccessible + * @unit + */ private transient Map<String, Duo<Double, Double>> basinsToUpdate; - private transient double kOpt; //parametre de croissance + + /** + * Brody growth coefficient of the von Bertalanffy growth curve (from the parameterset file) + * * L = Linf *(1-exp(-K*(t-t0)) + * @unit year-1 + */ + private transient double kOpt; + /** + * minimum temperature for the reproduction (from the parameterset file) + * @unit °C + */ private transient double tempMinRep; //parametre de reproduction + + + /** + * list of the parameters provided by the calibration + * @unit + */ private transient List<Duo<Double, Double>> parameterSets; public static void main(String[] args) { @@ -65,13 +132,18 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe public double getPattractive(String basinName){ - if (basinsToUpdate.containsKey(basinName.substring(0, basinName.length()-2))) - return basinsToUpdate.get(basinName.substring(0, basinName.length()-2)).getFirst(); + // TODO pass in argument a Basin + // remove "-s" of the sea basin name + String shortBasinName = basinName.substring(0, basinName.length()-2); + if (basinsToUpdate.containsKey(shortBasinName)) + return basinsToUpdate.get(shortBasinName).getFirst(); else return Double.NaN; } public double getPaccessible(String basinName){ + // TODO pass in argument a Basin + //WHY not a short name if (basinsToUpdate.containsKey(basinName)) return basinsToUpdate.get(basinName).getSecond(); else @@ -95,6 +167,7 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe InvocationTargetException { super.initTransientParameters(pilot); + // basin to be updated if ( basinsToUpdate != null){ String subDir=basinsToUpdateFile; if (basinsToUpdateFile.lastIndexOf("/")!=-1) @@ -186,41 +259,60 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe @Observable(description = "Nb of SI") public int getNbSI() { - return this.getAquaNismsList().size(); + int nbSI = 0; + for (Basin basin : this.getEnvironment().getBasins() ) { + if (basin.getFishs(this) != null) + nbSI += basin.getFishs(this).size(); + } + return nbSI; } @Observable(description = "Sizes mean of SI") public double getSizesMeanOfSI() { - double sum = 0; - for (DiadromousFish list : getAquaNismsList()) { - sum += (int) list.getAmount(); + double totalEffective = 0; + double nbSI =0; + for (Basin basin : this.getEnvironment().getBasins() ) { + if (basin.getFishs(this) != null) { + nbSI += basin.getFishs(this).size(); + for (DiadromousFish superFish : basin.getFishs(this)) { + totalEffective += superFish.getAmount(); + } + } } - return sum / getAquaNismsList().size(); + if (nbSI >=0) + return totalEffective /nbSI; + else + return Double.NaN; } @Observable(description = "# of SI with ind < 10") public double getNbLittleSI() { double nb = 0; - for (DiadromousFish list : getAquaNismsList()) { - if (list.getAmount() < 10) { - nb++; + for (Basin basin : this.getEnvironment().getBasins() ) { + if (basin.getFishs(this) != null) { + for (DiadromousFish superFish : basin.getFishs(this)) { + if ( superFish.getAmount()<10L) + nb++; + } } } return nb; } public double getMeanLengthOfMatureFish(){ - double meanLengthOfMatureFish = 0.; double sumOfLength = 0.; double numberOfMatureFish = 0.; - for (DiadromousFish fish : getAquaNismsList()){ - if (fish.isMature()){ - sumOfLength += fish.getAmount() * fish.getLength(); - numberOfMatureFish += fish.getAmount(); + for (Basin basin : this.getEnvironment().getBasins() ) { + if (basin.getFishs(this) != null) { + for (DiadromousFish fish : basin.getFishs(this)) { + if (fish.isMature()){ + sumOfLength += fish.getAmount() * fish.getLength(); + numberOfMatureFish += fish.getAmount(); + } + } } - meanLengthOfMatureFish = sumOfLength / numberOfMatureFish; } - return meanLengthOfMatureFish; + return sumOfLength / numberOfMatureFish; } public double getStandardDeviationOfMatureFishLength(){ @@ -228,13 +320,18 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe double sumOfSquareLength = 0.; double numberOfMatureFish = 0.; double meanOfSquareLengthOfMatureFish = 0.; - for (DiadromousFish fish : getAquaNismsList()){ - if (fish.isMature()){ - sumOfSquareLength += fish.getAmount() * Math.pow(fish.getLength(), 2); - numberOfMatureFish += fish.getAmount(); + for (Basin basin : this.getEnvironment().getBasins() ) { + if (basin.getFishs(this) != null) { + for (DiadromousFish fish : basin.getFishs(this)) { + if (fish.isMature()){ + sumOfSquareLength += fish.getAmount() * fish.getLength() * fish.getLength(); + numberOfMatureFish += fish.getAmount(); + } + } } meanOfSquareLengthOfMatureFish = sumOfSquareLength / numberOfMatureFish; - standardDeviationOfMatureFishLength = Math.pow((meanOfSquareLengthOfMatureFish - Math.pow(getMeanLengthOfMatureFish(), 2)), 0.5); + double meanLength = getMeanLengthOfMatureFish(); + standardDeviationOfMatureFishLength = Math.sqrt(meanOfSquareLengthOfMatureFish - meanLength * meanLength); } return standardDeviationOfMatureFishLength; } @@ -266,29 +363,20 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe public void setlFirstMaturity(double lFirstMaturity) { this.lFirstMaturity = lFirstMaturity; } - - - @Observable(description="Higher Populated Latitude") - public double getHigherPopulatedLatitude() { - double latitude = 0.0; - RiverBasin[] basins = getEnvironment().getRiverBasins(); - int[] finalStates = getEnvironment().getFinalStates(); - for (int i = 0; i < finalStates.length; i++) { - if ((finalStates[i] == 1) && (basins[i].getLatitude() > latitude)) { - latitude = basins[i].getLatitude(); - } - - } - return latitude; - } - + + // ================================================================ + // statictis for calibration + // ================================================================ @Observable(description="Spawners For First Time Summary Statistic") public double computeSpawnerForFirstTimeSummaryStatistic() { double sum = 0; + //TODO move TARGET to the right place double TARGET = 5.0; for (RiverBasin riverBasin : getEnvironment().getRiverBasins()) { - if (riverBasin.getSpawnersForFirstTimeMeanAges().getMeanWithoutZero() > 0.) - sum += Math.pow(riverBasin.getSpawnersForFirstTimeMeanAges().getMeanWithoutZero() - TARGET, 2); + if (riverBasin.getSpawnersForFirstTimeMeanAges().getMeanWithoutZero() > 0.) { + double val = riverBasin.getSpawnersForFirstTimeMeanAges().getMeanWithoutZero() - TARGET; + sum += val * val; + } } return sum; } @@ -299,6 +387,7 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe // 1 : read input file of observation FileReader reader; Scanner scanner; + //TODO move the obs1900 and the scanner Map<String, Integer> obs1900 = new HashMap<String, Integer>(); try { reader = new FileReader(fileNameInputForInitialObservation); @@ -337,7 +426,26 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe return sumLogWhereAbs + sumLogWherePres; } + + + // ======================================================== + // obeserver to explore the distribution + // ======================================================== + @Observable(description="Higher Populated Latitude") + public double getHigherPopulatedLatitude() { + double latitude = 0.0; + RiverBasin[] basins = getEnvironment().getRiverBasins(); + int[] finalStates = getEnvironment().getFinalStates(); + for (int i = 0; i < finalStates.length; i++) { + if ((finalStates[i] == 1) && (basins[i].getLatitude() > latitude)) { + latitude = basins[i].getLatitude(); + } + } + return latitude; + } + + @Observable(description="Number of colonized basins") public double getNbColonizedBasins() { int nb = 0; @@ -350,6 +458,7 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe } return nb; } + @Observable(description="Northern colonized basins") public double getNorthernBasins() { @@ -364,6 +473,7 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe return northernBasin; } + @Observable(description="Southern colonized basins") public double getSouthernBasins() { int southernBasin = Integer.MIN_VALUE; @@ -408,6 +518,7 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe return rangeDistribution; } + @Observable(description = "Range distribution") public Double[] getRangeDistribution() { double southernBasin = 0; @@ -440,15 +551,23 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe return rangeDistribution; } - @Observable(description = "Number of fishes") + /** + * @return sum of effectives in all the river basins + */ + @Observable(description = "Number of fishes in river basin") public double getFishEffective() { long eff = 0; - for (DiadromousFish fish : this.getAquaNismsList()) { - eff += fish.getAmount(); + for (RiverBasin basin : this.getEnvironment().getRiverBasins()){ + if (basin.getFishs(this) != null) { + for (DiadromousFish fish : basin.getFishs(this)) { + eff += fish.getAmount(); + } + } } return eff; } + @Override public void addAquaNism(DiadromousFish fish) { // avoid utilisation of global fishes list @@ -456,6 +575,7 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe fish.getPosition().addFish(fish, this); } + @Override public void removeAquaNism(DiadromousFish fish) { // avoid utilisation of global fishes list @@ -463,11 +583,18 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe fish.getPosition().removeFish(fish, this); } + @Override public int compareTo(DiadromousFishGroup t) { return name.compareTo(t.name); } + + /** + * + * concat at RngSatusIndex, temperatureCatchmentFile + * @return simulation name + */ public String getSimulationId(){ String id="_"; id=id.concat(Integer.toString(getPilot().getParameters().getRngStatusIndex())); @@ -482,7 +609,7 @@ public class DiadromousFishGroup extends AquaNismsGroup< DiadromousFish, BasinNe public boolean isThereBasinToUpdate(){ return basinsToUpdate != null; } - + /** * @return the outputPath */ diff --git a/src/main/java/species/DisperseAndMigrateToRiverBasic.java b/src/main/java/species/DisperseAndMigrateToRiverBasic.java index 37b2d0b1013d5beda0153d410c2163e4ce0d220f..cbbae2950cdd2230ec04568b2fe1d6369d450445 100644 --- a/src/main/java/species/DisperseAndMigrateToRiverBasic.java +++ b/src/main/java/species/DisperseAndMigrateToRiverBasic.java @@ -21,31 +21,86 @@ import com.thoughtworks.xstream.io.xml.DomDriver; @ServiceProvider(service = AquaNismsGroupProcess.class) public class DisperseAndMigrateToRiverBasic extends AquaNismsGroupProcess<DiadromousFish, DiadromousFishGroup> { + /** the coefficient independent of environmental factors in the logistic function used to calculate the probability to disperse + * @unit - + */ private double alpha0Rep = -2.2; - private double alpha1Rep = 17.3; + + /** + * the coefficient associated with the distance between catchment in the logistic function used to calculate the probability to disperse + * i.e. the relative influence of accessibility + * @unit - + */ + //TODO transform to a negative value (the larger the distance , the smaller the accessibility is) and correct in the computation of the weight + private double alpha1Rep = 17.3; + + /** + * the mean distance between catchments used to standardize the inter-catchment distance in the logistic function that calculates the probability to disperse + * @unit km + */ + private double meanInterDistance = 300.; // (from the 53 cathments among the 173 of Lassalles 2008) + + /** + * the standard deviation of distances between catchments used to standardize the inter-catchment distance in the logistic function that calculates the probability to disperse + * @unit km + */ + private double standardDeviationInterDistance = 978.; // (from the 53 cathments among the 173 of Lassalles 2008) + + /** + * the coefficient associated with the attractive surface of the catchment in the logistic function used to calculate the probability to disperse + * i.e. the relative influence of attractiveness + * should be positive : the larger the surface , the higher the attractiveness is + * @unit - + */ + //TODO check the sign in the formula private double alpha3Rep = 0.; - private double meanBvSurface = 23071., standardDeviationBvSurface = 39833.; // for standard core values... Value for the selected 54 BV of the Atlantic Coast from the 196 BV of LAssale, 2008 - private double meanInterDistance = 300., standardDeviationInterDistance = 978.; // for standard core values...Value for the selected 54 BV of the Atlantic Coast from the 196 BV of LAssale, 2008 + /** + * the mean surface used to standardize the catchment surface in the logistic function that calculates the probability to disperse + * @unit ? ha ? + */ + private double meanBvSurface = 23071.; // (from the 53 cathments among the 173 of Lassalles 2008) + + /** + * the standard deviation used to standardize the catchment surface in the logistic function that calculates the probability to disperse + * @unit ? ha ? + */ + private double standardDeviationBvSurface = 39833.; // (from the 53 cathments among the 173 of Lassalles 2008) + /** + * a map associtaing a sea bassin with the weight (accessibility and atrrtactivity) for each river bassin + * <key> SeaBasin + * <value> + * <key> RiverBasin + * <value> weight to calculate probaility to disperse + */ protected transient Map<Basin,Map<Basin,Double>> accessibleBasinsPerBasin; + + /** + * a map associtaing a sea bassin with the distance for each river bassin + * <key> SeaBasin + * <value> + * <key> RiverBasin + * <value> distance between the river Basin and the river basin associated with the sea basin + */ protected transient Map<Basin,Map<Basin,Double>> distanceBasinsPerBasin; - //private transient ObservablesHandler cObservable; + @Override @InitTransientParameters public void initTransientParameters(Pilot pilot) { super.initTransientParameters(pilot); - // calcul les poids des bassins voisins qui ne dépendent pas des poissons pour chaque SeaBassin + // calcul les poids des bassins voisins qui ne d�pendent pas des poissons pour chaque SeaBassin BasinNetwork bn = (BasinNetwork) pilot.getAquaticWorld().getEnvironment(); accessibleBasinsPerBasin = new TreeMap<Basin, Map<Basin,Double>>(); distanceBasinsPerBasin = new TreeMap<Basin, Map<Basin,Double>>(); for (Basin seaBas : bn.getSeaBasins()){ + // compoute the distance with between seaBas and all the river basins Map<Basin,Double> mapDist = bn.getNeighboursWithDistance(seaBas); distanceBasinsPerBasin.put(seaBas, mapDist); - // Compute the weight of each basin + // Compute the weight of each river basin Map<Basin,Double> accessibleBasins = bn.getNeighboursWithDistance(seaBas); for (Basin bas : accessibleBasins.keySet()){ double weight = alpha0Rep diff --git a/src/main/java/species/DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin.java b/src/main/java/species/DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin.java index b7f86e6c9a66d06a0c1100257a2d95c4506a0daa..e3949b2d192896b996f5c293eafef5cc4903af9f 100644 --- a/src/main/java/species/DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin.java +++ b/src/main/java/species/DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin.java @@ -18,17 +18,71 @@ import com.thoughtworks.xstream.io.xml.DomDriver; import miscellaneous.Duo; +/** + * + */ @ServiceProvider(service = AquaNismsGroupProcess.class) public class DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin extends DisperseAndMigrateToRiverBasic { + + /** + * the season when fish migrate to the river to reproduce + * @unit + */ + private Season riverMigrationSeason = Season.SPRING; + + /** + * the homing probalilty during the installation of new populations ( to reach kind of equilibrium) + * @unit + */ private double pHomingForReachEquil = 1.0; + + /** + * the homing probalilty after the installation of new populations ( after reaching an equilibrium) + * @unit + */ private double pHomingAfterEquil = 0.8; + + /** + * Number of year for newly created populations to be installed ( to reach an equilibrium) + * @unit + */ private long NbYearForInstallPop = 50; - private Season riverMigrationSeason = Season.SPRING; + + + /** the coefficient associated with the fish size in the logistic function used to calculate the probability to disperse + * @unit - + */ private double alpha2Rep = 0.; - private double meanSpawnersLengthAtRepro = 45., standardDeviationOfSpawnersLengthAtRepro = 2.; // for standard core values... + + /** + * the mean length used to standardize the fish length in the logistic function that calculates the probability to disperse + * @unit - + */ + private double meanSpawnersLengthAtRepro = 45.; + + /** + * the length standard deviation used to standardize the fish length in the logistic function that calculates the probability to disperse + * @unit - + */ + private double standardDeviationOfSpawnersLengthAtRepro = 2.; // for standard core values... + + /** + * the weigth of the death bassin ( for strayers that do not find a catcment) used to calculate the probability to disperse + * @unit + */ private double weightOfDeathBasin = 0.2; + + /** + * a bollean to kill of the strayers (used to determine if a catchment is a souce or a sink) the year given by yearOfTheKilling + * @unit + */ private boolean killStrayers; + + /** + * the year when the strayers are killed (used to determine if a catchment is a souce or a sink) if killStrayers is true + * @unit + */ private long yearOfTheKillings; public static void main(String[] args) { @@ -43,8 +97,9 @@ public class DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin extends Di BasinNetwork bn = group.getEnvironment(); long amountWithHoming, strayedAmount; - double pHoming; + // probability of homing + double pHoming; if (Time.getYear(group.getPilot()) < NbYearForInstallPop) { pHoming = pHomingForReachEquil; } else { @@ -54,18 +109,23 @@ public class DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin extends Di List<DiadromousFish> deadFish = new ArrayList<DiadromousFish>(); List<DiadromousFish> newFish = new ArrayList<DiadromousFish>(); + // creation of the death basin (for the lost strayers) + //TODO move as a transient field Basin deathBasin = new Basin(-1, "deathBasin", 0, 0, 0, 0); + List<Duo<DiadromousFish, Basin>> fishesToMove = new ArrayList<Duo<DiadromousFish, Basin>>(); for (Basin basin : group.getEnvironment().getSeaBasins()) { List<DiadromousFish> fishes = basin.getFishs(group); if (fishes != null) { - for (int j = 0; j < fishes.size(); j++) { - DiadromousFish fish = fishes.get(j); + for (DiadromousFish fish : fishes) { + + // verify that fish is in a sea basin assert fish.getPosition().getType() == Basin.TypeBassin.SEA; + if (fish.isMature()) { // fish with homing - amountWithHoming = Miscellaneous.binomialForSuperIndividual(group.getPilot(), fish.getAmount(), pHoming); // seuil par défaut fixé à 50 + amountWithHoming = Miscellaneous.binomialForSuperIndividual(group.getPilot(), fish.getAmount(), pHoming); // seuil par d�faut fix� � 50 // strayed fish if (killStrayers == true && Time.getYear(group.getPilot()) >= yearOfTheKillings) { @@ -75,10 +135,12 @@ public class DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin extends Di strayedAmount = fish.getAmount() - amountWithHoming; } + // influence of the fish length on the probability to disperse if (strayedAmount != 0) { - double weightFishLength = Math.exp(-(alpha2Rep * ((fish.getLength() - meanSpawnersLengthAtRepro) / standardDeviationOfSpawnersLengthAtRepro))); + // calcula the weight associated with the fish length in the probabaility to disperse + double weightFishLength = -(alpha2Rep * ((fish.getLength() - meanSpawnersLengthAtRepro) / standardDeviationOfSpawnersLengthAtRepro)); - // On récupère les info du poids des bassin par rapport à la position du poisson + // upload the weights associated with features of the catchment (accessibility and attractivity) List<Duo<Basin, Double>> accBasOfFish = new ArrayList<Duo<Basin, Double>>(); for (Map.Entry<Basin, Double> entry : accessibleBasinsPerBasin.get(fish.getPosition()).entrySet()) { Duo<Basin, Double> duo = new Duo<Basin, Double>(entry.getKey(), entry.getValue()); @@ -89,11 +151,13 @@ public class DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin extends Di double totalWeight = 0.; double probToGo = 0.; long amountToGo = 0; - // TODO Qu'est ce qui se passe si AccBasOfFish est vide... ça beug pas mais c'est pas très clair... donc à vérifier + // TODO manage the case when AccBasOfFish is empty for (Duo<Basin, Double> accBasin : accBasOfFish) { + // total weight for the basin Basin b = accBasin.getFirst(); Double weight = accBasin.getSecond(); - double accBasinWeight = 1 / (1 + Math.exp(-weight) * weightFishLength); + double accBasinWeight = 1 / (1 + Math.exp(-(weight + weightFishLength))); + // put weight to 0 for unused basins if (group.isThereBasinToUpdate()){ if (Time.getYear(group.getPilot()) >= group.getYearOfTheUpdate() @@ -104,10 +168,8 @@ public class DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin extends Di } accBasin.setSecond(accBasinWeight); totalWeight += accBasinWeight; - //} } - // add the deathBasin in the list accBasOfFish.add(new Duo<Basin, Double>(deathBasin, weightOfDeathBasin)); totalWeight = totalWeight + weightOfDeathBasin; @@ -141,7 +203,7 @@ public class DisperseAndMigrateToRiverWithMultiNomDistriAndDeathBasin extends Di if (amountWithHoming > 0) { fish.setAmount(amountWithHoming); // retour soit dans le bassin de naissance pour les semelpares - // soit dans le dernier bassin de reproduction pour les itéropares + // soit dans le dernier bassin de reproduction pour les it�ropares fishesToMove.add(new Duo<DiadromousFish, Basin>(fish, bn.getAssociatedRiverBasin(fish.getPosition()))); } else { deadFish.add(fish); diff --git a/src/main/java/species/ExportLenghtAgeDistribution.java b/src/main/java/species/ExportLenghtAgeDistribution.java new file mode 100644 index 0000000000000000000000000000000000000000..25a38baf047f813d67bb88cdc51d7697738792f9 --- /dev/null +++ b/src/main/java/species/ExportLenghtAgeDistribution.java @@ -0,0 +1,111 @@ +/** + * patrick.lambert + * @author Patrick Lambert + * @copyright Copyright (c) 2018, Irstea + * + * 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 <http://www.gnu.org/licenses/>. + + */ +package species; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; + +import environment.RiverBasin; +import environment.Time; +import environment.Time.Season; +import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; +import fr.cemagref.simaqualife.pilot.Pilot; +import species.DiadromousFish.Stage; + +/** + * + */ +public class ExportLenghtAgeDistribution extends AquaNismsGroupProcess<DiadromousFish, DiadromousFishGroup> { + + private Season exportSeason = Season.SPRING; + + private String fileNameOutput = "lengthAgeDistribution"; + + private transient BufferedWriter bW; + private transient String sep=";"; + + public static void main(String[] args) { + System.out.println((new XStream(new DomDriver())) + .toXML(new ExportLenghtAgeDistribution())); + } + + /* (non-Javadoc) + * @see fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess#initTransientParameters(fr.cemagref.simaqualife.pilot.Pilot) + */ + @Override + public void initTransientParameters(Pilot pilot) { + super.initTransientParameters(pilot); + sep=";"; + + } + + @Override + public void doProcess(DiadromousFishGroup group) { + + if (bW==null){ + if (fileNameOutput != null){ + new File(group.getOutputPath()+fileNameOutput).getParentFile().mkdirs(); + try { + bW = new BufferedWriter(new FileWriter(new File(group.getOutputPath()+ + fileNameOutput +group.getSimulationId()+ ".csv"))); + + bW.write("timestep"+sep+"year"+sep+"season"+sep+"basin"+ sep+"gender" + +sep+ "effective" +sep+"length"+sep+"age"+sep+"nbSpawn"+"\n"); + + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + try { + if (Time.getSeason(pilot) == exportSeason & Time.getYear(pilot)>1900) { + for (RiverBasin basin : group.getEnvironment().getRiverBasins()) { + if (basin.getFishs(group) != null) { + for (DiadromousFish fish : basin.getFishs(group)) { + if (fish.getStage() == Stage.MATURE) { + System.out.println(fish.getAge() + " -> "+ fish.getLength() +" - "+fish.getNumberOfReproduction()); + bW.write(pilot.getCurrentTime() + sep); + bW.write(Time.getYear(pilot) + sep); + bW.write(Time.getSeason(pilot) + sep); + bW.write(basin.getName() + sep); + bW.write(fish.getGender() + sep); + bW.write(fish.getAmount() + sep); + bW.write(fish.getLength() + sep); + bW.write(fish.getAge()+ sep); + bW.write(fish.getNumberOfReproduction()+ "\n"); + } + } + } + } + } + if (group.getPilot().getCurrentTime()== group.getPilot().getSimBegin()+group.getPilot().getSimDuration()-1) + bW.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} + diff --git a/src/main/java/species/Grow.java b/src/main/java/species/Grow.java index df3bb3f5fdd502d893a9f7e752384cb7329eb9b4..47bce1821a5728e4e85b139703f0a1e9c4727363 100644 --- a/src/main/java/species/Grow.java +++ b/src/main/java/species/Grow.java @@ -23,11 +23,36 @@ import umontreal.iro.lecuyer.randvar.NormalGen; @ServiceProvider(service = AquaNismsGroupProcess.class) public class Grow extends AquaNismsGroupProcess<DiadromousFish, DiadromousFishGroup> { + /** + * temperature minimum for growth + * @unit °C + */ private double tempMinGrow = 3.; + + /** + * temperature maximum for growth + * @unit °C + */ private double tempMaxGrow = 26.; + + /** + * temperature optimal for growth + * @unit °C + */ private double tempOptGrow = 17.; + + /** + * K, Brody growth rate at optimal temperature + * L = Linf *(1-exp(-K*(t-t0)) + * @unit year -1 + */ private double kOpt = 0.3; - private double sigmaDeltaLVonBert = 0.2; // random value... has to be fixed with literature + + /** + * standart deviation for the lognormal random draw of growth increment + * @unit cm + */ + private double sigmaDeltaLVonBert = 0.2; private transient NormalGen genNormal; @@ -37,45 +62,52 @@ public class Grow extends AquaNismsGroupProcess<DiadromousFish, DiadromousFishGr @Override @InitTransientParameters public void initTransientParameters(Pilot pilot) { - super.initTransientParameters(pilot); + super.initTransientParameters(pilot); genNormal = new NormalGen( pilot.getRandomStream(), new NormalDist(0., 1.)); } + @Override public void doProcess(DiadromousFishGroup group) { - for(Basin basin : group.getEnvironment().getBasins()){ - if (basin.getFishs(group)!=null) for(DiadromousFish fish : basin.getFishs(group)){ - double muDeltaLVonBert = 0.; - double kVonBert = 0.; - double growthIncrement = 0.; - //Grow - // 1) We calculate the kVonBert - - if (group.getKOpt()==Double.NaN){ - kVonBert = kOpt * - Miscellaneous.temperatureEffect(fish.getPosition().getCurrentTemperature(group.getPilot()), tempMinGrow, tempOptGrow, tempMaxGrow); - } else { - kVonBert = group.getKOpt() * - Miscellaneous.temperatureEffect(fish.getPosition().getCurrentTemperature(group.getPilot()), tempMinGrow, tempOptGrow, tempMaxGrow); - } - - // 2) We update the size of the fish - if (fish.getLength() < group.getLinfVonBert()){ - muDeltaLVonBert = Math.log((group.getLinfVonBert() - fish.getLength()) * (1 - Math.exp(-kVonBert * Time.getSeasonDuration()))) - (Math.pow(sigmaDeltaLVonBert,2))/2; - growthIncrement = Math.exp(genNormal.nextDouble()*sigmaDeltaLVonBert + muDeltaLVonBert); - fish.setLength(Math.min(group.getLinfVonBert(), fish.getLength() + growthIncrement)); - }else{ - fish.setLength(group.getLinfVonBert()); - } - - if (fish.getStage() == Stage.IMMATURE){ - if (fish.getLength() > group.getlFirstMaturity()){ - fish.setStage(Stage.MATURE); + for(Basin basin : group.getEnvironment().getBasins()){ + if (basin.getFishs(group)!=null) + for(DiadromousFish fish : basin.getFishs(group)){ + double muDeltaLVonBert = 0.; + double kVonBert = 0.; + double growthIncrement = 0.; + + // 1) calculate the kVonBert (from the grow process or forn Diadromousgroup + // when Brody coeff comes from calibration output + if (Double.isNaN(group.getKOpt())){ + kVonBert = kOpt * + Miscellaneous.temperatureEffect(fish.getPosition().getCurrentTemperature(group.getPilot()), tempMinGrow, tempOptGrow, tempMaxGrow); + } else { + kVonBert = group.getKOpt() * + Miscellaneous.temperatureEffect(fish.getPosition().getCurrentTemperature(group.getPilot()), tempMinGrow, tempOptGrow, tempMaxGrow); + } + + // 2) Update the fish length with a lognormal normal draw of increment + // limit the fish length to Linf + if (fish.getLength() < group.getLinfVonBert()){ + muDeltaLVonBert = Math.log((group.getLinfVonBert() - fish.getLength()) * (1 - Math.exp(-kVonBert * Time.getSeasonDuration()))) - (sigmaDeltaLVonBert*sigmaDeltaLVonBert)/2; + growthIncrement = Math.exp(genNormal.nextDouble()*sigmaDeltaLVonBert + muDeltaLVonBert); + + + fish.setLength(Math.min(group.getLinfVonBert(), fish.getLength() + growthIncrement)); + } + else { + fish.setLength(group.getLinfVonBert()); + } + //System.out.println(fish.getAge() + " -> "+ fish.getLength() + " ("+fish.getStage()+"): "+ growthIncrement); + // test if fish become mature + if (fish.getStage() == Stage.IMMATURE){ + if (fish.getLength() > group.getlFirstMaturity()){ + fish.setStage(Stage.MATURE); + } + } + //System.out.println("la temp�rature du lieu de vie du poisson est :" + fish.getPosition().getCurrentTemperature() + ", la saison est :" + Time.getSeason() + " et sa nouvelle taille est :" + fish.getLength()); } - } - //System.out.println("la température du lieu de vie du poisson est :" + fish.getPosition().getCurrentTemperature() + ", la saison est :" + Time.getSeason() + " et sa nouvelle taille est :" + fish.getLength()); - } - } + } } } diff --git a/src/main/java/species/IdentifyPopulation.java b/src/main/java/species/IdentifyPopulation.java index 68dea76c2ef15b90f8b5201a72be7c4b73d39ef2..f6e651d02dfa113db8ceb8b4b71d28b0a10d4960 100644 --- a/src/main/java/species/IdentifyPopulation.java +++ b/src/main/java/species/IdentifyPopulation.java @@ -69,7 +69,8 @@ public class IdentifyPopulation extends AquaNismsGroupProcess<DiadromousFish, Di bW = new BufferedWriter(new FileWriter(new File(group.getOutputPath()+ fileNameOutput +group.getSimulationId()+ ".csv"))); - BasinNetworkReal nbr= (BasinNetworkReal) pilot.getAquaticWorld().getEnvironment(); + // BasinNetworkReal nbr= (BasinNetworkReal) pilot.getAquaticWorld().getEnvironment(); + BasinNetwork nbr= group.getEnvironment(); bW.write("year"+sep+"migrationBasin"); for (String basinName : nbr.getRiverBasinNames()){ bW.write(sep+basinName); diff --git a/src/main/java/species/PopulateBasinNetwork.java b/src/main/java/species/PopulateBasinNetwork.java index 68631510d0a9acf80f67206f587c1a384fca0323..aae4046c03976a067b46a4d38f1d837cd471c95e 100644 --- a/src/main/java/species/PopulateBasinNetwork.java +++ b/src/main/java/species/PopulateBasinNetwork.java @@ -5,6 +5,8 @@ import com.thoughtworks.xstream.io.xml.DomDriver; import environment.Basin; import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; +import species.DiadromousFish.Gender; + import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = AquaNismsGroupProcess.class) @@ -21,7 +23,7 @@ public class PopulateBasinNetwork extends AquaNismsGroupProcess<DiadromousFish, public void doProcess(DiadromousFishGroup group) { for (Basin basin : group.getEnvironment().getRiverBasins()){ for (int i=0; i < nbSIPerBasin; i++){ - group.addAquaNism(new DiadromousFish(group.getPilot(), basin, initialLength, nbFishPerSI)); + group.addAquaNism(new DiadromousFish(group.getPilot(), basin, initialLength, nbFishPerSI, Gender.UNDIFFERENCIED)); } } } diff --git a/src/main/java/species/PopulateBasinNetworkWithANorthLimit.java b/src/main/java/species/PopulateBasinNetworkWithANorthLimit.java index 1c1b972a3f04fb023f1d9a11982b0fd964e53edd..c1ea61d092aed0ddb4c90da8fe6272c8b40cabfe 100644 --- a/src/main/java/species/PopulateBasinNetworkWithANorthLimit.java +++ b/src/main/java/species/PopulateBasinNetworkWithANorthLimit.java @@ -24,6 +24,7 @@ import com.thoughtworks.xstream.io.xml.DomDriver; import environment.RiverBasin; import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; +import species.DiadromousFish.Gender; /** * @@ -46,7 +47,7 @@ public class PopulateBasinNetworkWithANorthLimit extends AquaNismsGroupProcess<D for (RiverBasin basin : group.getEnvironment().getRiverBasins()){ if (basin.getLatitude()<=northLimitLatitude){ for (int i=0; i < nbSIPerBasin; i++){ - group.addAquaNism(new DiadromousFish(group.getPilot(), basin, initialLength, nbFishPerSI)); + group.addAquaNism(new DiadromousFish(group.getPilot(), basin, initialLength, nbFishPerSI, Gender.UNDIFFERENCIED)); } } } diff --git a/src/main/java/species/PopulateWithASinglePopulation.java b/src/main/java/species/PopulateWithASinglePopulation.java index 5278c926286487d2c3b45f42bbf7278adabc342f..5af2db3d2a432d09a4b4fa924b88be98825299c0 100644 --- a/src/main/java/species/PopulateWithASinglePopulation.java +++ b/src/main/java/species/PopulateWithASinglePopulation.java @@ -5,6 +5,8 @@ import com.thoughtworks.xstream.io.xml.DomDriver; import environment.Basin; import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; +import species.DiadromousFish.Gender; + import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = AquaNismsGroupProcess.class) @@ -23,7 +25,7 @@ public class PopulateWithASinglePopulation extends AquaNismsGroupProcess<Diadrom Basin basin = group.getEnvironment().getRiverBasins()[bassinInd]; for (int i=0; i < nbSIPerBasin; i++){ - group.addAquaNism(new DiadromousFish(group.getPilot(), basin, initialLength, nbIndPerSI)); + group.addAquaNism(new DiadromousFish(group.getPilot(), basin, initialLength, nbIndPerSI, Gender.UNDIFFERENCIED)); } } } diff --git a/src/main/java/species/ReproduceAndSurviveAfterReproduction.java b/src/main/java/species/ReproduceAndSurviveAfterReproduction.java index 9903cfa63d4da333970b41e1aabaa4c872662acf..8e8f773cbb3aa64198476c7b0995999594a281c2 100644 --- a/src/main/java/species/ReproduceAndSurviveAfterReproduction.java +++ b/src/main/java/species/ReproduceAndSurviveAfterReproduction.java @@ -10,6 +10,7 @@ import java.util.TreeMap; import miscellaneous.Duo; import miscellaneous.Miscellaneous; +import species.DiadromousFish.Gender; import org.openide.util.lookup.ServiceProvider; @@ -26,8 +27,8 @@ import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; import fr.cemagref.simaqualife.kernel.util.TransientParameters.InitTransientParameters; import fr.cemagref.simaqualife.pilot.Pilot; +@Deprecated @ServiceProvider(service = AquaNismsGroupProcess.class) - public class ReproduceAndSurviveAfterReproduction extends AquaNismsGroupProcess<DiadromousFish, DiadromousFishGroup>{ // for the calibration of the model we use S_etoileGir = 190000; surfGir = 80351; @@ -48,10 +49,8 @@ public class ReproduceAndSurviveAfterReproduction extends AquaNismsGroupProcess< private double survivalRateAfterReproduction = 0.1; private double maxNumberOfSuperIndividualPerReproduction = 50.; - private transient NormalGen genNormal; - // private transient UniformGen genUniform; public static void main(String[] args) { System.out.println((new XStream(new DomDriver())) .toXML(new ReproduceAndSurviveAfterReproduction())); } @@ -92,14 +91,15 @@ public class ReproduceAndSurviveAfterReproduction extends AquaNismsGroupProcess< // origins of spawner during this reproduction Map<String, Long> spawnerOriginsDuringReproduction = new HashMap<String, Long>(group.getEnvironment().getRiverBasinNames().length); for (String basinName : group.getEnvironment().getRiverBasinNames()){ - spawnerOriginsDuringReproduction.put(basinName, (long) 0); + spawnerOriginsDuringReproduction.put(basinName, 0L); } // System.out.println("REPRODUCTION in "+riverBasin.getName()+" : FISH FROM "); List<DiadromousFish> fishInBasin = riverBasin.getFishs(group); if (fishInBasin != null){ - //Calcul of b and c in stock-recruitment relationships + + // effective temperature for reproduction (priority to the ANG value) double tempEffectRep; if (group.getTempMinRep() == Double.NaN){ tempEffectRep = Miscellaneous.temperatureEffect(riverBasin.getCurrentTemperature(group.getPilot()), tempMinRep, tempOptRep, tempMaxRep); @@ -108,36 +108,36 @@ public class ReproduceAndSurviveAfterReproduction extends AquaNismsGroupProcess< tempEffectRep = Miscellaneous.temperatureEffect(riverBasin.getCurrentTemperature(group.getPilot()), group.getTempMinRep(), tempOptRep, tempMaxRep); } - if (tempEffectRep == 0.) - b=0; - else - b = - Math.log(survOptRep * tempEffectRep) / delta_t; - + // Compute the prelimenary parameters b and c for the stock-recruitment relationship + b = (tempEffectRep == 0.) ? 0. : - Math.log(survOptRep * tempEffectRep) / delta_t; c = lambda/riverBasin.getAccessibleSurface(); - // Calcul of alpha and beta of the basin + // Compute alpha and beta parameters of the the stock-recruitment relationship alpha = (b * Math.exp(- b * delta_t))/(c * (1 - Math.exp(- b * delta_t))); beta = b / (a * c * (1 - Math.exp(- b * delta_t))); - //System.out.println(a+ ", " +b + ", " + c + ", " + delta_t + "= "+ alpha); + + // keep the last value of alpha (productive capacities) riverBasin.getLastProdCapacities().push(alpha); - // Calcul of the amount per superIndividual + // Compute the amount per superIndividual amountPerSuperIndividual = alpha / maxNumberOfSuperIndividualPerReproduction; - // Calcul of Setoile, S95 and S50 - Setoile = eta * riverBasin.getAccessibleSurface(); - S95 = Setoile; + // Compute the Allee effect parameters S95 and S50 + S95 = eta * riverBasin.getAccessibleSurface(); // corresponds to S* in the rougier publication S50 = S95 / ratioS95_S50; - // compute the number of spawners and keep the origines of the spawners + // initilisation of the stock recruitment relationship + //stockRecruitmentRelationship.init(alpha, beta, S50, S95); + // age of autochnonous spawnser //Map<Integer, Long> ageOfNativeSpawners = new TreeMap<Integer, Long>(); + // compute the number of spawners and keep the origine of the spawners for( DiadromousFish fish : fishInBasin){ if( fish.isMature()){ if (fish.getNumberOfReproduction() < 1) { - numberOfSpawnerForFirstTime++; + numberOfSpawnerForFirstTime++; //ASK individual or super-individual ? spawnersForFirstTimeAgesSum += fish.getAge(); } numberOfGenitors += fish.getAmount() ; @@ -146,18 +146,17 @@ public class ReproduceAndSurviveAfterReproduction extends AquaNismsGroupProcess< String basinName = fish.getBirthBasin().getName(); spawnerOriginsDuringReproduction.put(basinName, spawnerOriginsDuringReproduction.get(basinName) + fish.getAmount() ); - // number of autochtone and age of autochnone - if (riverBasin == fish.getBirthBasin()){ + // number of autochtonous fish per age + /*if (riverBasin == fish.getBirthBasin()){ numberOfAutochtones += fish.getAmount(); - /*Integer age = (int) Math.floor(fish.getAge()); + Integer age = (int) Math.floor(fish.getAge()); if (ageOfNativeSpawners.containsKey(age)) ageOfNativeSpawners.put(age, ageOfNativeSpawners.get(age)+fish.getAmount()); else - ageOfNativeSpawners.put(age, fish.getAmount());*/ - } + ageOfNativeSpawners.put(age, fish.getAmount()); + } */ - //System.out.println("l'âge du poisson est :" + fish.getAge() + " et la saison est :" + Time.getSeason()); - // Survive After Reproduction + // increment number of reproduction (for possible iteroparty) fish.incNumberOfReproduction(); // survival after reproduction (semelparity or iteroparity) of SI (change the amount of the SI) @@ -169,8 +168,9 @@ public class ReproduceAndSurviveAfterReproduction extends AquaNismsGroupProcess< } } + System.out.println(" numberOfGenitors: "+ numberOfGenitors); /* - // calcul de la mortalité associée aux géniteurs autochtones + // calcul de la mortalit� associ�e aux g�niteurs autochtones if (numberOfGenitors > 0.) { System.out.println(riverBasin.getName().toUpperCase()); System.out.println("Spawners"); @@ -209,12 +209,15 @@ public class ReproduceAndSurviveAfterReproduction extends AquaNismsGroupProcess< double meanNumberOfRecruit = Math.round((alpha * numberOfGenitors * (1 / (1 + Math.exp(- Math.log(19)*((numberOfGenitors - S50) / (S95 - S50)))))) / (beta + numberOfGenitors * (1 / (1 + Math.exp(- Math.log(19)*((numberOfGenitors - S50) / (S95 - S50))))))); - muRecruitment = Math.log(meanNumberOfRecruit) - (Math.pow(sigmaRecruitment,2))/2; + // lognormal random draw + muRecruitment = Math.log(meanNumberOfRecruit) - (Math.pow(sigmaRecruitment,2))/2; long numberOfRecruit = Math.round(Math.exp(genNormal.nextDouble()*sigmaRecruitment + muRecruitment)); + // keep last % of autochtone riverBasin.getLastPercentagesOfAutochtones().push(numberOfAutochtones * 100 / numberOfGenitors); + // keep the number of spawners for the firt time in the basin if (numberOfSpawnerForFirstTime>0){ riverBasin.getSpawnersForFirstTimeMeanAges().push(spawnersForFirstTimeAgesSum/numberOfSpawnerForFirstTime); }else{ @@ -225,25 +228,26 @@ public class ReproduceAndSurviveAfterReproduction extends AquaNismsGroupProcess< //System.out.println("nb recruit in basin " + riverBasin.getName() + " : " + numberOfRecruit); // Creation of new superFish - if(numberOfRecruit > 0){ - // stock the first year when recruitment is non nul - if(riverBasin.getYearOfFirstNonNulRep() == 0){ - riverBasin.setYearOfFirstNonNulRep(Time.getYear(group.getPilot())); - } - + if (numberOfRecruit > 0){ + + // features of the super individuals int numberOfsuperIndividual = Math.max(1, (int) Math.round(numberOfRecruit / amountPerSuperIndividual)); long effectiveAmount = numberOfRecruit / numberOfsuperIndividual; - - // System.out.println(numberOfRecruit + " / " + amountPerSuperIndividual +" = " +numberOfsuperIndividual); - //System.out.println(numberOfRecruit + " / " + numberOfsuperIndividual +" = " +effectiveAmount); + for (int i=0; i<numberOfsuperIndividual; i++){ - group.addAquaNism(new DiadromousFish(group.getPilot(), riverBasin, initialLength, effectiveAmount)); + group.addAquaNism(new DiadromousFish(group.getPilot(), riverBasin, initialLength, effectiveAmount, Gender.UNDIFFERENCIED)); } + + // stock the first year when recruitment is non nul + if (riverBasin.getYearOfFirstNonNulRep() == 0){ + riverBasin.setYearOfFirstNonNulRep(Time.getYear(group.getPilot())); + } riverBasin.getLastRecruitmentExpectations().push(Math.round(meanNumberOfRecruit)); - riverBasin.getLastRecruitments().push(numberOfsuperIndividual * effectiveAmount); // on remplit la pile qui permet de stocker un nombre fixé de derniers recrutement + riverBasin.getLastRecruitments().push(numberOfsuperIndividual * effectiveAmount); // on remplit la pile qui permet de stocker un nombre fix� de derniers recrutement riverBasin.getLastRecsOverProdCaps().push(((double) riverBasin.getLastRecruitments().getLastItem())/riverBasin.getLastProdCapacities().getLastItem()); + if (numberOfAutochtones > 0){ riverBasin.getNumberOfNonNulRecruitmentForFinalProbOfPres().push(1.0); riverBasin.getNumberOfNonNulRecruitmentDuringLastYears().push(1.0); @@ -289,7 +293,7 @@ public class ReproduceAndSurviveAfterReproduction extends AquaNismsGroupProcess< riverBasin.getSpawnerOrigins().push(spawnerOriginsDuringReproduction); //System.out.println(" AFTER " +riverBasin.getSpawnerOrigins().keySet()); } - // on met à jour les observeurs + // on met � jour les observeurs for (RiverBasin riverBasin : group.getEnvironment().getRiverBasins()){ riverBasin.getCobservable().fireChanges(riverBasin, pilot.getCurrentTime()); } diff --git a/src/main/java/species/ReproduceAndSurviveAfterReproductionWithDiagnose.java b/src/main/java/species/ReproduceAndSurviveAfterReproductionWithDiagnose.java index 530e581296c1df8c95f57c3b7094c2ca333e100e..63f83c7bcd6002dd403b266a9c83e3ed9faa51eb 100644 --- a/src/main/java/species/ReproduceAndSurviveAfterReproductionWithDiagnose.java +++ b/src/main/java/species/ReproduceAndSurviveAfterReproductionWithDiagnose.java @@ -11,6 +11,7 @@ import java.util.TreeMap; import miscellaneous.Duo; import miscellaneous.Miscellaneous; import miscellaneous.Trio; +import species.DiadromousFish.Gender; import org.apache.commons.math3.analysis.UnivariateFunction; import org.apache.commons.math3.optim.MaxEval; @@ -55,6 +56,7 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG private double sigmaRecruitment = 0.3; private double survivalRateAfterReproduction = 0.1; private double maxNumberOfSuperIndividualPerReproduction = 50.; + private boolean withDiagnose = true; private transient NormalGen genNormal; @@ -82,7 +84,7 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG List<DiadromousFish> deadFish = new ArrayList<DiadromousFish>(); for(RiverBasin riverBasin : group.getEnvironment().getRiverBasins()){ - double b, c, alpha, beta, amountPerSuperIndividual , Setoile, S95, S50 ; + double b, c, alpha, beta, amountPerSuperIndividual , S95, S50 ; double numberOfGenitors = 0.; double numberOfAutochtones = 0.; double numberOfSpawnerForFirstTime = 0.; @@ -94,56 +96,59 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG // origins of spawner during this reproduction Map<String, Long> spawnerOriginsDuringReproduction = new HashMap<String, Long>(group.getEnvironment().getRiverBasinNames().length); for (String basinName : group.getEnvironment().getRiverBasinNames()){ - spawnerOriginsDuringReproduction.put(basinName, (long) 0); + spawnerOriginsDuringReproduction.put(basinName, 0L); } List<DiadromousFish> fishInBasin = riverBasin.getFishs(group); if (fishInBasin != null){ - //Calcul of b and c in stock-recruitment relationships + // -------------------------------------------------------------------------------------------------- + // definition of the stock recruiment relationship + // -------------------------------------------------------------------------------------------------- + + // effective temperature for reproduction (priority to the ANG value) double tempEffectRep; - if (group.getTempMinRep() == Double.NaN){ + if (Double.isNaN(group.getTempMinRep())){ tempEffectRep = Miscellaneous.temperatureEffect(riverBasin.getCurrentTemperature(group.getPilot()), tempMinRep, tempOptRep, tempMaxRep); } else { tempEffectRep = Miscellaneous.temperatureEffect(riverBasin.getCurrentTemperature(group.getPilot()), group.getTempMinRep(), tempOptRep, tempMaxRep); } - // Calcul of alpha and beta of the basin + // Compute the prelimenary parameters b and c for the stock-recruitment relationship + b = (tempEffectRep == 0.) ? 0. : - Math.log(survOptRep * tempEffectRep) / delta_t; c = lambda/riverBasin.getAccessibleSurface(); - if (tempEffectRep == 0.){ - b=0; - alpha=0.; - beta=0.; - } - else { - b = - Math.log(survOptRep * tempEffectRep) / delta_t; - alpha = (b * Math.exp(- b * delta_t))/(c * (1 - Math.exp(- b * delta_t))); - beta = b / (a * c * (1 - Math.exp(- b * delta_t))); - } + // Compute alpha and beta parameters of the the stock-recruitment relationship + alpha = (b * Math.exp(- b * delta_t))/(c * (1 - Math.exp(- b * delta_t))); + beta = b / (a * c * (1 - Math.exp(- b * delta_t))); //System.out.println(a+ ", " +b + ", " + c + ", " + delta_t + "= "+ alpha); + + // keep the last value of alpha (productive capacities) riverBasin.getLastProdCapacities().push(alpha); - // Calcul of the amount per superIndividual + // Compute the amount per superIndividual amountPerSuperIndividual = alpha / maxNumberOfSuperIndividualPerReproduction; - // Calcul of Setoile, S95 and S50 - Setoile = eta * riverBasin.getAccessibleSurface(); - S95 = Setoile; + // Compute the Allee effect parameters S95 and S50 + S95 = eta * riverBasin.getAccessibleSurface(); // corresponds to S* in the rougier publication S50 = S95 / ratioS95_S50; - // initilisation de la relation stock recruitment + // initilisation of the stock recruitment relationship stockRecruitmentRelationship.init(alpha, beta, S50, S95); + + // -------------------------------------------------------------------------------------------------- + // calulation of the spawner number + // -------------------------------------------------------------------------------------------------- - // calcul de Zcrash - //Double Zcrash = Math.log(alpha*(d-1)/(d*beta*Math.pow(d-1, 1/d))); // age of autochnonous spawnser Map<Integer, Long> ageOfNativeSpawners = new TreeMap<Integer, Long>(); // compute the number of spawners and keep the origines of the spawners for( DiadromousFish fish : fishInBasin){ if( fish.isMature()){ + + //System.out.println(fish.getAge() + " -> "+ fish.getLength() + " ("+fish.getStage()+")"); if (fish.getNumberOfReproduction() < 1) { numberOfSpawnerForFirstTime++; spawnersForFirstTimeAgesSum += fish.getAge(); @@ -154,18 +159,17 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG String basinName = fish.getBirthBasin().getName(); spawnerOriginsDuringReproduction.put(basinName, spawnerOriginsDuringReproduction.get(basinName) + fish.getAmount() ); - // number of autochtone and age of autochnone + // number of autochtonous fish per age if (riverBasin == fish.getBirthBasin()){ numberOfAutochtones += fish.getAmount(); - Integer age = (int) Math.floor(fish.getAge()); + Integer age = (int) Math.floor(fish.getAge()); //ASK floor() or ceil() if (ageOfNativeSpawners.containsKey(age)) ageOfNativeSpawners.put(age, ageOfNativeSpawners.get(age)+fish.getAmount()); else ageOfNativeSpawners.put(age, fish.getAmount()); } - //System.out.println("l'âge du poisson est :" + fish.getAge() + " et la saison est :" + Time.getSeason()); - // Survive After Reproduction + // increment number of reproduction (for possible iteroparty) fish.incNumberOfReproduction(); // survival after reproduction (semelparity or iteroparity) of SI (change the amount of the SI) @@ -177,76 +181,93 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG } } + // keep the spawner number + riverBasin.setLastSpawnerNumber(numberOfGenitors); - // prepare les données pour le calcul de la mortalité associée aux géniteurs autochtones - if (numberOfGenitors > 0.) { - List<Trio<Integer, Long, Long>> mortalityData= new ArrayList<Trio<Integer, Long, Long>>(); - // first age - // second effective of native spwaner - // third effective of corresponding recruitment - for (Integer age : ageOfNativeSpawners.keySet()){ - if (riverBasin.getLastRecruitments().getItemFromLast(age) != null){ - mortalityData.add(new Trio<Integer, Long, Long>(age, - ageOfNativeSpawners.get(age), - riverBasin.getLastRecruitments().getItemFromLast(age))); - } else{ - mortalityData.add(new Trio<Integer, Long, Long>(age, 0L, 0L)); + // -------------------------------------------------------------------------------------------------- + // Diagnose of the population dynamics in the basin + // -------------------------------------------------------------------------------------------------- + if (withDiagnose==true) { + // calculate and keep the features of the stock recruitment relationships + riverBasin.setMortalityCrash(stockRecruitmentRelationship.getSigmaZcrash()); + + // initialise the mortality function for the autochnous spawners + // use to approximate the mortality of all the spawners to give a proxy of the Allee trap + if (numberOfGenitors > 0.) { + List<Trio<Integer, Long, Long>> mortalityData= new ArrayList<Trio<Integer, Long, Long>>(); + // first age + // second effective of native spwaner + // third effective of corresponding recruitment + for (Integer age : ageOfNativeSpawners.keySet()){ + if (riverBasin.getLastRecruitments().getItemFromLast(age) != null){ + mortalityData.add(new Trio<Integer, Long, Long>(age, + ageOfNativeSpawners.get(age), + riverBasin.getLastRecruitments().getItemFromLast(age))); + } + else{ + mortalityData.add(new Trio<Integer, Long, Long>(age, 0L, 0L)); + } } + mortalityFunction.init(mortalityData); + riverBasin.setNativeSpawnerMortality(mortalityFunction.getSigmaZ()); + } + else { + riverBasin.setNativeSpawnerMortality(Double.NaN); } - mortalityFunction.init(mortalityData); - riverBasin.setNativeSpawnerMortality(mortalityFunction.getSigmaZ()); - } - else{ - riverBasin.setNativeSpawnerMortality(Double.NaN); - } - - riverBasin.setMortalityCrash(stockRecruitmentRelationship.getSigmaZcrash()); - riverBasin.setStockTrap(stockRecruitmentRelationship.getStockTrap(riverBasin.getNativeSpawnerMortality())); - riverBasin.setLastSpawnerNumber(numberOfGenitors); - - // AFFICHAGE DES RESULTATS - /*System.out.println(riverBasin.getName().toUpperCase()); - //System.out.println("alpha="+alpha+ "\tbeta="+beta+"\tS50="+S50+ "\tS95="+S95); - System.out.println("\tScrash="+stockRecruitmentRelationship.getStockAtZcrash()+ - "\tZcrash="+ stockRecruitmentRelationship.getSigmaZcrash() + - "\tZ="+ riverBasin.getNativeSpawnerMortality()); - System.out.println("\tStrap="+stockRecruitmentRelationship.getStockTrap(riverBasin.getNativeSpawnerMortality())+ - "\tStotal="+numberOfGenitors+"\tSautochthonous="+ - spawnerOriginsDuringReproduction.get(riverBasin.getName())); - - - String diagnose; - if (Double.isNaN(riverBasin.getNativeSpawnerMortality())) - diagnose="noSense"; - else { - double stockTrap=stockRecruitmentRelationship.getStockTrap(riverBasin.getNativeSpawnerMortality()); - if (riverBasin.getNativeSpawnerMortality()>stockRecruitmentRelationship.getSigmaZcrash()) - diagnose="overZcrash"; + riverBasin.setStockTrap(stockRecruitmentRelationship.getStockTrap(riverBasin.getNativeSpawnerMortality())); + + + System.out.println(riverBasin.getName().toUpperCase()); + //System.out.println("alpha="+alpha+ "\tbeta="+beta+"\tS50="+S50+ "\tS95="+S95); + System.out.println("\tScrash="+stockRecruitmentRelationship.getStockAtZcrash()+ + "\tZcrash="+ stockRecruitmentRelationship.getSigmaZcrash() + + "\tZ="+ riverBasin.getNativeSpawnerMortality()); + System.out.println("\tStrap="+stockRecruitmentRelationship.getStockTrap(riverBasin.getNativeSpawnerMortality())+ + "\tStotal="+numberOfGenitors+"\tSautochthonous="+ + spawnerOriginsDuringReproduction.get(riverBasin.getName())); + + + String message; + if (Double.isNaN(riverBasin.getNativeSpawnerMortality())) + message="noSense"; else { - if (numberOfGenitors < stockTrap) - diagnose = "inTrapWithStrayers"; + double stockTrap=stockRecruitmentRelationship.getStockTrap(riverBasin.getNativeSpawnerMortality()); + if (riverBasin.getNativeSpawnerMortality()>stockRecruitmentRelationship.getSigmaZcrash()) + message="overZcrash"; else { - if (spawnerOriginsDuringReproduction.get(riverBasin.getName()) < stockTrap) - diagnose = "inTrapWithOnlyNatives"; - else - diagnose = "sustain"; + if (numberOfGenitors < stockTrap) + message = "inTrapWithStrayers"; + else { + if (spawnerOriginsDuringReproduction.get(riverBasin.getName()) < stockTrap) + message = "inTrapWithOnlyNatives"; + else + message = "sustain"; + } } } + System.out.println("\t"+message); } - System.out.println("\t"+diagnose);*/ - + // -------------------------------------------------------------------------------------------------- // Reproduction process (number of recruits) + // -------------------------------------------------------------------------------------------------- + if (numberOfGenitors > 0.) { + //BH Stock-Recruitment relationship with logistic depensation double meanNumberOfRecruit = stockRecruitmentRelationship.getRecruitment(numberOfGenitors); - muRecruitment = Math.log(meanNumberOfRecruit) - (Math.pow(sigmaRecruitment,2))/2; + // lognormal random draw + muRecruitment = Math.log(meanNumberOfRecruit) - (Math.pow(sigmaRecruitment,2))/2; long numberOfRecruit = Math.round(Math.exp(genNormal.nextDouble()*sigmaRecruitment + muRecruitment)); + //System.out.println(group.getPilot().getCurrentTime()+" "+Time.getSeason(group.getPilot())+" "+ riverBasin.getName()+": " + numberOfGenitors + " spwaners \tgive "+ numberOfRecruit + " recruits"); + + // keep last % of autochtone riverBasin.getLastPercentagesOfAutochtones().push(numberOfAutochtones * 100 / numberOfGenitors); + // keep the number of spawners for the firt time in the basin if (numberOfSpawnerForFirstTime>0){ riverBasin.getSpawnersForFirstTimeMeanAges().push(spawnersForFirstTimeAgesSum/numberOfSpawnerForFirstTime); }else{ @@ -257,31 +278,34 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG //System.out.println("nb recruit in basin " + riverBasin.getName() + " : " + numberOfRecruit); // Creation of new superFish - if(numberOfRecruit > 0){ - // stock the first year when recruitment is non nul - if(riverBasin.getYearOfFirstNonNulRep() == 0){ - riverBasin.setYearOfFirstNonNulRep(Time.getYear(group.getPilot())); - } + if (numberOfRecruit > 0){ + // features of the super individuals int numberOfsuperIndividual = Math.max(1, (int) Math.round(numberOfRecruit / amountPerSuperIndividual)); long effectiveAmount = numberOfRecruit / numberOfsuperIndividual; - // System.out.println(numberOfRecruit + " / " + amountPerSuperIndividual +" = " +numberOfsuperIndividual); - //System.out.println(numberOfRecruit + " / " + numberOfsuperIndividual +" = " +effectiveAmount); - for (int i=0; i<numberOfsuperIndividual; i++){ - group.addAquaNism(new DiadromousFish(group.getPilot(), riverBasin, initialLength, effectiveAmount)); + for (int i = 0; i < numberOfsuperIndividual; i++){ + group.addAquaNism(new DiadromousFish(group.getPilot(), riverBasin, initialLength, effectiveAmount, Gender.UNDIFFERENCIED)); } + + // stock the first year when recruitment is non nul + if (riverBasin.getYearOfFirstNonNulRep() == 0){ + riverBasin.setYearOfFirstNonNulRep(Time.getYear(group.getPilot())); + } + + // keep the last recruitments in the stack riverBasin.getLastRecruitmentExpectations().push(Math.round(meanNumberOfRecruit)); - riverBasin.getLastRecruitments().push(numberOfsuperIndividual * effectiveAmount); // on remplit la pile qui permet de stocker un nombre fixé de derniers recrutement + riverBasin.getLastRecruitments().push(numberOfsuperIndividual * effectiveAmount); riverBasin.getLastRecsOverProdCaps().push(((double) riverBasin.getLastRecruitments().getLastItem())/riverBasin.getLastProdCapacities().getLastItem()); + // keep the no null recruitment if (numberOfAutochtones > 0){ - riverBasin.getNumberOfNonNulRecruitmentForFinalProbOfPres().push(1.0); - riverBasin.getNumberOfNonNulRecruitmentDuringLastYears().push(1.0); + riverBasin.getNumberOfNonNulRecruitmentForFinalProbOfPres().push(1.); + riverBasin.getNumberOfNonNulRecruitmentDuringLastYears().push(1.); }else{ - riverBasin.getNumberOfNonNulRecruitmentForFinalProbOfPres().push(0.0); - riverBasin.getNumberOfNonNulRecruitmentDuringLastYears().push(0.0); + riverBasin.getNumberOfNonNulRecruitmentForFinalProbOfPres().push(0.); + riverBasin.getNumberOfNonNulRecruitmentDuringLastYears().push(0.); } } @@ -292,7 +316,7 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG riverBasin.getLastRecruitments().push((long) 0); riverBasin.getLastRecsOverProdCaps().push(0.); riverBasin.getNumberOfNonNulRecruitmentDuringLastYears().push(0.); - riverBasin.getNumberOfNonNulRecruitmentForFinalProbOfPres().push(0.0); + riverBasin.getNumberOfNonNulRecruitmentForFinalProbOfPres().push(0.); } } else { @@ -303,10 +327,11 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG riverBasin.getLastRecsOverProdCaps().push(0.); riverBasin.getLastPercentagesOfAutochtones().push(0.); riverBasin.getNumberOfNonNulRecruitmentDuringLastYears().push(0.); - riverBasin.getNumberOfNonNulRecruitmentForFinalProbOfPres().push(0.0); + riverBasin.getNumberOfNonNulRecruitmentForFinalProbOfPres().push(0.); } - + // -------------------------------------------------------------------------------------------------- // Remove deadfish + // -------------------------------------------------------------------------------------------------- for (DiadromousFish fish : deadFish){ group.removeAquaNism(fish); } @@ -321,45 +346,101 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG riverBasin.getSpawnerOrigins().push(spawnerOriginsDuringReproduction); //System.out.println(" AFTER " +riverBasin.getSpawnerOrigins().keySet()); } - // on met à jour les observeurs + // -------------------------------------------------------------------------------------------------- + // update the observers + // -------------------------------------------------------------------------------------------------- for (RiverBasin riverBasin : group.getEnvironment().getRiverBasins()){ riverBasin.getCobservable().fireChanges(riverBasin, pilot.getCurrentTime()); } } } + /** + * Berverton and Holt stock-recruitment relationship with an Allee effect simulated with a logistic function + */ class StockRecruitmentRelationship implements UnivariateFunction{ + /** + * alpha of the stock-recruitment relationship + * R = beta Seff / (beta + Seff) with Seff the stock that effectivly participates to the reproduction + * + * @unit # of individuals + */ double alpha; + + /** + * * beta of the stock-recruitment relationship + * R = alpha * Seff / (beta + Seff) with Seff the stock that effectivly participates to the reproduction + * @unit + */ double beta; + + /** + * the value of the stock for which 50% partipate to the reproduction + * @unit # of individuals + */ double S50; + + /** + * the value of the stock for which 95% partipate to the reproduction + * @unit # of individuals + */ double S95; - double sigmaZ; // mortality + /** + * to simplify the calculation + * @unit + */ + transient double log19; + + /** + * the value of the stock for which 50% partipate to the reproduction + * @unit # of individuals + */ + double sigmaZ; // public void init(double alpha, double beta, double S50, double S95) { this.alpha = alpha; this.beta = beta; this.S50 = S50; this.S95 = S95; + + log19 = Math.log(19) ; + } + + + public double getEffectiveStock (double stock) { + return stock / (1 + Math.exp(- log19 * (stock - S50) / (S95 - S50))); } + public double getRecruitment(double stock){ //BH Stock-Recruitment relationship with logistic depensation double meanNumberOfRecruit = 0.; + double effectiveStock = getEffectiveStock(stock); if (stock >0) - meanNumberOfRecruit= Math.round((alpha * stock * (1 / (1 + Math.exp(- Math.log(19)*((stock - S50) / (S95 - S50)))))) / - (beta + stock * (1 / (1 + Math.exp(- Math.log(19)*((stock - S50) / (S95 - S50))))))); + meanNumberOfRecruit = Math.round(alpha * effectiveStock) /(beta + effectiveStock ); return meanNumberOfRecruit; } + + /** + * the stock that corresponds to the intersection between SR relationship and tahe tangent that pass through the origin + * @return the stock at + */ public double getStockAtZcrash(){ if (beta !=0) - return(S50 + (S95 - S50) * Math.log(beta * Math.log(19) / (S95-S50)) / Math.log(19)); + return(S50 + (S95 - S50) * Math.log(beta * log19 / (S95-S50)) / log19); else return Double.NaN; } + + /** + * the crash mortality + * (corresponds the slope of the tangent that pass through the origin) + * @return the crash mortality ( year-1) + */ public double getSigmaZcrash(){ double stockAtZcrash= getStockAtZcrash(); if (!Double.isNaN(stockAtZcrash)) @@ -369,13 +450,23 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG } + /** + * the objective function uses to calculate the depensation trap (Allee trap) + */ @Override - public double value(double S) { - double res=getRecruitment(S)-S*Math.exp(sigmaZ); + public double value(double stock) { + double res=getRecruitment(stock) - stock * Math.exp(sigmaZ); return res*res; } - private double getPoint(double sigmaZ){ + + /** + * calculate the stock correspondinf to the depensation trap + * corresponds to intersection between mortality rate and the stock-recruitment relationship + * @param sigmaZ the total mortality coefficient + * @return + */ + private double getStockTrap(double sigmaZ){ if (!Double.isNaN(sigmaZ)){ this.sigmaZ=sigmaZ; BrentOptimizer optimizer = new BrentOptimizer(1e-6, 1e-12); @@ -384,25 +475,23 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG new MaxEval(100), GoalType.MINIMIZE, new SearchInterval(0, getStockAtZcrash())); - this.sigmaZ = Double.NaN; + this.sigmaZ = Double.NaN; //WHY return solution.getPoint(); } else return Double.NaN; } - - public double getStockTrap(double sigmaZ) { - return getPoint(sigmaZ); - } - } + /** + * mortatiity function for stock with dirrenet ages + */ class MortalityFunction implements UnivariateFunction { - // first age - // second effective of native spwaner - // third effective of corresponding recruitment - List<Trio<Integer, Long, Long>> data; + // first: age + // second: effective of native spwaner + // third: effective of corresponding recruitment + List<Trio<Integer, Long, Long>> data; //WHY age as integer public void init(List<Trio<Integer, Long, Long>> data){ this.data = data; @@ -418,50 +507,45 @@ public class ReproduceAndSurviveAfterReproductionWithDiagnose extends AquaNismsG return res/effTotal; } + @Override public double value(double Z) { double res=0.; for(Trio<Integer, Long, Long> trio : data){ res += (((double) trio.getSecond())/((double) trio.getThird())) * Math.exp(Z * (double) trio.getFirst()); } - return Math.pow(res-1., 2.); + return (res-1) * (res-1); //WHY -1 } - private double getPoint(){ - if (data.isEmpty()){ - return Double.NaN; - } - else { + + /** + * calculate by optimsation of the total mortality coefficient over the livespan + * @return + */ + private double getSigmaZ2(){ + double Z = Double.NaN; + + if (!data.isEmpty()){ BrentOptimizer optimizer = new BrentOptimizer(1e-6, 1e-12); UnivariatePointValuePair solution = optimizer.optimize(new UnivariateObjectiveFunction(this), new MaxEval(100), GoalType.MINIMIZE, new SearchInterval(0, 10)); - return solution.getPoint(); + Z= solution.getPoint(); } + return Z * getMeanAge(); } - // return sigmaZ = Z*meanAge - public double getSigmaZ2(){ - /*double Z = getPoint(); - double alpha; // % of maturation for a given age - double sum=0; - double sum1=0; - for(Trio<Integer, Long, Long> trio : data){ - alpha = ((double)trio.getSecond()) / (((double)trio.getThird())*Math.exp(-((double) trio.getFirst())*Z)); - sum += alpha * Math.exp(-((double) trio.getFirst())*Z); - sum1 += ((double)trio.getSecond()) / ((double)trio.getThird()); - } - - System.out.println(getPoint()*getMeanAge()+" <> "+ Math.log(sum)+ " <> " + Math.log(sum1));*/ - return getPoint()*getMeanAge(); - } - + + /** + * simple approximation of total mortality coefficient over the lifespan + * @return + */ public double getSigmaZ(){ double sum=0; for(Trio<Integer, Long, Long> trio : data){ - sum += ((double)trio.getSecond()) / ((double)trio.getThird()); + sum += ((double)trio.getSecond()) / ((double)trio.getThird()); } return (- Math.log(sum)); } diff --git a/src/main/java/species/Survive.java b/src/main/java/species/Survive.java index 1b3149314c1893e22bd95c8a28228ed7d08c386f..2b6fc5a4371e39f57704cd373efcb7aaffa49dbd 100644 --- a/src/main/java/species/Survive.java +++ b/src/main/java/species/Survive.java @@ -33,44 +33,44 @@ public class Survive extends AquaNismsGroupProcess<DiadromousFish, DiadromousFis @Override public void doProcess(DiadromousFishGroup group) { - // TODO Auto-generated method stub - double survivalProbability; + + double survivalProbability=1.; List<DiadromousFish> deadFish = new ArrayList<DiadromousFish>(); long survivalAmount; for(Basin basin : group.getEnvironment().getBasins()){ - if (basin.getFishs(group)!=null) for(DiadromousFish fish : basin.getFishs(group)){ - survivalProbability = 1.; - //Survive - if(fish.getPosition().getType() == TypeBassin.RIVER && fish.isMature()){ - double tempEffectSurv = Miscellaneous.temperatureEffect(fish.getPosition().getCurrentTemperature(group.getPilot()), tempMinMortGenInRiv, tempOptMortGenInRiv, tempMaxMortGenInRiv); - if (tempEffectSurv == 0.){ - survivalProbability = 0.; - //System.out.println("le poisson situé dans le bassin " + fish.getPosition().getName() + " en " + Time.getSeason() +" a un coeff de mortalité de " + fish.getMortalityRateInRiver() + " mais à cause de la température une prob de survie de " + survivalProbability); - }else{ - survivalProbability = survivalProbOptGenInRiv * tempEffectSurv; - //System.out.println("le poisson situé dans le bassin " + fish.getPosition().getName() + " en " + Time.getSeason() + " a un coeff de mortalité de " + fish.getMortalityRateInRiver() + " et donc une prob de survie de " + survivalProbability); - } - }else if (fish.getPosition().getType() == TypeBassin.SEA){ - survivalProbability = Math.exp(-mortalityRateInSea * Time.getSeasonDuration()); - //System.out.println("le poisson situé dans le bassin " + fish.getPosition().getName() + " en " + Time.getSeason() + " a un coeff de mortalité de " + fish.getMortalityRateInSea() + " et donc une prob de survie de " + survivalProbability); - }else if (fish.getPosition().getType() == TypeBassin.OFFSHORE){ - survivalProbability = Math.exp(-mortalityRateInOffshore * Time.getSeasonDuration()); - //System.out.println("le poisson situé dans le bassin " + fish.getPosition().getName() + " en " + Time.getSeason() + " a un coeff de mortalité de " + fish.getMortalityRateInOffshore() + " et donc une prob de survie de " + survivalProbability); - }else{ + if (basin.getFishs(group)!=null) for(DiadromousFish fish : basin.getFishs(group)){ survivalProbability = 1.; - } + //Survive + if(fish.getPosition().getType() == TypeBassin.RIVER && fish.isMature()){ + double tempEffectSurv = Miscellaneous.temperatureEffect(fish.getPosition().getCurrentTemperature(group.getPilot()), tempMinMortGenInRiv, tempOptMortGenInRiv, tempMaxMortGenInRiv); + if (tempEffectSurv == 0.){ + survivalProbability = 0.; + //System.out.println("le poisson situ� dans le bassin " + fish.getPosition().getName() + " en " + Time.getSeason() +" a un coeff de mortalit� de " + fish.getMortalityRateInRiver() + " mais � cause de la temp�rature une prob de survie de " + survivalProbability); + }else{ + survivalProbability = survivalProbOptGenInRiv * tempEffectSurv; + //System.out.println("le poisson situ� dans le bassin " + fish.getPosition().getName() + " en " + Time.getSeason() + " a un coeff de mortalit� de " + fish.getMortalityRateInRiver() + " et donc une prob de survie de " + survivalProbability); + } + }else if (fish.getPosition().getType() == TypeBassin.SEA){ + survivalProbability = Math.exp(-mortalityRateInSea * Time.getSeasonDuration()); + //System.out.println("le poisson situ� dans le bassin " + fish.getPosition().getName() + " en " + Time.getSeason() + " a un coeff de mortalit� de " + fish.getMortalityRateInSea() + " et donc une prob de survie de " + survivalProbability); + }else if (fish.getPosition().getType() == TypeBassin.OFFSHORE){ + survivalProbability = Math.exp(-mortalityRateInOffshore * Time.getSeasonDuration()); + //System.out.println("le poisson situ� dans le bassin " + fish.getPosition().getName() + " en " + Time.getSeason() + " a un coeff de mortalit� de " + fish.getMortalityRateInOffshore() + " et donc une prob de survie de " + survivalProbability); + }else{ + survivalProbability = 1.; + } - if (survivalProbability<1.){ - survivalAmount = Miscellaneous.binomialForSuperIndividual(group.getPilot(), fish.getAmount(), survivalProbability); + if (survivalProbability<1.){ + survivalAmount = Miscellaneous.binomialForSuperIndividual(group.getPilot(), fish.getAmount(), survivalProbability); - if (survivalAmount > 0) - fish.setAmount(survivalAmount); - else - deadFish.add(fish); + if (survivalAmount > 0) + fish.setAmount(survivalAmount); + else + deadFish.add(fish); + } } - } - } + } for (DiadromousFish fish : deadFish){ group.removeAquaNism(fish);