V5_0.java [src/java/m/watershed/average_slope] 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.watershed.average_slope;

import csip.Check;
import csip.ModelDataService;
import csip.api.server.PayloadParameter;
import csip.api.server.ServiceException;
import csip.annotations.Description;
import csip.annotations.Name;
import csip.annotations.Resource;
import static csip.annotations.ResourceType.OUTPUT;
import csip.api.client.ModelDataServiceCall;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import javax.ws.rs.Path;
import m.watershed.Resources;
import static m.watershed.Resources.D8;
import static m.watershed.Resources.DINF;
import static m.watershed.Resources.GDAL;
import static m.watershed.Resources.LOCATION_MNT_DATA1;
import static m.watershed.Resources.LOCATION_MNT_CSIP_DEM;
import static m.watershed.Resources.MPI;
import static m.watershed.Resources.OGR;
import static m.watershed.Resources.PITREMOVE;
import static m.watershed.Resources.PYTHON;
import static m.watershed.Resources.ZONALSTATS_MEAN;
import static m.watershed.Utils.exec;
import static m.watershed.Utils.checkExist;
import org.apache.commons.io.FileUtils;
import org.codehaus.jettison.json.JSONObject;

/**
 * average_slope
 *
 * @author @author HK (using JK's template (using OD's template))
 */
@Name("average_slope")
@Description("Example of average_slope")
@Path("m/average_slope/5.0")
@Resource(from = Resources.class)
//@Resource(file = "*.tif *.csv *.kml *.kmz *.geojson *.asc *.shp *.txt *.dbf *.prj *.shx", type = OUTPUT)
@Resource(file = "*.csv", type = OUTPUT)
public class V5_0 extends ModelDataService {

  static final String BOUNDARY = "boundary";
  static final String RESULTID = "result_ID";
  static final String DINFIN = "DInf";
  static final String DEM_RES = "DEM_RES";
  static final String SERVICETHREADS = "Threads";
  static final String DEM_RES1 = "DEM_res1";
  static final String AOI_BUF = "AOI_buf";

  boolean shp_file = false;
  boolean DEM1_cover = false;
  boolean DEM3_cover = false;
  String shp_name = "";
  Integer resolution = 10;
  Integer pixel_width = 10;
  JSONObject boundary = null;
  double avgResult = Double.NaN;

  @Override
  protected void doProcess() throws Exception {
    PayloadParameter inputPayload = parameter();

    if (inputPayload.has(BOUNDARY) && inputPayload.has(RESULTID)) {

      String b = parameter().getString(BOUNDARY);

      if (b.endsWith("shp")) {
        shp_file = true;
        File input_file = attachments().getFile(b);
        shp_name = input_file.getName();
      } else {
        boundary = parameter().getJSONArray(BOUNDARY).getJSONObject(0);
        FileUtils.writeStringToFile(workspace().getFile("boundary.geojson"), boundary.toString(), "UTF-8");
      }

      String ID = parameter().getString(RESULTID);

      // optional parameter
      boolean TauDEMInf = parameter().getBoolean(DINFIN, false);

      resolution = parameter().getInt(DEM_RES, 10);
      new Check().positive().forNumber(resolution);

      int threads = parameter().getInt(SERVICETHREADS, 2);
      int resample = parameter().getInt(DEM_RES1, 10);
      int buffer = parameter().getInt(AOI_BUF, 25);

      run(ID, TauDEMInf, resolution, threads, resample, buffer);
    } else {
      throw new ServiceException("Geometry Input File not found and/or Result-ID not found !! ");
    }
  }

