V1_0.java [src/java/d/crlmod/cropResidue] Revision: default  Date:
/*
 * Copyright 2020 sidereus.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package d.crlmod.cropResidue;

import crlmod.ServiceResources;
import static crlmod.ServiceResources.*;
import csip.ModelDataService;
import csip.api.server.ServiceException;
import csip.annotations.Description;
import csip.annotations.Name;
import csip.annotations.Resource;
import csip.annotations.VersionInfo;
import java.io.StringReader;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Path;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

/**
 *
 * @author sidereus
 */
@Name("sm crops")
@Description("sm crops")
@VersionInfo("1.0")
@Path("d/cropResidue/1.0")
@Resource(from = ServiceResources.class)
public class V1_0 extends ModelDataService {

  @Override
  protected void doProcess() throws Exception {
    //does the user want param_sets, or just base data?
    int crop_id = parameter().getInt("crop_id");
    double cropYield = parameter().getDouble("crop_yield");
    String harvest_date = parameter().getString("harvest_date");
    String plant_date = parameter().getString("plant_date");

    LocalDate harvest = LocalDate.parse(harvest_date);
    LocalDate plant = LocalDate.parse(plant_date);

    long residueInterval = ChronoUnit.DAYS.between(harvest, plant);
    computeBiomassResidue(crop_id, cropYield, residueInterval);
  }

  private void computeBiomassResidue(int crop_id, double cropYield, long residueInterval) throws Exception {
    DecimalFormat df = new DecimalFormat("0.00");
    List<String> params = new ArrayList<>();
    String query = "SELECT crop_id, crop_name, crop_yield, crop_yield_unit, \n"
        + "weps_crop_param_set, wepp_crop_param_set, rs_lbs_per_unit \n"
        + "FROM crops \n"
        + "     LEFT JOIN weps_crops on (fk_weps_crop_id = weps_crop_id) \n"
        + "     LEFT JOIN wepp_crops on (fk_wepp_crop_id = wepp_crop_id) \n"
        + "     LEFT JOIN step_crop on (fk_step_crop_id = rs_crop_id) \n";

    try (Connection connection = resources().getJDBC(getJDBCId())) {
      try (Statement statement = connection.createStatement()) {
        try (ResultSet resultSet = statement.executeQuery(query)) {
          if (!resultSet.next()) {
            String errors = "No crops found with ";
            for (int i = 0; i < params.size(); i++) {
              errors += params.get(i);
              if (i < params.size() - 1)
                errors += "and ";
            }
            throw new ServiceException(errors);
          }
          boolean found = false;
          do {
            BigDecimal cropID = resultSet.getBigDecimal("crop_id");
            if (cropID.equals(new BigDecimal(crop_id))) {
              double conversionFactor = resultSet.getInt("rs_lbs_per_unit");
              String wepp_param_set = resultSet.getString("wepp_crop_param_set");

              DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
              DocumentBuilder builder = factory.newDocumentBuilder();
              Document doc = builder.parse(new InputSource(new StringReader(wepp_param_set)));
              XPathFactory xPf = XPathFactory.newInstance();
              XPath xP = xPf.newXPath();
              XPathExpression expr = xP.compile("//weppcrop/hi");

              double wepp_hi = Double.parseDouble(expr.evaluate(doc)); // harvest index
              expr = xP.compile("//weppcrop/oratea");
              double wepp_oratea = Double.parseDouble(expr.evaluate(doc)); // daily residue decomposition rate
              double cropResidue = computeBiomassResidue(cropYield, conversionFactor, wepp_hi, wepp_oratea, residueInterval);
              results().put("cropResidue", df.format(cropResidue));
              found = true;
              break;
            }
          } while (resultSet.next());
          if (!found)
            throw new RuntimeException("Crop ID " + crop_id + " not in database.");
        }
      }
    }
  }

  private double computeBiomassResidue(double cropYield, double conversionFactor,
      double hi, double residueDecompositionRate, long residueInterval) {
    double convertedCropYield = cropYield * conversionFactor;
    double hi_denominator = (1 - hi) / hi;
    double residue = Math.pow((1 - residueDecompositionRate), residueInterval);
    return (convertedCropYield / hi_denominator) * residue;
  }

  protected String getJDBCId() {
    return CR_LMOD_2019_STEP_ID;
  }

  @Override
  protected Map<String, Object> getConfigInfo() {
    return new LinkedHashMap<String, Object>() {
      {
        put(getJDBCId(), resources().getResolved(getJDBCId()));
      }
    };
  }
}