V2_0.java [src/java/m/ghg/daycent] 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 m.ghg.daycent;

import csip.Config;
import csip.api.client.ModelDataServiceCall;
import csip.api.server.PayloadParameter;
import csip.api.server.ServiceException;
import csip.annotations.Description;
import csip.annotations.Name;
import csip.annotations.Options;
import csip.annotations.Resource;
import csip.utils.Parallel;
import gisobjects.GISObject;
import gisobjects.GISObjectFactory;
import gisobjects.db.GISEngineFactory;
import java.io.IOException;
import java.nio.file.Files;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.ws.rs.Path;
import m.ghg.ApplicationResources;
import static m.ghg.ApplicationResources.*;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

/**
 *
 * @author sidereus, od
 */
@Name("Daycent simulation execution")
@Description("Daycent CSIP service")
@Path("m/daycent/2.0")
@Options(timeout = "P1H")
@Resource(from = ApplicationResources.class)
public class V2_0 extends V1_0 {

  protected JSONObject rotation;
  protected List<Integer> crop_id;
  protected Collection<String> JSONparams;


  @Override
  protected void preProcess() throws ServiceException {
    super.preProcess();
    JSONparams = parameter().getNames();
  }


  @Override
  protected void doProcess() throws Exception {

    //  Get centroid of shape, if it is not a point already.  (If it's a point, the centroid is the point)
    try (Connection conn = resources().getJDBC(GISDB_SQLSVR)) {
      GISObject shape = GISObjectFactory.createGISObject(aoa_geometry, GISEngineFactory.createGISEngine(conn));

      //  getLat/Lon functions get point value or the centroid of the shape.
      latlon[0] = shape.getLatitude();
      latlon[1] = shape.getLongitude();
    }

    getJSONParams();

    Parallel.run(Config.getBoolean("ghg.serial.datafetch", false),
        () -> {
          fetchClimate();
          computeWeatherStats();
        },
        () -> {
          fetchSoil();
          countLayers(); // testing if we need the fix structure in Black et al. 2017
        },
        () -> {
          createConfig("crop.100");
        }
    );
    createConfig(getSite100());
    createConfig("fix.100");
    runDaycent();
    runDaycentList();
  }

  static final Map<String, Map<String, String>> defMap = new HashMap() {
    {
      put("prdx", prdxDef);
      put("ppdf1", ppdf1Def);
      put("himax", himaxDef);
      put("ppdf2", ppdf2Def);
      put("pramn", pramnDef);
      put("pramx", pramxDef);

    }

  };


  protected void countLayers() {
    try {
      profileDepths = new LinkedList<>();
      List<Double> profiles = Files.lines(workspace().getFile("soils.in").toPath())
          .map(str -> str.split("\\s+"))
          .map(str -> Double.parseDouble(str[1]))
          .collect(Collectors.toList());
      double[] defaultProfile = new double[]{10, 20, 15, 15, 30, 30, 30, 30, 30, 30};
      double val = 0;
      double bottom = profiles.get(profiles.size() - 1);
      for (int i = 0; i < defaultProfile.length; i++) {
        double prof = defaultProfile[i];
        val += prof;
        if (val == bottom) {
          profileDepths.add(prof);
          break;
        } else if (val > bottom) {
          double tmpval = val - prof;
          profileDepths.add(bottom - tmpval);
          break;
        } else {
          profileDepths.add(prof);
        }
      }
      nlayer = profileDepths.size(); // - 2; // the first three layers are meshed into 1
    } catch (IOException ex) {
      throw new RuntimeException(ex.getMessage());
    }
  }


  protected Map<String, Map<String, Double>> dictPopulation(Map<String, Map<String, Double>> hashmap, String s) throws ServiceException {
    String[] parts = s.split("\\.");
    String cropName = parts[1];
    String parameterName = parts[2];
    Double parameterValue = parameter().getDouble(s);
    if (hashmap.containsKey(cropName)) {
      hashmap.get(cropName).put(parameterName, parameterValue);
    } else {
      Map<String, Double> val1 = new HashMap<>();
      val1.put(parameterName, parameterValue);
      hashmap.put(cropName, val1);
    }
    return hashmap;
  }


  protected void fillCropValues() {
    for (Map.Entry<String, Map<String, Double>> entry : crops.entrySet()) {

      List<String> cropparamList = Arrays.asList("prdx", "ppdf1", "ppdf2", "himax");
      for (String param : cropparamList) {
        if (!entry.getValue().containsKey(param)) {

          crops.get(entry.getKey()).put(param, Double.parseDouble(defMap.get(param).get(entry.getKey())));
        }
      }
    }
  }


  protected void fillFileValues(List<String> paramList, Map<String, Map<String, Double>> hashmap, Map<String, String> defName) {

    for (Map.Entry<String, Map<String, Double>> entry : hashmap.entrySet()) {
      for (String param : paramList) {
        if (!entry.getValue().containsKey(param)) {

          hashmap.get(entry.getKey()).put(param, Double.parseDouble(defName.get(param)));
        }
      }
    }

  }


  protected void getJSONParams() throws JSONException, ServiceException {
    List<String> paramList = Arrays.asList("fwloss1", "fwloss2", "fwloss3", "fwloss4",
        "dec32", "dec4", "dec52", "dec11", "dec12", "dec22", "dec21", "dec31", "dec51", "teff1", "teff2", "teff3", "teff4", "ps1s31",
        "ps1s32", "ps2s31", "ps2s32");
    List<String> lrrmList = Arrays.asList("basef");
    for (String s : JSONparams) {
      String[] parts = s.split("\\.");
      if (parts.length > 1) {
        String cropType = parts[0];
        String fileName = parts[1];
        if (cropType.equals("crop")) {
          crops = dictPopulation(crops, s);
        } else if (cropType.equals("param") && fileName.equals("fixes")) {
          fixes = dictPopulation(fixes, s);
        } else if (cropType.equals("param") && fileName.equals("lrrm")) {
          lrrm = dictPopulation(lrrm, s);
        }
      }
    }

    fillFileValues(paramList, fixes, fixDef);
    fillFileValues(lrrmList, lrrm, lrrmDef);
    fillCropValues();
  }


  protected void fetchSoil() throws Exception {
    ModelDataServiceCall mds = new ModelDataServiceCall()
        .put(STREAM_FILE, fileAsJSON)
        .put(soils.AoA.AOA_GEOMETRY, new JSONObject()
            .put(TYPE, aoa_geometry.get(TYPE))
            .put(COORDINATES, aoa_geometry.get(COORDINATES)))
        .url(Config.getString("ghg.soilfile.url",
            request().getCodebase() + "d/insoilfile/2.0"))
        .call();

    if (mds.serviceFinished()) {
      mds.download("soils.in", workspace().getFile("soils.in"));
    } else {
      throw new ServiceException("GHG Soil service error: " + mds.getError());
    }
  }

}