V1_0.java [src/java/m/comet/comet06_cometplanner] Revision: default  Date:
/*
 * $Id$
 *
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * a Model-as-a-Service framework, API, and application suite.
 *
 * 2012-2017, OMSLab, Colorado State University.
 *
 * OMSLab licenses this file to you under the MIT license.
 * See the LICENSE file in the project root for more information.
 */
package m.comet.comet06_cometplanner;

import csip.ModelDataService;
import csip.ServiceException;
import csip.annotations.Polling;
import csip.annotations.Resource;
import static csip.annotations.ResourceType.FILE;
import gisobjects.raster.GISRaster;
import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.Callable;
import javax.ws.rs.Path;
import static m.comet.comet06_cometplanner.V1_0.PET_FILE;
import static m.comet.comet06_cometplanner.V1_0.PRISM_FILE;
import m.comet.utils.DBQueries;
import m.comet.utils.DBResources;
import csip.annotations.Description;
import csip.annotations.Name;
import org.codehaus.jettison.json.JSONException;
import org.geotools.coverage.grid.GridCoordinates2D;
import static m.comet.utils.DBResources.CRDB;

/**
 * COMET-06: Compute Conservation Practice Effects on Carbon Sequestration and
 * Greenhouse Gas Emissions
 *
 * @author rumpal
 * @version 1.0
 */
@Name("COMET-06: Compute Conservation Practice Effects on Carbon Sequestration "
    + "and Greenhouse Gas Emissions")
@Description("This service computes conservation practice effects on carbon "
    + "sequestration and greenhouse gas emissions. The service is based "
    + "on COMET-Planner and has two design options: (1) compute practice "
    + "effects, or (2) get practice data and populate an XML input file "
    + "for a COMET-Planner API. This specification covers the first option.")
@Path("m/comet/runcometplanner/1.0")
@Polling(first = 10000, next = 2000)
@Resource(from = DBResources.class)
@Resource(file = "/data/CONUS_PET_800m.tif", type = FILE, id = PET_FILE)
@Resource(file = "/data/PRISM_ppt_30yr_normal_800mM2_annual.tif", type = FILE, id = PRISM_FILE)
@Deprecated
//Work in progress, might need adjustments
public class V1_0 extends ModelDataService {

  private int practiceId, climateZoneId;
  private double practiceArea, latitude, longitude;
  private String climateZoneName;
  private double effectCO2, effectN2O, effectCH3, effect_co2_equiv = 0;

  public static final String PET_FILE = "pet_file";
  public static final String PRISM_FILE = "prism_file";

  static GISRaster gisRaster;
  static GISRaster gisPRISMRaster;

  static final Object RASTER_LOCK = new Object();

  private double annualPrecip, pet;

  private boolean noData = true;


  @Override
  public void preProcess() throws ServiceException, JSONException {
    practiceId = parameter().getInt("practice_id");
    practiceArea = parameter().getDouble("practice_acres");
    latitude = parameter().getParamJSON("aoa_centroid").getDouble("latitude");
    longitude = parameter().getParamJSON("aoa_centroid").getDouble("longitude");
  }


  @Override
  public void doProcess() throws ServiceException, Exception {
    setClimateZone();
    computePracticeEffects();
  }


  @Override
  public void postProcess() {
    if (noData) {
      results().put("Message", "Not a COMET practice.");
    } else {
      results().put("climate_area_id", climateZoneId, "Climate Area Identifier");
      results().put("climate_area_name", climateZoneName, "Climate Area Name");
      results().put("effect_co2", effectCO2, "", "tons/acre/year");
      results().put("effect_n2o", effectN2O, "", "tons/acre/year");
      results().put("effect_ch3", effectCH3, "", "tons/acre/year");
      results().put("effect_co2_equiv", effect_co2_equiv, "", "tons/acre/year");
      results().put("PRISM precipitation", annualPrecip);
      results().put("CGIAR PET", pet);
      results().put("CGIAR PET * 0.75", pet * 0.75);
    }
  }


  /**
   * Singleton.
   *
   * @param rasterFile
   * @throws Exception
   */
  private static synchronized void loadPETRaster(Callable<File> rasterFile) throws Exception {
    if (gisRaster == null) {
      gisRaster = new GISRaster(rasterFile.call());
    }
  }


  /**
   * Singleton.
   *
   * @param rasterFile
   * @throws Exception
   */
  private static synchronized void loadPRISMRaster(Callable<File> rasterFile) throws Exception {
    if (gisPRISMRaster == null) {
      gisPRISMRaster = new GISRaster(rasterFile.call());
    }
  }

  //Getting the value of the pixel at point from the raster
  //PET data from CIGAR

  private double getPET() throws Exception {
    loadPETRaster(() -> resources().getFile(PET_FILE));
    GridCoordinates2D posGrid;
    synchronized (RASTER_LOCK) {
      posGrid = gisRaster.transformToRasterGrid(latitude, longitude, 4326);
    }

    if (gisRaster.contains(posGrid)) {
      synchronized (RASTER_LOCK) {
        pet = (gisRaster.pixelValue(posGrid));
      }
    }
    System.out.println("pet = " + pet);
    return pet;
  }


  private double getAnnualPrecip() throws Exception {
    loadPRISMRaster(() -> resources().getFile(PRISM_FILE));
    GridCoordinates2D posGrid;
    synchronized (RASTER_LOCK) {
      posGrid = gisPRISMRaster.transformToRasterGrid(latitude, longitude, 4326);
    }

    if (gisPRISMRaster.contains(posGrid)) {
      synchronized (RASTER_LOCK) {
        annualPrecip = (gisPRISMRaster.pixelValue(posGrid));
      }
    }
    System.out.println("annualPrecip = " + annualPrecip);
    return annualPrecip;
  }


  private void setClimateZone() throws Exception {
    // 1 is moist humid and 2 is dry semiarid
    climateZoneId = getPET() * 0.75 <= getAnnualPrecip() ? 1 : 2;
  }


  private void computePracticeEffects() throws ServiceException, SQLException {
    try (Connection ssurgoConn = resources().getJDBC(CRDB);) {
      if (climateZoneId == 1) {
        climateZoneName = "Moist Humid";
        try (Statement statement = ssurgoConn.createStatement();
            ResultSet resultSet = statement.executeQuery(DBQueries.COMET06Query01(practiceId))) {
          while (resultSet.next()) {
            noData = false;
            effectCO2 = resultSet.getDouble("moist_humid_co2") * practiceArea / 1.10231;
            effectN2O = resultSet.getDouble("moist_humid_n20") * practiceArea / 1.10231;
            effectCH3 = resultSet.getDouble("moist_humid_methane") * practiceArea / 1.10231;
            effect_co2_equiv += effectCO2 + effectN2O + effectCH3;
          }
        }
      } else if (climateZoneId == 2) {
        climateZoneName = "Dry Semiarid";
        try (Statement statement = ssurgoConn.createStatement();
            ResultSet resultSet = statement.executeQuery(DBQueries.COMET06Query02(practiceId))) {
          while (resultSet.next()) {
            noData = false;
            effectCO2 = resultSet.getDouble("dry_semiarid_co2") * practiceArea / 1.10231;
            effectN2O = resultSet.getDouble("dry_semiarid_n20") * practiceArea / 1.10231;
            effectCH3 = resultSet.getDouble("dry_semiarid_methane") * practiceArea / 1.10231;
            effect_co2_equiv += effectCO2 + effectN2O + effectCH3;
          }
        }
      }
    }
  }
}