SoilFileBuilder.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 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 SoilFileBuilder {
private Map<Double, List<Profile>> strata;
private double top = 0.0;
private boolean todo = Boolean.FALSE;
public SoilFileBuilder(Map<Double, List<Profile>> strata) {
this.strata = strata;
}
public String build() {
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) {
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()) {
String msg = "Avg and entry have different lengths";
throw new RuntimeException(msg);
}
for (int i = 0; i < avg.size(); i++) {
Horizon horizon = entry.getValue().get(i).getHorizon();
double tmpavg = avg.get(i);
if (tmpavg > 1.0) {
String msg = "Weghted average bigger than 1.0";
throw new RuntimeException(msg);
}
thirdbar += horizon.dbthirdbar_r() * tmpavg;
fieldCapacity += SoilUtils.getFieldCapacitySWC(horizon) * tmpavg;
wiltPoint += SoilUtils.getWiltingPointSWC(horizon) * tmpavg;
evaporation += 0;
percentRoots += 0;
sand += horizon.sandtotal_r() / 100 * tmpavg;
clay += horizon.claytotal_r() / 100 * tmpavg;
om += horizon.om_r() / 100 * tmpavg;
conductivity += (horizon.ksat_r() / 10000.0) * tmpavg;
ph += SoilUtils.getSoilpH(horizon) * tmpavg;
}
double toplayer = top;
double bottomlayer = entry.getKey();
if (bottomlayer == 2.0) {
waterContent = 0.09;
evaporation = 0.8;
percentRoots = 0.3 * 2 / 10;
} else if (bottomlayer == 5.0) {
waterContent = 0.07;
evaporation = 0.2;
percentRoots = 0.3 * 3 / 10;
} else if (bottomlayer == 10.0) {
waterContent = 0.05;
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;
}
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;
}
}
return space8format(toplayer) // top layer
+ space8format(bottomlayer) // bottom layer
+ space9format(thirdbar) // bulk density
+ space12format(fieldCapacity) // field capacity
+ space12format(wiltPoint) // wilting point
+ space9format(evaporation) // evaporation
+ space9format(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) // pH
+ System.lineSeparator();
}
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 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));
}
}