DaycentStrata.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 data.interpretors.IFCFile;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import soils.Component;
import soils.Horizon;
import soils.MapUnit;
import soils.exceptions.SDMException;
import soils.exceptions.WEPPException;
import soils.exceptions.WEPSException;

/**
 *
 * @author sidereus
 */
public class DaycentStrata {

  private final Map<Double, List<Profile>> strata = new LinkedHashMap<>();
  private final List<Double> requiredDepths = new LinkedList();
  private Component comp = null;
  private double top = 0.0;
  private IFCFile ifcFile;


  public DaycentStrata(Component comp) {
    this.comp = comp;
    requiredDepths.add(2.0);
    requiredDepths.add(5.0);
    requiredDepths.add(10.0);
    requiredDepths.add(20.0);
    requiredDepths.add(30.0);
    requiredDepths.add(45.0);
    requiredDepths.add(60.0);
    requiredDepths.add(75.0);
    requiredDepths.add(90.0);
    requiredDepths.add(105.0);
    requiredDepths.add(120.0);
    requiredDepths.add(150.0);
    requiredDepths.add(180.0);
    requiredDepths.add(210.0);
//    requiredDepths.add(240.0);
  }


  public DaycentStrata(MapUnit mapunit, Component _comp) throws WEPSException, IOException, WEPPException, ServiceException, SDMException {

    if (mapunit.components().size() > 1) {
      if (!mapunit.components().containsKey(_comp.cokey())) {
        throw new ServiceException("This mapunit does not contain this component cokey.");
      }
    }

    comp = _comp;

    requiredDepths.add(2.0);
    requiredDepths.add(5.0);
    requiredDepths.add(10.0);
    requiredDepths.add(20.0);
    requiredDepths.add(30.0);
    requiredDepths.add(45.0);
    requiredDepths.add(60.0);
    requiredDepths.add(75.0);
    requiredDepths.add(90.0);
    requiredDepths.add(105.0);
    requiredDepths.add(120.0);
    requiredDepths.add(150.0);
    requiredDepths.add(180.0);
    requiredDepths.add(210.0);
//    requiredDepths.add(240.0);

    if (comp.usesGenericIFCorSOLValues()) {
      //Don't throw these away anymore...set them to use their original layer data.
      comp.usesGenericIFCorSOLValues(false);
    }

    String ifcString = mapunit.toIfc(comp.cokey());
    ifcFile = new IFCFile(ifcString);

    //Create new horizons array from the IFC information for the comp object and insert them.
    LinkedHashMap<String, Horizon> newHorizons = new LinkedHashMap<>();
    int beginLayer = 0;
    for (int i = 0; i < ifcFile.numberOfSoilLayers; i++) {
      Horizon tHorizon = new Horizon();
      tHorizon.chkey(String.valueOf(i + 1));
      tHorizon.dbthirdbar_r(ifcFile.wetBulkDensity[i]);
      tHorizon.hzthk_r(ifcFile.layerThickness[i] / 10);
      tHorizon.hzdepb_r(beginLayer + tHorizon.hzthk_r());
      tHorizon.hzdept_r(beginLayer);

      tHorizon.fieldCapacitySWC(ifcFile.fieldCapacitySWC[i]);
      tHorizon.wiltingPointSWC(ifcFile.wiltingPointSWC[i]);
      tHorizon.sandtotal_r(ifcFile.fractionSand[i] * 100);
      tHorizon.claytotal_r(ifcFile.fractionClay[i] * 100);
      tHorizon.om_r(ifcFile.organicMaterial[i] * 100);
      tHorizon.ksat_r(ifcFile.saturatedHydraulicConductivity[i] * 1000000);  //um/s to cm/s
      tHorizon.soilPh(ifcFile.soilpH[i]);
      if (checkBulkField(tHorizon)) {
        break;
      }
      newHorizons.put(tHorizon.chkey(), tHorizon);
      beginLayer += tHorizon.hzthk_r();
    }
    comp.setHorizons(newHorizons);
  }


  public Map<Double, List<Profile>> computeDaycentStrata() {
    comp.horizons().values().forEach((horizon) -> {
      //if (top == 0.0 & horizon.hzdepb_r() < 2) continue; // skip if initial horizon hzdepb < 2 cm
      if (horizon.dbthirdbar_r() >= 0) {  //ifcFile.wetBulkDensity value
        createDaycentHorizon(requiredDepths, horizon);
      }
    });
    return strata;
  }


  private boolean checkBulkField(Horizon h) {
    double partdens = 2.65;
    double porosity = 1.0 - (h.dbthirdbar_r() / partdens);
    return porosity - h.fieldCapacitySWC() < 0.0;
  }


  private void createDaycentHorizon(List<Double> requiredDepths, Horizon horizon) {
    if (!requiredDepths.isEmpty()) {
      if (horizon.hzdepb_r() <= requiredDepths.get(0)) { // add horizon
        addDaycentHorizon(horizon, requiredDepths.get(0), top, horizon.hzdepb_r());
        top = horizon.hzdepb_r();
      } else if (horizon.hzdepb_r() > requiredDepths.get(0)) {
        addDaycentHorizon(horizon, requiredDepths.get(0), top, requiredDepths.get(0));
        top = requiredDepths.get(0);
        requiredDepths.remove(0);
        createDaycentHorizon(requiredDepths, horizon);
      }
    }
//    } else {
//      if (horizon.hzdepb_r() > 90.0 & top < 90.0) {  // for root algorithm
//        double bottom = 90;
//        addDaycentHorizon(horizon, bottom, top, bottom);
//        top = bottom;
//        createDaycentHorizon(requiredDepths, horizon);
//      } else {
//        addDaycentHorizon(horizon, horizon.hzdepb_r(), top, horizon.hzdepb_r());
//        top = horizon.hzdepb_r();
//      }

//    }
  }


  private List getLinkedList(double bottomLayer) {
    if (strata.containsKey(bottomLayer)) {
      return strata.get(bottomLayer);
    } else {
      return new LinkedList<>();
    }
  }


  private void addDaycentHorizon(Horizon horizon, double depth, double top, double bottom) {
    List<Profile> listProf = getLinkedList(depth);
    Profile prof = new Profile(top, bottom, horizon);
    listProf.add(prof);
    strata.put(depth, listProf);
  }

}