V1_0.java [src/java/m/comet/comet02_soilinput] 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.comet02_soilinput;

import m.comet.utils.DBQueries;
import csip.ModelDataService;
import csip.ServiceException;
import csip.annotations.Polling;
import csip.annotations.Resource;
import static csip.annotations.ResourceType.OUTPUT;
import csip.utils.JSONUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Map;
import javax.ws.rs.Path;
import m.comet.utils.DBResources;
import static m.comet.utils.DBResources.SDM_REST;
import csip.annotations.Description;
import csip.annotations.Name;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

/**
 * COMET-02: Get Soil Parameters for the COMET API
 *
 * @author rumpal
 * @version 1.0
 */
@Name("COMET-02: Get Soil Parameters for the COMET API")
@Description("This service fetches soil parameters from the NRCS Soil Data Mart "
        + "through the CDSI csip-soils layer for the COMET models.")
@Path("m/comet/cometsoilinput/1.0")
@Polling(first = 10000, next = 2000)
@Resource(from = DBResources.class)
@Resource(file = "*.IN", type = OUTPUT)
@Deprecated
public class V1_0 extends ModelDataService {

    private ArrayList<MapUint> mapunitList = new ArrayList<>();

    @Override
    public void preProcess() throws ServiceException {
        JSONArray muArr = parameter().getJSONArray("Mukey List");
        try {
            for (int i = 0; i < muArr.length(); i++) {
                Map<String, JSONObject> mu = JSONUtils.preprocess(muArr.getJSONArray(i));
                int mukey = JSONUtils.getIntParam(mu, "mukey", 0);
                ArrayList<Component> componentList = new ArrayList<>();

                JSONArray compArr = JSONUtils.getJSONArrayParam(mu, "Cokey List");
                for (int j = 0; j < compArr.length(); j++) {
                    Map<String, JSONObject> comp = JSONUtils.preprocess(compArr.getJSONArray(j));
                    int cokey = JSONUtils.getIntParam(comp, "cokey", 0);
                    componentList.add(new Component(cokey));
                }
                mapunitList.add(new MapUint(mukey, componentList));
            }
        } catch (JSONException ex) {
            throw new ServiceException(ex);
        }
    }

    @Override
    public void doProcess() throws ServiceException {
        retrieveData();
        try {
            generateSoilFiles();
        } catch (FileNotFoundException ex) {
            throw new ServiceException(ex);
        }
    }

    @Override
    public void postProcess() throws ServiceException {
        JSONArray mapunitArray = new JSONArray();
        try {
            for (MapUint mapuint : mapunitList) {
                JSONArray mapunitArr = new JSONArray();
                mapunitArr.put(JSONUtils.dataDesc("mukey", mapuint.mukey, "Soil Mapunit Key"));
                mapunitArr.put(JSONUtils.dataDesc("muname", mapuint.muname, "Soil Mapunit Name"));

                JSONArray componentArray = new JSONArray();
                for (Component component : mapuint.componentList) {
                    JSONArray componentArr = new JSONArray();
                    componentArr.put(JSONUtils.dataDesc("cokey", component.cokey, "Soil Component Key"));
                    componentArr.put(JSONUtils.dataDesc("compname", component.compname, "Soil Component Name"));
                    componentArr.put(JSONUtils.dataDesc("taxorder", component.taxorder, "Soil Taxonomic Order"));

                    JSONArray horizonArray = new JSONArray();
                    for (Horizon horizon : component.horizonList) {
                        JSONArray horizonArr = new JSONArray();
                        horizonArr.put(JSONUtils.data("chkey", horizon.chkey));
                        horizonArr.put(JSONUtils.data("hzdept_r", horizon.hzdept_r));
                        horizonArr.put(JSONUtils.data("wthirdbar_r", horizon.wthirdbar_r));
                        horizonArr.put(JSONUtils.data("wfifteenbar_r", horizon.wfifteenbar_r));
                        horizonArr.put(JSONUtils.data("sandtotal_r", horizon.sandtotal_r));
                        horizonArr.put(JSONUtils.data("claytotal_r", horizon.claytotal_r));
                        horizonArr.put(JSONUtils.data("ksat_r", horizon.ksat_r));
                        horizonArr.put(JSONUtils.data("om_r", horizon.om_r));
                        horizonArr.put(JSONUtils.data("hzdepb_r", horizon.hzdepb_r));
                        horizonArr.put(JSONUtils.data("ph", horizon.ph));
                        JSONArray textureArray = new JSONArray();
                        for (String texture : horizon.textureList) {
                            JSONArray textureArr = new JSONArray();
                            textureArr.put(JSONUtils.data("texcl", texture));
                            textureArray.put(textureArr);
                        }
                        horizonArr.put(JSONUtils.data("texture_class_list", textureArray));
                        horizonArray.put(horizonArr);
                    }
                    componentArr.put(JSONUtils.data("SOILS", horizonArray));
                    componentArray.put(componentArr);
                }
                mapunitArr.put(JSONUtils.data("Component List", componentArray));
                mapunitArray.put(mapunitArr);
            }
        } catch (JSONException ex) {
            throw new ServiceException(ex);
        }
        results().put("Mapunit List", mapunitArray);

    }

