SoilFileBuilder2.java [src/java/d/soils] 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.soils;
import csip.api.server.ServiceException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import soils.Horizon;
import soils.utils.SoilUtils;
/**
*
* @author sidereus
*/
public class SoilFileBuilder2 {
private Map<Double, List<Profile>> strata;
private double top = 0.0;
private boolean todo = Boolean.FALSE;
private boolean calibration;
public SoilFileBuilder2(Map<Double, List<Profile>> strata, boolean calibration) {
this.strata = strata;
this.calibration = calibration;
}
public String build() throws Exception {
String outLine = "";
for (Map.Entry<Double, List<Profile>> entry : strata.entrySet()) {
if (entry.getValue().size() > 1) {
// compute weighted average
List<Double> avg = profileDepthWeightedAverage(entry);
outLine += buildInLine(entry, avg);
} else {
List<Double> avg = new ArrayList<>();
avg.add(1.0);
outLine += buildInLine(entry, avg);
}
}
return outLine;
}
private List<Double> profileDepthWeightedAverage(Map.Entry<Double, List<Profile>> entry) {
List<Double> weightedAvg = new LinkedList<>();
double bottom = entry.getKey();
for (Profile prof : entry.getValue()) {
double avg = prof.getWeight(top, bottom);
weightedAvg.add(avg);
}
return weightedAvg;
}
/*
Column 1 - Minimum depth of soil layer (cm)
Column 2 - Maximum depth of soil layer (cm)
Column 3 - Bulk density of soil layer (g/cm^3)
Column 4 - Field capacity of soil layer, volumetric
Column 5 - Wilting point of soil layer, volumetric
Column 6 - Evaporation coefficient for soil layer (currently not being used)
Column 7 - Percentage of roots in soil layer, these values must sum to 1.0
Column 8 - Fraction of sand in soil layer, 0.0 - 1.0
Column 9 - Fraction of clay in soil layer, 0.0 - 1.0
Column 10 - Organic matter in soil layer, fraction 0.0 - 1.0
Column 11 - Minimum volumetric soil water content below wilting point for soil
layer, soil water content will not be allowed to drop below this
value
Column 12 - Saturated hydraulic conductivity of soil layer in centimeters per
second
Column 13 - pH of soil layer
*/
private String buildInLine(Map.Entry<Double, List<Profile>> entry, List<Double> avg) throws Exception {
double thirdbar = 0.0;
double fieldCapacity = 0.0;
double wiltPoint = 0.0;
double evaporation = 0.0;
double percentRoots = 0.0;
double sand = 0.0;
double clay = 0.0;
double om = 0.0;
double waterContent = 0.0;
double conductivity = 0.0;
double ph = 0.0;
if (entry.getValue().size() != avg.size()) {
throw new ServiceException("Avg and entry have different lengths");
}
for (int i = 0; i < avg.size(); i++) {
Horizon horizon = entry.getValue().get(i).getHorizon();
double tmpavg = avg.get(i);
if (tmpavg > 1.0) {
throw new ServiceException("Weghted average bigger than 1.0");
}
thirdbar += horizon.dbthirdbar_r() * tmpavg;
fieldCapacity += horizon.fieldCapacitySWC() * tmpavg; //testDouble(SoilUtils.getFieldCapacitySWC(horizon), " Field Capacity SWC ") * tmpavg;
wiltPoint += horizon.wiltingPointSWC() * tmpavg; //testDouble(SoilUtils.getWiltingPointSWC(horizon), "Wiltng Point SWC") * tmpavg;
evaporation += 0;
percentRoots += 0;
sand += testDouble(horizon.sandtotal_r(), "sandtotal_r") / 100 * tmpavg;
clay += testDouble(horizon.claytotal_r(), "claytotal_r") / 100 * tmpavg;
om += testDouble(horizon.om_r(), "om_r") / 100 * tmpavg;
conductivity += (testDouble(horizon.ksat_r(), "ksat_r") / 10000.0) * tmpavg;
ph += horizon.soilPh() * tmpavg; //testDouble(SoilUtils.getSoilpH(horizon), "soil pH") * tmpavg;
}
double toplayer = top;
double bottomlayer = entry.getKey();
if (bottomlayer == 2.0) {
waterContent = 0.09;
evaporation = 0.8;
// percentRoots = 0.027; // was 0.3 * 2 / 10;
percentRoots = 0.3 * 2 / 10;
} else if (bottomlayer == 5.0) {
waterContent = 0.07;
evaporation = 0.2;
percentRoots = 0.040; // was 0.3 * 3 / 10;
// percentRoots = 0.3 * 3 / 10;
} else if (bottomlayer == 10.0) {
waterContent = 0.05;
// percentRoots = 0.067; // was 0.3 * 5 / 10;
percentRoots = 0.3 * 5 / 10;
todo = Boolean.TRUE;
} else if (todo) {
waterContent = 0.02;
todo = Boolean.FALSE;
}
if (bottomlayer > 10.0 & toplayer <= 90.0) {
double depth = 0.0;
if (bottomlayer > 90.0) {
depth = 90 - toplayer;
} else {
depth = bottomlayer - toplayer;
}
percentRoots = 0.7 * depth / 80;
}
// if (bottomlayer == 20.0) {
// percentRoots = 0.133;
// } else if (bottomlayer == 30.0) {
// percentRoots = 0.133;
// } else if (bottomlayer == 45.0) {
// percentRoots = 0.1;
// } else if (bottomlayer == 60.0) {
// percentRoots = 0.1;
// } else if (bottomlayer == 75.0) {
// percentRoots = 0.1;
// } else if (bottomlayer == 90.0) {
// percentRoots = 0.1;
// } else if (bottomlayer == 105.0) {
// percentRoots = 0.033;
// } else if (bottomlayer == 120.0) {
// percentRoots = 0.033;
// } else if (bottomlayer == 150.0) {
// percentRoots = 0.067;
// } else if (bottomlayer == 180.0) {
// percentRoots = 0.067;
// }
top = bottomlayer;
// tmp fix to avoid waterContent > wiltpoint
if (waterContent > wiltPoint) {
if (wiltPoint == 0.0) {
waterContent = wiltPoint;
} else if (wiltPoint > 0.01) {
waterContent = wiltPoint - 0.01;
} else {
waterContent = 0.0;
}
} else if (waterContent == wiltPoint && waterContent > 0) {
waterContent = wiltPoint - 0.01;
}
return space8format(toplayer) // top layer
+ space8format(bottomlayer) // bottom layer
+ space9format(thirdbar) // bulk density
+ space12format(fieldCapacity)//getFieldCapacity(toplayer, calibration, fieldCapacity) // field capacity
+ space12format(wiltPoint)//getWiltingPoint(toplayer, calibration, wiltPoint) // wilting point
+ space9format(evaporation) // evaporation
+ space9format3(percentRoots) // percentage roots
+ space9format(sand) // fraction sand
+ space9format(clay) // fraction clay
+ space11format(om) // organic matter
+ space9format(waterContent) // soil water content
+ space15format(conductivity) // saturated hydraulic conductivity mm/h to cm/s
+ space4format((((ph < 6.5) && (toplayer < 30)) ? 6.5 : ph)) // pH
+ System.lineSeparator();
}
private String getFieldCapacity(double toplayer, boolean calibration, double fieldCapacity) {
if (calibration) {
if (toplayer == 0.0) {
return "${daycent.fieldCapacity1} ";
} else if (toplayer == 2.0) {
return "${daycent.fieldCapacity2} ";
} else if (toplayer == 5.0) {
return "${daycent.fieldCapacity3} ";
} else if (toplayer == 10.0) {
return "${daycent.fieldCapacity4} ";
} else if (toplayer == 20.0) {
return "${daycent.fieldCapacity5} ";
} else if (toplayer == 30.0) {
return "${daycent.fieldCapacity6} ";
} else if (toplayer == 45.0) {
return "${daycent.fieldCapacity7} ";
} else if (toplayer == 60.0) {
return "${daycent.fieldCapacity8} ";
} else if (toplayer == 75.0) {
return "${daycent.fieldCapacity9} ";
} else if (toplayer == 90.0) {
return "${daycent.fieldCapacity10} ";
} else {
return space12format(fieldCapacity);
}
} else {
return space12format(fieldCapacity);
}
}
private String getWiltingPoint(double toplayer, boolean calibration, double wiltingPoint) {
if (calibration) {
if (toplayer == 0.0) {
return "${daycent.wiltingPoint1} ";
} else if (toplayer == 2.0) {
return "${daycent.wiltingPoint2} ";
} else if (toplayer == 5.0) {
return "${daycent.wiltingPoint3} ";
} else if (toplayer == 10.0) {
return "${daycent.wiltingPoint4} ";
} else if (toplayer == 20.0) {
return "${daycent.wiltingPoint5} ";
} else if (toplayer == 30.0) {
return "${daycent.wiltingPoint6} ";
} else if (toplayer == 45.0) {
return "${daycent.wiltingPoint7} ";
} else if (toplayer == 60.0) {
return "${daycent.wiltingPoint8} ";
} else if (toplayer == 75.0) {
return "${daycent.wiltingPoint9} ";
} else if (toplayer == 90.0) {
return "${daycent.wiltingPoint10} ";
} else {
return space12format(wiltingPoint);
}
} else {
return space12format(wiltingPoint);
}
}
private double testDouble(double value, String field) throws Exception {
if (Double.isNaN(value)) {
throw new ServiceException("The value passed was NaN, indicating that for this field, " + field + ", of the SDM database there was missing data. Cannot continue building this SoilIN line.");
}
return value;
}
private String space4format(double value) {
DecimalFormat df1 = new DecimalFormat("0.00");
return String.format("%1$-4s", df1.format(value));
}
private String space8format(double value) {
DecimalFormat df1 = new DecimalFormat("0.0");
return String.format("%1$-8s", df1.format(value));
}
private String space9format(double value) {
DecimalFormat df1 = new DecimalFormat("0.00");
return String.format("%1$-9s", df1.format(value));
}
private String space9format3(double value) {
DecimalFormat df1 = new DecimalFormat("0.000");
return String.format("%1$-9s", df1.format(value));
}
private String space11format(double value) {
DecimalFormat df1 = new DecimalFormat("0.0000");
return String.format("%1$-11s", df1.format(value));
}
private String space12format(double value) {
DecimalFormat df1 = new DecimalFormat("0.00000");
return String.format("%1$-12s", df1.format(value));
}
private String space15format(double value) {
DecimalFormat df1 = new DecimalFormat("0.00000000");
return String.format("%1$-15s", df1.format(value));
}
}