5b168b63 by Nathan Lighthart

Merge branch 'release/0.2.0'

2 parents 2aaf8ad9 14333aad
......@@ -11,3 +11,5 @@ nbactions.xml
output/
reg_*.csv
*.zip
MANIFEST.MF
manifest.mf
......
......@@ -7,9 +7,9 @@
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="AgES-W" default="default" basedir=".">
<project name="AgES" default="default" basedir=".">
<description>Builds, tests, and runs the project AgES-W.</description>
<import file="nbproject/build-impl.xml"/>
<import file="nbproject/build-impl.xml" as="netbeans" />
<!--
There exist several targets which are by default empty and which can be
......@@ -71,6 +71,9 @@
-->
<property file=".oms/project.properties"/>
<!-- Environment properties -->
<property environment="env" />
<!-- Directory properties -->
<property name="src.dir" value="src"/>
......@@ -79,7 +82,18 @@
<property name="build.dir" value="build"/>
<property name="obj.dir" value="${build.dir}/obj"/>
<property name="gensrc.dir" value="${build.dir}/generated-sources/oms"/>
<property name="proj.dir" value="projects"/>
<property name="proj.dir" value="projects"/>
<!-- Version properties -->
<property name="project.name" value="AgES" />
<property name="implementation.name" value="ages" />
<property name="vendor.name" value="USDA/CSU" />
<tstamp>
<format property="NOW" pattern="yyyy-MM-dd HH:mm:ss z" />
</tstamp>
<property file="build_info.properties" />
<property name="build.version" value="${build.major.number}.${build.minor.number}.${build.patch.number}" />
<!-- NAP properties -->
<property name="fortran.files" value="**/*.f90, **/*.for, **/*.f"/>
......@@ -87,10 +101,34 @@
<property name="cpp.files" value="**/*.cpp, **/*.cpp, **/*.c++, **/*.C"/>
<property name="nl.files" value="**/*.nlogo"/>
<!--<property name="nap.skip" value=""/>-->
<property name="nap.skip" value="false"/>
<property name="nap.gen.logging" value="false"/>
<property name="nap.gen.singleton" value="false"/>
<property name="nap.gen.protected" value="false"/>
<!-- Fortran compilation properties -->
<property name="fortran.compile.flag" value="true" />
<target name="increment-patch" description="increments patch number">
<propertyfile file="build_info.properties">
<entry key="build.patch.number" type="int" operation="+" value="1" />
</propertyfile>
</target>
<target name="increment-minor" description="increments minor version">
<propertyfile file="build_info.properties">
<entry key="build.minor.number" type="int" operation="+" value="1"/>
<entry key="build.patch.number" type="int" value="0"/>
</propertyfile>
</target>
<target name="increment-major" description="increments major version">
<propertyfile file="build_info.properties">
<entry key="build.major.number" type="int" operation="+" value="1"/>
<entry key="build.minor.number" type="int" value="0"/>
<entry key="build.patch.number" type="int" value="0"/>
</propertyfile>
</target>
<path id="oms-cp" >
<fileset dir="${lib.dir}" erroronmissingdir="false">
......@@ -101,7 +139,7 @@
<taskdef name="nap" classname="oms3.nap.JNAComponentTask" classpathref="oms-cp" />
<taskdef name="cc" classname="net.sf.antcontrib.cpptasks.CCTask" classpathref="oms-cp" />
<target name="nap" depends="init" unless="nap.skip" description="Perform native annotation processing (NAP)">
<target name="nap" depends="init" unless="${nap.skip}" description="Perform native annotation processing (NAP)">
<nap destdir="${gensrc.dir}" dllName="upgm"
genlogging="${nap.gen.logging}"
gensingleton="${nap.gen.singleton}"
......@@ -109,13 +147,45 @@
<fileset dir="${src.dir}" includes="${fortran.files}"/>
</nap>
</target>
<target name="fortran-compiler-exists">
<condition property="fortran.compiler.exists">
<or>
<available file="gfortran.exe" filepath="${env.Path}" />
<available file="gfortran" filepath="${env.Path}" />
<available file="gfortran.exe" filepath="${env.PATH}" />
<available file="gfortran" filepath="${env.PATH}" />
</or>
</condition>
</target>
<target name="should-compile-fortran" depends="fortran-compiler-exists">
<condition property="should.compile.fortran">
<and>
<istrue value="${fortran.compile.flag}" />
<istrue value="${fortran.compiler.exists}" />
</and>
</condition>
</target>
<target name="compile-fortran" depends="init" description="Compile UPGM Fortran">
<target name="compile-fortran" depends="init, should-compile-fortran"
if="${should.compile.fortran}" description="Compile UPGM Fortran">
<cc name="gfortran" outtype="shared" subsystem="console" outfile="${dist.dir}/upgm" objdir="${obj.dir}">
<fileset dir="${src.dir}" includes="${fortran.files}"/>
<linker name="gfortran"/>
</cc>
</target>
<target name="-pre-init" description="actions that need to happen before project properties are initialized">
<manifest file="MANIFEST.MF">
<attribute name="Specification-Title" value="${project.name}" />
<attribute name="Specification-Version" value="${build.version}" />
<attribute name="Specification-Vendor" value="${vendor.name}" />
<attribute name="Implementation-Title" value="${implementation.name}" />
<attribute name="Implementation-Version" value="${build.version}" />
<attribute name="Implementation-Vendor" value="${vendor.name}" />
</manifest>
</target>
<target name="-post-init">
<mkdir dir="${obj.dir}"/>
......@@ -123,10 +193,16 @@
</target>
<target name="-pre-compile" depends="nap">
<manifest file="MANIFEST.MF" mode="update">
<attribute name="Build-Time" value="${NOW}" />
</manifest>
</target>
<target name="-post-jar" depends="compile-fortran">
</target>
<target name="run" depends="jar, netbeans.run" description="Run hook to force jar creation when running">
</target>
<target name="zip-all-projects">
<delete file="${proj.dir}/projects.zip" quiet="true" />
......
#Tue, 18 Apr 2017 12:31:35 -0600
build.major.number=0
build.minor.number=2
build.patch.number=0
No preview for this file type
# Ignore everything in this directory
*
# Except this file
!.gitignore
# Ignore all sub-directories
**/
......@@ -988,6 +988,7 @@ public class AgESModel {
last = now;
}
temporalContext.put("time", time);
readerCO2.readData();
readerCO2.setValue(temporalContext);
if (temporalReader != null) {
......
......@@ -184,6 +184,10 @@ public class PotentialCropGrowthAdapter extends AnnotatedAdapter {
@Optional
@Input @Output public double BioYield;
@Description("the daily atmospheric level of CO2")
@Units("ppm")
@Input public double co2;
@Description("Amount N Added to Residue Pool After Harvesting")
@Units("kgN/ha")
@Output public double Addresidue_pooln;
......@@ -210,6 +214,9 @@ public class PotentialCropGrowthAdapter extends AnnotatedAdapter {
@Description("DLAI (Senescence)")
@Output public double dlai;
@Description("Co2Effect")
@Output public double co2effect;
private Map<HRU, PotentialCropGrowthSWAT> swatComponentMap = new ConcurrentHashMap<>();
@Override
......@@ -230,7 +237,9 @@ public class PotentialCropGrowthAdapter extends AnnotatedAdapter {
private void executeSWAT() {
PotentialCropGrowthSWAT component = swatComponentMap.get(hru);
if (component == null) {
//component = new PotentialCropGrowthSWAT();
component = new PotentialCropGrowthSWAT();
swatComponentMap.put(hru, component);
}
......@@ -288,6 +297,9 @@ public class PotentialCropGrowthAdapter extends AnnotatedAdapter {
component.FPHUact = FPHUact;
component.nfert = nfert;
// co2
component.co2 = co2;
component.execute();
plantStateReset = component.plantStateReset;
......@@ -316,6 +328,7 @@ public class PotentialCropGrowthAdapter extends AnnotatedAdapter {
topt = component.topt;
fr3N = component.fr3N;
dlai = component.dlai;
co2effect = component.co2eff;
}
private void executeUPGM() {
......
......@@ -21,6 +21,9 @@
package crop;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
public class PotentialCropGrowthSWAT {
......@@ -88,6 +91,20 @@ public class PotentialCropGrowthSWAT {
public double fracharvestn;
private double LAI_delta;
private static final boolean DO_CO2_BIOMASS = false;
// For co2 response.
public double co2;
public double co2eff;
// Assuming hardcoded values for initial testing will be ok. Eventually this could be user input.
// c4 crops
private static final List<Double> CO2_X_C4CROPS = Arrays.asList(0.0, 220.0, 280.0, 330.0, 400.0, 490.0, 570.0, 750.0, 990.0, 9999.0);
private static final List<Double> CO2_Y_C4CROPS = Arrays.asList(0.00, 0.85, 0.95, 1.00, 1.02, 1.04, 1.05, 1.06, 1.07, 1.08);
// c5 crops
private static final List<Double> CO2_X_C3CROPS = Arrays.asList(0.0, 220.0, 330.0, 440.0, 550.0, 660.0, 770.0, 880.0, 990.0, 9999.0);
private static final List<Double> CO2_Y_C3CROPS = Arrays.asList(0.00, 0.71, 1.00, 1.08, 1.17, 1.25, 1.32, 1.38, 1.43, 1.50);
public void execute() {
BioYield = 0;
......@@ -103,7 +120,12 @@ public class PotentialCropGrowthSWAT {
calc_phu();
calc_lai();
calc_biomass();
if (DO_CO2_BIOMASS) {
calc_co2_biomass();
} else {
co2eff = 1.0;
calc_biomass();
}
CanHeightAct = calc_canopy();
calc_root();
calc_nuptake();
......@@ -207,6 +229,43 @@ public class PotentialCropGrowthSWAT {
BioOpt_delta = (dormancy) ? 0 : BioOpt_delta;
}
private void calc_co2_biomass() {
co2eff = 1.0; // default = no impact.
int indexLess = 0;
int indexPlusOne = 0;
if (idc == 4) {
// c4 crops (?maybe?)
// either exact position of co2 value, or pos - 1 in array.
int indx = Collections.binarySearch(CO2_X_C4CROPS, co2);
if (indx < 0) {
indexLess = Math.abs(indx) - 2;
indexPlusOne = Math.abs(indx) - 1;
} else {
indexLess = indx;
indexPlusOne = Math.abs(indx) + 1;
}
co2eff = (co2 - CO2_X_C4CROPS.get(indexLess)) * (CO2_Y_C4CROPS.get(indexPlusOne) - CO2_Y_C4CROPS.get(indexLess))
/ (CO2_X_C4CROPS.get(indexPlusOne) - CO2_X_C4CROPS.get(indexLess)) + CO2_Y_C4CROPS.get(indexLess);
} else {
// either exact position of co2 value, or pos - 1 in array.
int indx = Collections.binarySearch(CO2_X_C3CROPS, co2);
if (indx < 0) {
indexLess = Math.abs(indx) - 2;
indexPlusOne = Math.abs(indx) - 1;
} else {
indexLess = indx;
indexPlusOne = Math.abs(indx) + 1;
}
co2eff = (co2 - CO2_X_C3CROPS.get(indexLess)) * (CO2_Y_C3CROPS.get(indexPlusOne) - CO2_Y_C3CROPS.get(indexLess))
/ (CO2_X_C3CROPS.get(indexPlusOne) - CO2_X_C3CROPS.get(indexLess)) + CO2_Y_C3CROPS.get(indexLess);
}
double Hphosyn = 0.5 * solRad * (1 - Math.exp(LExCoef * LAI)) * co2eff; // intercepted photosynthetically active radiation (MJ/m^2)
BioOpt_delta = rue * Hphosyn;
BioOpt_delta = (dormancy) ? 0 : BioOpt_delta;
}
// canopy cover
// canopy cover is expressed as a function of LAI
private double calc_canopy() {
......
......@@ -27,7 +27,8 @@ import java.io.IOException;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAccessor;
import java.util.Arrays;
import java.util.Iterator;
......@@ -42,9 +43,12 @@ public class CO2ClimateReader implements ClimateReader {
private Iterator<String[]> rows;
private DateTimeFormatter dateFormatter;
private double co2;
private double missingDataValue;
private LocalDate time;
private double co2;
private RowData nextUpdate;
public CO2ClimateReader(Path dataFilePath, double defaultCO2, LocalDate startTime, LocalDate endTime) {
this.dataFilePath = dataFilePath;
this.defaultCO2 = defaultCO2;
......@@ -61,23 +65,33 @@ public class CO2ClimateReader implements ClimateReader {
if (alwaysDefault) {
return;
}
try {
readData0();
} catch (Exception ex) {
throw new IOException("Error reading co2 file: " + dataFilePath, ex);
}
}
private void readData0() throws Exception {
// Initialize if not intialized otherwise update the time to the next day
if (rows == null) {
init();
time = startTime;
} else {
time = time.plusDays(1L);
}
String[] row = rows.next();
if (row.length < 3) {
throw new IOException("Malformed data line: " + Arrays.toString(row));
} else {
try {
co2 = Double.parseDouble(row[2]);
} catch (NumberFormatException ex) {
throw new IOException("Malformed data line: " + Arrays.toString(row), ex);
}
// if nextUpdate is null then there is no more data to read
// when there is no more data to read co2 should stay as the last known value
if (nextUpdate == null) {
return; // no more data to read so keep using last known value
}
if (Double.compare(co2, missingDataValue) == 0) {
co2 = defaultCO2;
// If nextUpdate.time >= time then update co2 and read next value
if (!time.isBefore(nextUpdate.time)) {
updateCO2(nextUpdate.co2);
nextUpdate = readNextRow();
}
}
......@@ -117,7 +131,7 @@ public class CO2ClimateReader implements ClimateReader {
if (missingDataValueString == null) {
missingDataValueString = table.getInfo().get("missing_val");
if (missingDataValueString == null) {
throw new IOException("Missing data value cannot be found");
missingDataValueString = "NaN";
}
}
missingDataValue = Double.parseDouble(missingDataValueString);
......@@ -128,17 +142,88 @@ public class CO2ClimateReader implements ClimateReader {
throw new IOException("Missing start/end time in " + dataFilePath);
}
LocalDate tableStartTime = LocalDate.parse(tableStartTimeString, dateFormatter);
LocalDate tableEndTime = LocalDate.parse(tableEndTimeString, dateFormatter);
if (startTime.isBefore(tableStartTime) || endTime.isAfter(tableEndTime) || tableEndTime.isBefore(tableStartTime)) {
throw new IOException("Illegal start/end in " + dataFilePath + " "
+ dateFormatter.format(startTime) + " - " + dateFormatter.format(endTime));
// Parse table start and end time
LocalDate tableStartTime;
LocalDate tableEndTime;
try {
tableStartTime = parseDate(tableStartTimeString);
} catch (DateTimeParseException ex) {
throw new IOException("Error parsing table start time: " + tableStartTimeString, ex);
}
try {
tableEndTime = parseDate(tableEndTimeString);
} catch (DateTimeParseException ex) {
throw new IOException("Error parsing table end time: " + tableEndTimeString, ex);
}
// validate that table end time is not before the table start time
// It is valid for tableEndTime >= tableStartTime
if (tableEndTime.isBefore(tableStartTime)) {
throw new IOException("Invalid co2 table time range: "
+ formatDate(tableStartTime) + " - " + formatDate(tableEndTime));
}
// validate table times are within simulation times
if (startTime.isBefore(tableStartTime)) {
System.out.println("WARNING: Simulation start time is before the start time of the co2 file. The default CO2 value of " + defaultCO2 + " will be used.");
}
// read co2 values until end of dates or until start time is found
co2 = defaultCO2;
while (true) {
nextUpdate = readNextRow();
if (nextUpdate == null) {
break;
} else if (nextUpdate.time.isAfter(startTime)) {
break;
} else {
updateCO2(nextUpdate.co2);
}
}
}
private RowData readNextRow() throws IOException {
if (!rows.hasNext()) {
return null;
}
String[] row = rows.next();
try {
return readNextRow0(row);
} catch (Exception ex) {
throw new IOException("Malformed data line: " + Arrays.toString(row), ex);
}
}
private RowData readNextRow0(String[] row) {
LocalDate timeValue = parseDate(row[1]);
double co2Value = Double.parseDouble(row[2]);
return new RowData(timeValue, co2Value);
}
private LocalDate parseDate(String dateString) throws DateTimeParseException {
return dateFormatter.parse(dateString, LocalDate::from);
}
private String formatDate(TemporalAccessor temporal) {
return dateFormatter.format(temporal);
}
private void updateCO2(double co2Value) {
// if new co2 value is missing value then leave as the last know value
if (Double.compare(co2Value, missingDataValue) == 0) {
return;
}
co2 = co2Value;
}
private class RowData {
public final LocalDate time;
public final double co2;
long daysUntilStart = tableStartTime.until(startTime, ChronoUnit.DAYS);
while (daysUntilStart > 0) {
rows.next();
--daysUntilStart;
public RowData(LocalDate time, double co2) {
this.time = time;
this.co2 = co2;
}
}
}
......
/*
* This file is part of the AgroEcoSystem-Watershed (AgES-W) model component
* collection. AgES-W components are derived from multiple agroecosystem models
* including J2K and J2K-SN (FSU-Jena, DGHM, Germany), SWAT (USDA-ARS, USA),
* WEPP (USDA-ARS, USA), RZWQM2 (USDA-ARS, USA), and others.
*
* The AgES-W model is free software; you can redistribute the model and/or
* modify the components 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 potet;
import lib.Climate;
public class PenmanMonteithCO2TransRatio {
private static final double CP = 1.031E-3;
private static final double RSS = 150;
public String tempRes;
public double wind;
public double tmean;
public double rhum;
public double netRad;
public double actRsc0;
public double elevation;
public double area;
public double LAI;
public double actEffH;
public int idc;
public double co2;
public double potET;
public double actET;
public void execute() {
double tempFactor = 0;
if ("d".equals(tempRes)) {
tempFactor = 86400;
} else if ("h".equals(tempRes)) {
tempFactor = 3600;
}
double abs_temp = Climate.absTemp(tmean, "C");
double delta_s = Climate.slopeOfSaturationPressureCurve(tmean);
double pz = Climate.atmosphericPressure(elevation, abs_temp);
double est = Climate.saturationVapourPressure(tmean);
double ea = Climate.vapourPressure(rhum, est);
double latH = Climate.latentHeatOfVaporization(tmean);
double psy = Climate.psyConst(pz, latH);
double G = 0.1 * netRad;
double vT = Climate.virtualTemperature(abs_temp, pz, ea);
double pa = Climate.airDensityAtConstantPressure(vT, pz);
double Letp = calcETAllen(delta_s, netRad, G, pa, CP, est, ea, calcRa(actEffH, wind), calcRs(LAI, actRsc0, RSS),
psy, tempFactor, calcStomatalRatio(idc, co2, LAI));
potET = Letp / latH;
// convert mm to l
potET *= area;
// negative potET is not allowed
if (potET < 0) {
potET = 0;
}
actET = 0; // reset actET
}
private static double calcETAllen(double ds, double netRad, double G, double pa,
double CP, double est, double ea, double ra, double rs, double psy, double tempFactor, double stomatalRatio) {
return (ds * (netRad - G) + ((pa * CP * (est - ea) / ra) * tempFactor)) / (ds + psy * (1 + (rs / ra * stomatalRatio)));
}
private static double calcRa(double eff_height, double wind_speed) {
double ra;
if (wind_speed <= 0) {
wind_speed = 0.5;
}
if (eff_height < 10) {
ra = (9.5 / wind_speed) * Math.pow(Math.log(2 / (0.1 * eff_height)), 2);
} else {
ra = 20 / (0.1681 * wind_speed);
}
return ra;
}
private static double calcRs(double LAI, double rsc, double rss) {
double A = Math.pow(0.7, LAI);
return 1. / (((1 - A) / rsc) + ((A / rss)));
}
private static double calcStomatalRatio(int idc, double co2, double LAI) {
/*
Programmed using the approach outlined in the DSSAT-CSM 4.6 source file TRANS.FOR.
This approach was adapted for use with the PenmanMonteith PET calculation.
*/
// if there is no LAI, no plant, so no change
if (LAI < 0.01) {
return 1.0;
}
double rb = 10.0;
double rlf = 0.0;
double rlfc = 0.0;
/* DSSAT-CSM 4.6 Comments on following code:
!-----------------------------------------------------------------------
! RLF = Leaf stomatal resistance at 330.0 ppm CO2, s/m
! RLFC = Leaf stomatal resistance at other CO2 conc., s/m
! (Allen, 1986), Plant responses to rising CO2.
! CO2 = CO2 Conc of the increased ATM case
! CO2 = 330 Ambient CO2
!-----------------------------------------------------------------------
*/
// "IF (INDEX('MZ,ML,SG,SC,SW,BM,BH,BR,NP,SI',CROP) .GT. 0) THEN"
// Note: maize/corn/millet/sorghum seem to fall under IDC 4,
// I am not sure if the other crops listed as c-4 crops fall in this range too.
if (idc == 4) {
// c4 crops
// DSSAT-CSM 4.6-> "EQ 7 from Allen (1986) for corn."
rlf = (1.0 / (0.0328 - (5.49 * 10E-5 * 330.0) + (2.95E-8 * Math.pow(330.0, 2)))) + rb;
rlfc = (1.0 / (0.0328 - (5.49 * 10E-5 * co2) + (2.95E-8 * Math.pow(co2, 2)))) + rb;
} else {
// c3 crops
rlf = 9.72 + (0.0757 * 330.0) + rb;
rlfc = 9.72 + (0.0757 * co2) + rb;
}
// DSSAT-CSM assumes 2.88 for the reference crop LAI:
//" FAO-56 assumption of 2.88 LAI reference"
rlf = rlf / (0.5 * 2.88);
rlfc = rlfc / (0.5 * 2.88);
return rlfc / rlf;
}
}
/*
* This file is part of the AgroEcoSystem-Watershed (AgES-W) model component
* collection. AgES-W components are derived from multiple agroecosystem models
* including J2K and J2K-SN (FSU-Jena, DGHM, Germany), SWAT (USDA-ARS, USA),
* WEPP (USDA-ARS, USA), RZWQM2 (USDA-ARS, USA), and others.
*
* The AgES-W model is free software; you can redistribute the model and/or
* modify the components 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 potet;
import ages.types.HRU;
import annotations.Author;
import annotations.Bibliography;
import annotations.Documentation;
import annotations.Execute;
import annotations.Keywords;
import annotations.License;
import annotations.Role;
import static annotations.Role.PARAMETER;
import annotations.SourceInfo;
import annotations.Status;
import annotations.VersionInfo;
import crop.Crop;
import gov.usda.jcf.annotations.Description;
import gov.usda.jcf.annotations.Input;
import gov.usda.jcf.annotations.Output;
import gov.usda.jcf.annotations.Units;
import gov.usda.jcf.core.Context;
import gov.usda.jcf.core.adapters.AnnotatedAdapter;
@Description("PenmanMonteith PET calculation with CO2 impact through stomatal conductance ratio")
@Author(name = "Olaf David, Manfred Fink, James C. Ascough II", contact = "jim.ascough@ars.usda.gov")
@Keywords("Insert keywords")
@Bibliography("Insert bibliography here")
@VersionInfo("$ID:$")
// Nathan, do we need to change this?
@SourceInfo("http://javaforge.com/scm/file/3979484/default/src/potet/PenmanMonteith.java")
@License("http://www.gnu.org/licenses/gpl.html")
@Status(Status.TESTED)
@Documentation("src/potet/PenmanMonteith.xml")
public class PenmanMonteithCO2TransRatioAdapter extends AnnotatedAdapter {
@Description("daily or hourly time steps [d|h]")
@Units("d | h")
@Role(PARAMETER)
@Input public String tempRes;
@Description("wind")
@Input public double wind;
@Description("Mean Temperature")
@Units("C")
@Input public double tmean;
@Description("Relative Humidity")
@Input public double rhum;
@Description("Daily net radiation")
@Units("MJ/m2")
@Input public double netRad;
@Description("state variable rsc0")
@Input public double actRsc0;
@Description("HRU")
@Input public HRU hru;
@Description("LAI")
@Input public double LAI;
@Description("effective height")
@Input public double actEffH;
@Description("crop")
@Input public Crop crop;
@Description("the daily atmospheric level of CO2")
@Units("ppm")
@Input public double co2;
@Description("HRU potential Evapotranspiration")
@Units("mm")
@Output public double potET;
@Description("HRU actual Evapotranspiration")
@Units("mm")
@Output public double actET;
@Override
protected void run(Context context) {
PenmanMonteithCO2TransRatio component = new PenmanMonteithCO2TransRatio();
component.tempRes = tempRes;
component.wind = wind;
component.tmean = tmean;
component.rhum = rhum;
component.netRad = netRad;
component.actRsc0 = actRsc0;
component.elevation = hru.elevation;
component.area = hru.area;
component.LAI = LAI;
component.actEffH = actEffH;
// required for co2 impact
component.idc = crop.idc;
component.co2 = co2;
component.execute();
potET = component.potET;
actET = component.actET;
}
/**
* OMS execute statement for testing before JCF
*/
@Execute
public void execute() {
run(null);
}
}
......@@ -29,6 +29,7 @@ import annotations.Status;
import annotations.Author;
import annotations.Documentation;
import annotations.Keywords;
import com.sun.jna.ptr.IntByReference;
import gov.usda.jcf.annotations.Input;
import gov.usda.jcf.annotations.Description;
......@@ -52,6 +53,9 @@ public class JupgmInitGen {
@Input public String upgmmgmtfile;
@Description("Upgm_mgmt.dat file")
@Input public String upgmsoilfile;
@Description("Upgm_mgmt.dat file")
@Input public String canopyhtoutfile;
@Description("Upgm_mgmt.dat file")
......@@ -75,13 +79,19 @@ public class JupgmInitGen {
@Description("Upgm_mgmt.dat file")
@Input public String shootoutfile;
@Description("HRU ID")
@Input
public int hruid;
public nap.Libupgm lib;
public void exec() throws Exception {
lib.jupgminit_(
new IntByReference(hruid),
cropxmlfile, cropxmlfile.length(),
upgmcropfile, upgmcropfile.length(),
upgmmgmtfile, upgmmgmtfile.length(),
upgmsoilfile, upgmsoilfile.length(),
canopyhtoutfile, canopyhtoutfile.length(),
cdbugoutfile, cdbugoutfile.length(),
cropoutfile, cropoutfile.length(),
......
......@@ -21,6 +21,7 @@
package upgm;
import ages.types.SoilType;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import crop.Crop;
......@@ -32,15 +33,12 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Upgm {
private static double acycon = 10000.0;
private static final Path tempLibDir;
private static final Lock initLock = new ReentrantLock();
static {
Path tempDir;
......@@ -60,6 +58,7 @@ public class Upgm {
public double co2;
public int hruID;
public Crop crop;
public SoilType soil;
public boolean plantExisting;
public boolean doHarvest;
public double tmin;
......@@ -164,9 +163,13 @@ public class Upgm {
Path upgmMgmt = outParent.resolve("Upgm_mgmt" + idString + ".dat");
writeUpgmManagement(upgmMgmt);
Path upgmSoil = outParent.resolve("upgm_soil_profile" + idString + ".dat");
writeUpgmSoil(upgmSoil);
Jupgminit.cropxmlfile = cropXML.toString();
Jupgminit.upgmcropfile = upgmCrop.toString();
Jupgminit.upgmmgmtfile = upgmMgmt.toString();
Jupgminit.upgmsoilfile = upgmSoil.toString();
Jupgminit.canopyhtoutfile = outParent.resolve("canopyht" + idString + ".out").toString();
Jupgminit.cdbugoutfile = outParent.resolve("cdbug" + idString + ".out").toString();
......@@ -176,15 +179,12 @@ public class Upgm {
Jupgminit.phenoloutfile = outParent.resolve("phenol" + idString + ".out").toString();
Jupgminit.seasonoutfile = outParent.resolve("season" + idString + ".out").toString();
Jupgminit.shootoutfile = outParent.resolve("shoot" + idString + ".out").toString();
Jupgminit.hruid = hruID;
initLock.lock();
try {
Jupgminit.exec();
} catch (Exception ex) {
Logger.getLogger(Upgm.class.getName()).log(Level.SEVERE, null, ex);