    public void retrieveData() throws ServiceException {
        try (Connection sdmConn = resources().getJDBC(SDM_REST);
                Statement statement = sdmConn.createStatement();) {
            for (MapUint mapunit : mapunitList) {
                try (ResultSet resultSet = statement.executeQuery(DBQueries.COMET02Query03(mapunit.mukey))) {
                    while (resultSet.next()) {
                        mapunit.setMuname(resultSet.getString("muname"));
                    }
                }
                for (Component component : mapunit.componentList) {
                    ArrayList<Horizon> horizonList = new ArrayList<>();
                    try (ResultSet resultset = statement.executeQuery(DBQueries.COMET02Query01(mapunit.mukey, component.cokey));) {
                        while (resultset.next()) {
                            component.setCompname(resultset.getString("compname"));
                            component.setTaxorder(resultset.getString("taxorder"));

                            int chkey = resultset.getInt("chkey");
                            int hzdept_r = resultset.getInt("hzdept_r");
                            int hzdepb_r = resultset.getInt("hzdepb_r");
                            double wthirdbar_r = resultset.getDouble("wthirdbar_r");
                            double wfifteenbar_r = resultset.getDouble("wfifteenbar_r");
                            double sandtotal_r = resultset.getDouble("sandtotal_r") / 100;
                            double claytotal_r = resultset.getDouble("claytotal_r") / 100;
                            double om_r = resultset.getDouble("om_r") / 100;
                            double ksat_r = resultset.getDouble("ksat_r");
                            double bulkdensity = computeBulkDensity(sandtotal_r, claytotal_r);
                            double ph = resultset.getDouble("ph1to1h2o_r");

                            horizonList.add(new Horizon(chkey, hzdept_r, hzdepb_r, bulkdensity,
                                    wthirdbar_r, wfifteenbar_r, sandtotal_r,
                                    claytotal_r, om_r, ksat_r, ph));
                        }
                        component.setHorizonList(horizonList);
                    }
                }
                for (Component component : mapunit.componentList) {
                    for (Horizon horizon : component.horizonList) {
                        try (ResultSet resultSet = statement.executeQuery(DBQueries.COMET02Query02(horizon.chkey))) {
                            ArrayList<String> textureList = new ArrayList<>();
                            while (resultSet.next()) {
                                textureList.add(resultSet.getString("texcl"));
                            }
                            horizon.setTexture(textureList);
                        }
                    }
                }
            }
        } catch (SQLException ex) {
            throw new ServiceException(ex);
        }
    }

