DSSATData.java [src/java/d/dataNodes] Revision: default Date:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package d.dataNodes;
import d.util.RangeMap;
import d.util.SOLbuilder;
import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import soils.Component;
import soils.Horizon;
import soils.db.tables.TableHorizon;
import soils.db.tables.TableHorizonCalculations;
import soils.utils.SoilUtils;
/**
*
* @author sidereus
*/
public class DSSATData {
DecimalFormat df1 = new DecimalFormat("#.###");
private static String SLASH = "/";
// Romero, C. C., Hoogenboom, G., Baigorria, G. A., Koo, J., Gijsman, A. J., & Wood, S. (2012).
// Reanalysis of a global soil database for crop and environmental modeling.
// Environmental Modelling & Software, 35, 163-170.
// Tab 4, columns Hydrological Group and Runoff curve number (at different slope angles)
private final Map<String, RangeMap<Double, Integer>> table_runoffCurveNumber = new HashMap() {
{
put("A", new RangeMap() {
{
// slope angle start, slope angle end, runoff curve number value
put(0d, 2d, 61);
put(2d, 5d, 64);
put(5d, 10d, 68);
put(10d, 100d, 71);
}
});
put("B", new RangeMap() {
{
put(0d, 2d, 73);
put(2d, 5d, 76);
put(5d, 10d, 80);
put(10d, 100d, 83);
}
});
put("C", new RangeMap() {
{
put(0d, 2d, 81);
put(2d, 5d, 84);
put(5d, 10d, 88);
put(10d, 100d, 91);
}
});
put("D", new RangeMap() {
{
put(0d, 2d, 84);
put(2d, 5d, 87);
put(5d, 10d, 91);
put(10d, 100d, 94);
}
});
}
};
public void executeComputation(Component comp, String fileName, String id_soil, double longitude, double latitude) {
List<String> firstSet = new ArrayList();
List<String> secondSet = new ArrayList();
double salb = albedo(comp);
double slu1 = evaporationLimit(comp);
double sldr = drainageRate(comp);
double slro = runoffCurveNumber(comp);
double slnf = 1.0;
double slpf = 1.0;
String smhb = "IB001";
String smpx = "IB001";
String smke = "IB001";
String scom = "-99"; // Color, moist, Munsell hue
horizons(comp, firstSet, secondSet);
SOLbuilder fileBuilder = new SOLbuilder();
fileBuilder.getSolFile(fileName,
"USA", id_soil, latitude, longitude, "-99",
scom, salb, slu1, sldr, slro, slnf, slpf, smhb, smpx, smke,
firstSet.iterator(), secondSet.iterator());
}
private double albedo(Component comp) {
double salb;
if (Double.isNaN(comp.albedodry_r())) {
comp.albedodry_r(SoilUtils.averageMissingValue(comp.albedodry_h(),
comp.albedodry_l(),
comp.albedodry_r()));
}
if (Double.isNaN(comp.albedodry_r())) {
comp.albedodry_r(-99d);
}
salb = comp.albedodry_r();
if (salb < 0.09 && salb > 0.17) {
String msg = "Albedo value ranges from 0.09 for a black soil"
+ " to 0.17 for a yellow soil. Current value is: " + salb;
throw new IllegalArgumentException(msg);
}
return salb;
}
// modified (upper limit 12) from https://github.com/ldemaz/rcropmod to adhere to
// Romero, C. C., Hoogenboom, G., Baigorria, G. A., Koo, J., Gijsman, A. J., & Wood, S. (2012).
// Reanalysis of a global soil database for crop and environmental modeling.
// Environmental Modelling & Software, 35, 163-170.
private double evaporationLimit(Component comp) {
double slu1 = Double.NaN;
for (Map.Entry<String, Horizon> horizon : comp.horizons.entrySet()) {
TableHorizon h = horizon.getValue().getTableHorizon();
computeAverageMissingValue(h);
double clay = h.claytotal_r();
slu1 = 5 + 0.15 * (100 - (98 - clay));
if (slu1 > 12) {
slu1 = 12;
}
break;
}
return slu1;
}
private double drainageRate(Component comp) {
return parseDrainClass(comp.getTableComponent().drainagecl());
}
private double parseDrainClass(String drainClass) {
String actualClass = drainClass.trim().toLowerCase().replace(" ", "");
switch (actualClass) {
case "verypoorlydrained":
return 0.01;
case "poorlydrained":
return 0.05;
case "somewhatpoorlydrained":
return 0.25;
case "moderatelywelldrained":
return 0.40;
case "welldrained":
return 0.60;
case "somewhatexcessivelydrained":
return 0.75;
case "excessivelydrained":
return 0.85;
default:
throw new IllegalArgumentException();
}
}
// if still NAN exit program
private double runoffCurveNumber(Component comp) {
if (Double.isNaN(comp.slope_r())) {
comp.slope_r(SoilUtils.averageMissingValue(comp.slope_h(), comp.slope_l(), comp.slope_r()));
}
if (Double.isNaN(comp.slope_r())) {
throw new IllegalArgumentException();
}
double slope = comp.slope_r();
String hd = comp.hydgrp();
// if soils in dual groups (A/D, B/D, C/D) get first soil type (drained condition)
if (hd.contains(SLASH)) {
hd = hd.split(SLASH)[0];
}
return table_runoffCurveNumber.get(hd).get(slope);
}
private void horizons(Component comp, List<String> firstSet, List<String> secondSet) {
double baseLayer_depth = 0;
for (Map.Entry<String, Horizon> horizon : comp.horizons.entrySet()) {
TableHorizon th = horizon.getValue().getTableHorizon();
TableHorizonCalculations cth = horizon.getValue().getTableHorizonCalculations();
computeAverageMissingValue(th);
double clayPerc = th.claytotal_r();
double siltPerc = th.silttotal_r();
double organic_matterPerc = th.om_r();
double bulkDensity = th.dbthirdbar_r();
if (!isMandatorysSoilPropertiesValid(clayPerc, siltPerc, organic_matterPerc, bulkDensity)) {
break;
}
// depth, base of layer [cm]
double slb = baseLayer_depth + th.hzdepb_r();
firstSet.add(firstDataSet(th, cth, clayPerc, siltPerc, organic_matterPerc, slb, bulkDensity, baseLayer_depth));
secondSet.add(secondDataSet(th, slb));
baseLayer_depth = slb;
}
}
private String firstDataSet(TableHorizon h, TableHorizonCalculations cth, double clayPerc, double siltPerc,
double organic_matterPerc, double slb, double bulkDensity, double baseLayer_depth) {
double clay = clayPerc / 100;
double silt = siltPerc / 100;
double organic_matter = organic_matterPerc / 100;
StringBuilder tmpFirstString = new StringBuilder();
tmpFirstString.append(spaceFormat(slb));
// Master horizon
double slmh = -99d;
tmpFirstString.append(spaceFormat(slmh));
// lower limit, or wilitng point [cm3/cm3]
double slll = computeWiltingPoint(clay, silt, organic_matter);
tmpFirstString.append(spaceFormat(slll));
// drained upper limit, or field capacity [cm3/cm3]
double sdul = computeFieldCapacity(clay, silt, organic_matter);
tmpFirstString.append(spaceFormat(sdul));
// upper limit, saturated [cm3/cm3]
double ssat = computeSaturatedUpperLimit(sdul, clay, silt, organic_matter);
tmpFirstString.append(spaceFormat(ssat));
// root growth factor [0-1]
double srgf = computeRootGrowth(baseLayer_depth, slb);
tmpFirstString.append(spaceFormat(srgf));
// Sat. hydraulic conductivity, macropore, [cm/h]
double ssks = computeSatHydraulicConductivity(h);
tmpFirstString.append(spaceFormat(ssks));
// bulk density [g/cm3]
double sbdm = bulkDensity;
tmpFirstString.append(spaceFormat(sbdm));
// soil organic carbon [%]
// Saxton K., Rawls W. (2006) Soil water characteristic estimates by texture and organic matter for
// hydrologic solutions. Soil Science Society of America Journal 70:1569-1578
double sloc = organic_matterPerc / 2;
tmpFirstString.append(spaceFormat(sloc));
// Clay (<0.002 mm), [%]
double slcl = clayPerc;
tmpFirstString.append(spaceFormat(slcl));
// Silt (0.05 to 0.002 mm), [%]
double slsi = siltPerc;
tmpFirstString.append(spaceFormat(slsi));
// Coarse fraction (>2 mm), [%]
double slcf = cth.fragvol_r();
tmpFirstString.append(spaceFormat(slcf));
// Total nitrogen, [%]
double slni = -99d;
tmpFirstString.append(spaceFormat(slni));
// pH in water
double slhw = h.ph1to1h2o_r();
tmpFirstString.append(spaceFormat(slhw));
// pH in buffer
double slhb = h.ph01mcacl2_r();
tmpFirstString.append(spaceFormat(slhb));
// Cation exchange capacity, [cmol/kg]
double scec = h.cec7_r();
tmpFirstString.append(spaceFormat(scec));
// ???
double sadc = -99d;
tmpFirstString.append(spaceFormat(sadc));
return tmpFirstString.toString();
}
private String secondDataSet(TableHorizon tb, double slb) {
StringBuilder tmpSecondString = new StringBuilder();
tmpSecondString.append(spaceFormat(slb));
// Phosphorus, extractable, [mg/kg]
double slpx = tb.pbray1_r();
tmpSecondString.append(spaceFormat(slpx));
// Phosphorus, total, [mg/kg]
double slpt = tb.ptotal_r();
tmpSecondString.append(spaceFormat(slpt));
// Phosphorus, organic, [mg/kg]
double slpo = -99d;
tmpSecondString.append(spaceFormat(slpo));
// CaCO3 content, [g/kg]
double caco3 = tb.caco3_r();
tmpSecondString.append(spaceFormat(caco3));
// Aluminum
double slal = tb.extral_r();
tmpSecondString.append(spaceFormat(slal));
// Iron
double slfe = tb.freeiron_r();
tmpSecondString.append(spaceFormat(slfe));
// Manganese
double slmn = -99d;
tmpSecondString.append(spaceFormat(slmn));
// Base saturation, [cmol/kg]
double slbs = -99d;
tmpSecondString.append(spaceFormat(slbs));
// Phosphorus isotherm A, [mmol/kg]
double slpa = -99d;
tmpSecondString.append(spaceFormat(slpa));
// Phosphorus iostherm B, [mmol/l]
double slpb = -99d;
tmpSecondString.append(spaceFormat(slpb));
// Potassium, exchangeable, [cmol/kg]
double slke = -99d;
tmpSecondString.append(spaceFormat(slke));
// Magnesium, [cmol/kg]
double slmg = -99d;
tmpSecondString.append(spaceFormat(slmg));
// Sodium, [cmol/kg]
double slna = -99d;
tmpSecondString.append(spaceFormat(slna));
// Sulphur
double slsu = -99d;
tmpSecondString.append(spaceFormat(slsu));
// Electric conductivity, seimen
double slec = tb.ec_r();
tmpSecondString.append(spaceFormat(slec));
// Calcium, exchangeable, [cmol/kg]
double slca = -99d;
tmpSecondString.append(spaceFormat(slca));
return tmpSecondString.toString();
}
private String spaceFormat(double value) {
return String.format("%8s", df1.format(value));
}
private boolean isMandatorysSoilPropertiesValid(double clay, double silt,
double organic_matter, double bulkDensity) {
if (Double.compare(clay, -99d) == 0) {
return false;
} else if (Double.compare(silt, -99d) == 0) {
return false;
} else if (Double.compare(organic_matter, -99d) == 0) {
return false;
} else if (Double.compare(bulkDensity, -99d) == 0) {
return false;
} else {
return true;
}
}
// Saxton K., Rawls W. (2006) Soil water characteristic estimates by texture and organic matter for
// hydrologic solutions. Soil Science Society of America Journal 70:1569-1578
// table 1, eq. 1
private double computeWiltingPoint(double clay, double silt, double organic_matter) {
double tmp_slll = -0.024 * silt + 0.487 * clay + 0.006 * organic_matter
+ +0.005 * (silt * organic_matter) - 0.013 * (clay * organic_matter)
+ +0.068 * (silt * clay) + 0.031;
return tmp_slll + (0.14 * tmp_slll - 0.02);
}
// Saxton K., Rawls W. (2006) Soil water characteristic estimates by texture and organic matter for
// hydrologic solutions. Soil Science Society of America Journal 70:1569-1578
// table 1, eq. 2
private double computeFieldCapacity(double clay, double silt, double organic_matter) {
double tmp_sdul = -0.251 * silt + 0.195 * clay + 0.011 * organic_matter
+ +0.006 * (silt * organic_matter) - 0.027 * (clay * organic_matter)
+ +0.452 * (silt * clay) + 0.299;
return tmp_sdul + (1.283 * Math.pow(tmp_sdul, 2) - 0.374 * tmp_sdul - 0.015);
}
// Saxton K., Rawls W. (2006) Soil water characteristic estimates by texture and organic matter for
// hydrologic solutions. Soil Science Society of America Journal 70:1569-1578
// table 1, eq. 3 & 5
private double computeSaturatedUpperLimit(double fieldCapacity, double clay, double silt, double organic_matter) {
double ttmp_ssat = 0.278 * silt + 0.034 * clay + 0.022 * organic_matter
+ -0.018 * (silt * organic_matter) - 0.027 * (clay * organic_matter)
+ -0.584 * (silt * clay) + 0.078;
double tmp_ssat = ttmp_ssat + (0.636 * ttmp_ssat - 0.107);
return fieldCapacity + tmp_ssat - 0.097 * silt + 0.043;
}
private double computeRootGrowth(double top, double bottom) {
if (bottom < 15) {
return 1;
} else {
double midlayer = 0.5 * (bottom - top);
return Math.exp(-0.02 * midlayer);
}
}
private double computeSatHydraulicConductivity(TableHorizon h) {
return h.ksat_r() * 0.36; // why 0.36???
}
private void computeAverageMissingValue(TableHorizon h) {
if (Double.isNaN(h.claytotal_r())) {
h.claytotal_r(SoilUtils.averageMissingValue(h.claytotal_h(), h.claytotal_l(), h.claytotal_r()));
}
if (Double.isNaN(h.claytotal_r())) {
h.claytotal_r(-99d);
}
if (Double.isNaN(h.sandtotal_r())) {
h.sandtotal_r(SoilUtils.averageMissingValue(h.sandtotal_h(), h.sandtotal_l(), h.sandtotal_r()));
}
if (Double.isNaN(h.sandtotal_r())) {
h.sandtotal_r(-99d);
}
if (Double.isNaN(h.silttotal_r())) {
h.silttotal_r(SoilUtils.averageMissingValue(h.silttotal_h(), h.silttotal_l(), h.silttotal_r()));
}
if (Double.isNaN(h.silttotal_r())) {
h.silttotal_r(-99d);
}
if (Double.isNaN(h.om_r())) {
h.om_r(SoilUtils.averageMissingValue(h.om_h(), h.om_l(), h.om_r()));
}
if (Double.isNaN(h.om_r())) {
h.om_r(-99d);
}
if (Double.isNaN(h.ksat_r())) {
h.ksat_r(SoilUtils.averageMissingValue(h.ksat_h(), h.ksat_l(), h.ksat_r()));
}
if (Double.isNaN(h.ksat_r())) {
h.ksat_r(-99d);
}
if (Double.isNaN(h.hzdepb_r())) {
h.hzdepb_r(SoilUtils.averageMissingValue(h.hzdepb_h(), h.hzdepb_l(), h.hzdepb_r()));
}
if (Double.isNaN(h.hzdepb_r())) {
h.hzdepb_r(-99d);
}
if (Double.isNaN(h.dbthirdbar_r())) {
h.dbthirdbar_r(SoilUtils.averageMissingValue(h.dbthirdbar_h(), h.dbthirdbar_l(), h.dbthirdbar_r()));
}
if (Double.isNaN(h.dbthirdbar_r())) {
h.dbthirdbar_r(-99d);
}
if (Double.isNaN(h.caco3_r())) {
h.caco3_r(SoilUtils.averageMissingValue(h.caco3_h(), h.caco3_l(), h.caco3_r()));
}
if (Double.isNaN(h.caco3_r())) {
h.caco3_r(-99d);
}
if (Double.isNaN(h.ph1to1h2o_r())) {
h.ph1to1h2o_r(SoilUtils.averageMissingValue(h.ph1to1h2o_h(), h.ph1to1h2o_l(), h.ph1to1h2o_r()));
}
if (Double.isNaN(h.ph1to1h2o_r())) {
h.ph1to1h2o_r(-99d);
}
if (Double.isNaN(h.ph01mcacl2_r())) {
h.ph01mcacl2_r(SoilUtils.averageMissingValue(h.ph01mcacl2_h(), h.ph01mcacl2_l(), h.ph01mcacl2_r()));
}
if (Double.isNaN(h.ph01mcacl2_r())) {
h.ph01mcacl2_r(-99d);
}
if (Double.isNaN(h.cec7_r())) {
h.cec7_r(SoilUtils.averageMissingValue(h.cec7_h(), h.cec7_l(), h.cec7_r()));
}
if (Double.isNaN(h.cec7_r())) {
h.cec7_r(-99d);
}
if (Double.isNaN(h.pbray1_r())) {
h.pbray1_r(SoilUtils.averageMissingValue(h.pbray1_h(), h.pbray1_l(), h.pbray1_r()));
}
if (Double.isNaN(h.pbray1_r())) {
h.pbray1_r(-99d);
}
if (Double.isNaN(h.ptotal_r())) {
h.ptotal_r(SoilUtils.averageMissingValue(h.ptotal_h(), h.ptotal_l(), h.ptotal_r()));
}
if (Double.isNaN(h.ptotal_r())) {
h.ptotal_r(-99d);
}
if (Double.isNaN(h.extral_r())) {
h.extral_r(SoilUtils.averageMissingValue(h.extral_h(), h.extral_l(), h.extral_r()));
}
if (Double.isNaN(h.extral_r())) {
h.extral_r(-99d);
}
if (Double.isNaN(h.freeiron_r())) {
h.freeiron_r(SoilUtils.averageMissingValue(h.freeiron_h(), h.freeiron_l(), h.freeiron_r()));
}
if (Double.isNaN(h.freeiron_r())) {
h.freeiron_r(-99d);
}
}
}