  /**
   *
   * @param boundary
   * @param ID
   * @param TauDEMInf
   * @param resolution
   * @throws Exception
   *
   */
  private void run(String ID, boolean TauDEMInf, int resolution, int threads, int resample, int buffer) throws Exception {

    checkExist(new File(LOCATION_MNT_DATA1), "DEM.vrt");

    String dem30 = LOCATION_MNT_DATA1 + "/DEM.vrt";
    String dem10 = LOCATION_MNT_CSIP_DEM + "/DEM.vrt";
    String dem3 = LOCATION_MNT_CSIP_DEM + "/DEM_1_9_arc/DEM_1_9.vrt";
    String dem1 = LOCATION_MNT_CSIP_DEM + "/DEM_1m/1m.vrt";

    if (!shp_file) {
      checkExist(workspace().getDir(), "boundary.geojson");
      exec(resources(), LOG,
          OGR,
          "-t_srs", "EPSG:5070",
          "-f", "ESRI Shapefile",
          workspace().getFile("boundaryPre.shp"),
          workspace().getFile("boundary.geojson")
      );

    } else {
      checkExist(workspace().getDir(), shp_name);
      exec(resources(), LOG,
          OGR,
          "-t_srs", "EPSG:5070",
          "-f", "ESRI Shapefile",
          workspace().getFile("boundaryPre.shp"),
          workspace().getFile(shp_name)
      );
    }
    checkExist(workspace().getDir(), "boundaryPre.shp");

    exec(resources(), LOG,
        OGR,
        "-update",
        "-append",
        "-dialect", "sqlite",
        "-sql", "select ST_buffer(extent(geometry), " + buffer + ")," + ID + " from boundaryPre",
        workspace().getFile("boundaryBuf.shp"),
        workspace().getFile("boundaryPre.shp")
    );
    checkExist(workspace().getDir(), "boundaryBuf.shp");

    if (resolution < 10) {
      if (resolution == 3) {
        setProgress("Calling DEM 3 check of coverage ...");
        String url = "http://csip.engr.colostate.edu:8087/csip-watershed/m/checkDEM3m_cover/1.0";

        ModelDataServiceCall res = new ModelDataServiceCall()
            .put("jsongeom", parameter().getJSONArray(BOUNDARY))
            .url(url)
            .call();

        if (res.serviceFinished()) {
          DEM3_cover = res.getBoolean("3m_DEM");
        } else {
          throw new Exception("3m DEM check service error: " + res.getError());
        }
      }
      if (resolution == 1) {
        setProgress("Calling DEM 1 check of coverage ...");
        String url = "http://csip.engr.colostate.edu:8087/csip-watershed/m/checkDEM1m_cover/1.0";

        ModelDataServiceCall res = new ModelDataServiceCall()
            .put("jsongeom", parameter().getJSONArray(BOUNDARY))
            .url(url)
            .call();

        if (res.serviceFinished()) {
          DEM1_cover = res.getBoolean("1m_DEM");
        } else {
          throw new Exception("1m DEM check service error: " + res.getError());
        }
      }
    }

    String selected_dem = dem10;
    pixel_width = 10;

    if (DEM3_cover && resolution < 10) {
      selected_dem = dem3;
      pixel_width = 3;
    }
    if (DEM1_cover && resolution == 1) {
      selected_dem = dem1;
      pixel_width = 1;
    }
    if (resolution > 10) {
      selected_dem = dem30;
      pixel_width = 30;
    }

    exec(resources(), LOG,
        GDAL,
        selected_dem,
        workspace().getFile("DEMclip0.tif"),
        "-crop_to_cutline",
        "-cutline",
        workspace().getFile("boundaryBuf.shp"),
        "-multi",
        "-of", "GTiff",
        "-co", "TILED=YES",
        "-co", "COMPRESS=LZW",
        "-co", "BIGTIFF=YES",
        "-ot", "Float32",
        "-co", "NUM_THREADS=" + threads,
        "-wo", "NUM_THREADS=" + threads,
        "-wo", "CUTLINE_ALL_TOUCHED=TRUE",
        "--config", "GDAL_CACHEMAX", "2000",
        "-wm", "2000"
    );
    checkExist(workspace().getDir(), "DEMclip0.tif");

//        if (resample < 1) {
//            resample = 1;
//        }
//        if (resample > 90) {
//            resample = 90;
//        }
    exec(resources(), LOG,
        GDAL,
        "-t_srs", "EPSG:5070",
        "-tr", "" + pixel_width, "" + pixel_width,
        "-r", "cubicspline",
        //"-r", "near",
        workspace().getFile("DEMclip0.tif"),
        workspace().getFile("DEMclip.tif"),
        "-multi",
        "-of", "GTiff",
        "-co", "TILED=YES",
        "-co", "COMPRESS=LZW",
        "-co", "BIGTIFF=YES",
        "-ot", "Float32",
        "-co", "NUM_THREADS=" + threads,
        "-wo", "NUM_THREADS=" + threads,
        "-wo", "CUTLINE_ALL_TOUCHED=TRUE",
        "--config", "GDAL_CACHEMAX", "2000",
        "-wm", "2000"
    );
    checkExist(workspace().getDir(), "DEMclip.tif");

    exec(resources(), LOG,
        MPI,
        "--allow-run-as-root",
        "--path", resources().getFile(PITREMOVE).getParent(),
        "-wdir", workspace().getDir(),
        "--oversubscribe",
        "-np", threads,
        resources().getFile(PITREMOVE).getName(),
        "-z", workspace().getFile("DEMclip.tif"),
        "-fel", workspace().getFile("demfill.tif")
    );
    checkExist(workspace().getDir(), "demfill.tif");

    if (!TauDEMInf) {
      exec(resources(), LOG,
          MPI,
          "--allow-run-as-root",
          "--path", resources().getFile(D8).getParent(),
          "-wdir", workspace().getDir(),
          "--oversubscribe",
          "-np", threads,
          resources().getFile(D8).getName(),
          "-fel", workspace().getFile("demfill.tif"),
          "-sd8", workspace().getFile("slope.tif"),
          "-p", workspace().getFile("p.tif")
      );
    } else {
      exec(resources(), LOG,
          MPI,
          "--allow-run-as-root",
          "--path", resources().getFile(DINF).getParent(),
          "-wdir", workspace().getDir(),
          "--oversubscribe",
          "-np", threads,
          resources().getFile(DINF).getName(),
          "-fel", workspace().getFile("demfill.tif"),
          "-slp", workspace().getFile("slope.tif"),
          "-ang", workspace().getFile("flow_direction_inf_pre.tif")
      );
    }
    checkExist(workspace().getDir(), "slope.tif");

    // zonal stats
    exec(resources(), LOG,
        PYTHON,
        resources().getFile(ZONALSTATS_MEAN),
        workspace().getFile("boundaryPre.shp"),
        workspace().getFile("slope.tif"),
        ID,
        "avg_slope_",
        "False"
    );
    checkExist(workspace().getDir(), "avg_slope_results.csv");
    pullAvgResult();
  }

  @Override
  protected void postProcess() throws Exception {
    //results().put(workspace().getFile("boundary.geojson"), "boundary");
    results().put("DEM_Resolution ", pixel_width, "used DEM for this request");
    results().put("average_slope", avgResult,"Average calculated slope from first line of csv file.");
    results().put(workspace().getFile("avg_slope_results.csv"), "results");
  }

  protected void pullAvgResult() throws IOException, ServiceException {
    File resultFile = workspace().getFile("avg_slope_results.csv");
    List<String> results = FileUtils.readLines(resultFile, Charset.defaultCharset());

    if (results.size() >= 2) {
      String average = results.get(1);
      String[] values = average.split(",");
      avgResult = Double.parseDouble(values[1]);
    } else {
      throw new ServiceException("No average values are found in the resulting csv file.");
    }

  }
}