    public double computeBulkDensity(double sand_fraction, double clay_fraction) {
        double sat = 0.332 - 0.0007251 * sand_fraction + 0.1276 * Math.log(clay_fraction / 100) / Math.log(10);
        double bulkDensity = (1.0 - sat) * 2.65;
        bulkDensity = bulkDensity + (-0.08 * bulkDensity);
        bulkDensity = (double) Math.round(bulkDensity * 1000000) / 1000000;
        return bulkDensity;
    }

    public void generateSoilFiles() throws ServiceException, FileNotFoundException {
        for (MapUint mapunit : mapunitList) {
            for (Component component : mapunit.componentList) {
                String fileName = "SOIL_" + mapunit.mukey + "_" + component.cokey + ".IN";
                try (PrintWriter writer = new PrintWriter(new File(getWorkspaceDir(), fileName));) {
                    for (Horizon horizon : component.horizonList) {
                        writer.print(String.format("%-7s", horizon.hzdept_r));
                        writer.print(String.format("%-7s", horizon.hzdepb_r));
                        writer.print(String.format("%-12s", horizon.bulkDensity));
                        writer.print(String.format("%-22s", horizon.wthirdbar_r));
                        writer.print(String.format("%-22s", horizon.wfifteenbar_r));
                        writer.print(String.format("%-5s", "?"));
                        writer.print(String.format("%-5s", "?"));
                        writer.print(String.format("%-22s", horizon.sandtotal_r));
                        writer.print(String.format("%-22s", horizon.claytotal_r));
                        writer.print(String.format("%-22s", horizon.om_r));
                        writer.print(String.format("%-5s", "?"));
                        writer.print(String.format("%-22s", horizon.ksat_r));
                        writer.print(String.format("%-5s", horizon.ph));
                        writer.println();
                    }
                }
            }
        }
    }

    class MapUint {

        protected int mukey;
        protected String muname;
        protected ArrayList<Component> componentList;

        public MapUint(int mukey, ArrayList<Component> compList) {
            this.mukey = mukey;
            componentList = compList;
        }

        public void setMuname(String muname) {
            this.muname = muname;
        }
    }

    class Component {

        protected int cokey;
        protected String compname;
        protected String taxorder;

        protected ArrayList<Horizon> horizonList;

        public Component(int cokey) {
            this.cokey = cokey;
            horizonList = new ArrayList<>();
        }

        public void setCompname(String value) {
            compname = value;
        }

        public void setTaxorder(String value) {
            taxorder = value;
        }

        public void setHorizonList(ArrayList<Horizon> value) {
            horizonList = value;
        }
    }

    class Horizon {

        protected int chkey;
        protected int hzdept_r; //layer_top
        protected int hzdepb_r; //layer_bottom
        protected double bulkDensity;
        protected double wthirdbar_r; //field_capacity
        protected double wfifteenbar_r; //wilting_point
        protected double sandtotal_r; //sandtotal_r/100 As sand_fraction
        protected double claytotal_r;//chorizon.claytotal_r/100 As clay_fraction
        protected double om_r; //om_r/100 As om_fraction
        protected double ksat_r;
        protected double ph;
        protected ArrayList<String> textureList;

        public Horizon(int chkey, int hzdept_r, int hzdepb_r, double bulkDensity, double wthirdbar_r,
                double wfifteenbar_r, double sandtotal_r, double claytotal_r,
                double om_r, double ksat_r, double ph) {
            this.chkey = chkey;
            this.hzdept_r = hzdept_r;
            this.hzdepb_r = hzdepb_r;
            this.bulkDensity = bulkDensity;
            this.wthirdbar_r = wthirdbar_r;
            this.wfifteenbar_r = wfifteenbar_r;
            this.sandtotal_r = sandtotal_r;
            this.claytotal_r = claytotal_r;
            this.om_r = om_r;
            this.ksat_r = ksat_r;
            this.ph = ph;
        }

        public void setTexture(ArrayList<String> texture) {
            this.textureList = texture;
        }

    }

}