SOLFile.java [tools/MetaModelTools/src/data/interpretors] Revision: f13b17137cf09777c558d6fb6a492f8e12884fb8  Date: Wed Dec 11 10:22:48 MST 2019
/*
 * $Id$
 *
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * a Model-as-a-Service framework, API, and application suite.
 *
 * 2012-2019, 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 data.interpretors;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author <a href="mailto:shaun.case@colostate.edu">Shaun Case</a>
 */
public class SOLFile {

    private static final Logger LOGGER = Logger.getLogger(IFCFile.class.getName());
    //Logs for errors and warnings.

    private String errorsInSolFile = "";	// list of variables adjusted on output
    public String comments = "";

    //File Line 4 values
    public String soilName; // a) soil name for current OFE or channel - character (slid)
    public String soilTexture; // b) soil texture for current OFE or channel - character (texid)
    public int numLayers; // c) number of soil layers for current OFE or channel - integer (nsl)
    public double salb; // d) albedo of the bare dry surface soil on the current OFE or channel - real (salb)
    public double sat; // e) initial saturation level of the soil profile porosity (m/m) - real (sat)
    public double ki; // f) baseline interrill erodibility parameter (kg*s/m4) - real (ki)
    public double kr; // g) baseline rill erodibility parameter (s/m) - real (kr)
    public double shcrit; // h) baseline critical shear parameter (N/m2) - real (shcrit)
    public double avke; // i) effective hydraulic conductivity of surface soil (mm/h) - real (avke)    

    //File starting line 5 values for each horizon/layer
    public double[] solthk; // a) depth from soil surface to bottom of soil layer (mm) - real (solthk)
    public double[] sand; // b) percentage of sand in the layer (%) - real (sand)
    public double[] clay; // c) percentage of clay in the layer (%) - real (clay)
    public double[] orgmat; // d) percentage of organic matter (volume) in the layer (%) - real (orgmat)
    public double[] cec; // e) cation exchange capacity in the layer (meq/100 g of soil) - real (cec)
    public double[] rfg; // f) percentage of rock fragments by volume in the layer (%) - real (rfg)

    //File last line values:  Bedrock restricting layer info (Most of the soils are not going to have any bedrock layer defined so this line ends up being all 0's)
    public int restrictingFlag; // a) flag to indicate if present
    public int restrictingType; // b) type
    public double anisotropyRatio; // c) anisotropy ratio
    public double ksat; // d) ksat    

    public SOLFile(String fileData) throws IOException {
        readSol(fileData);
    }

    /**
     * ********************************************************************************************************
     */
    /* reads line from file skipping comments */
    private String readLine(BufferedReader inpf) {
        String line;
        try {
            line = inpf.readLine();
        } catch (IOException e) {
            return null;
        }
        if (line == null || line.length() == 0) {
            return null;
        }

        return line;
    }

    // Sol file description
    // Line 1:  version control number (95.7) - real (datver)
    // Line 2:  a) User comment line - character*80, (solcom)
    // Line 3:  a) number of overland flow elements(OFE's) or channels integer (ntemp)
    //          b) flag to to use internal hydraulic conductivity adjustments - integer (ksflag)
    //              0 - do not use adjustments (conductivity will be held constant)
    //              1 - use internal adjustments
    //           [ALWAYS "1 1" if generated by us...
    //      Lines 4 & 5 are repeated for the number of OFE's or channels on Line 3a.
    // Line 4:  a) soil name for current OFE or channel - character (slid)
    //          b) soil texture for current OFE or channel - character (texid)
    //          c) number of soil layers for current OFE or channel - integer (nsl)
    //          d) albedo of the bare dry surface soil on the current OFE or channel - real (salb)
    //          e) initial saturation level of the soil profile porosity (m/m) - real (sat)
    //          f) baseline interrill erodibility parameter (kg*s/m4) - real (ki)
    //          g) baseline rill erodibility parameter (s/m) - real (kr)
    //          h) baseline critical shear parameter (N/m2) - real (shcrit)
    //          i) effective hydraulic conductivity of surface soil (mm/h) - real (avke)
    // Line 5: (repeated for the number of soil layers indicated on Line 4c.)
    //          a) depth from soil surface to bottom of soil layer (mm) - real (solthk)
    //          b) percentage of sand in the layer (%) - real (sand)
    //          c) percentage of clay in the layer (%) - real (clay)
    //          d) percentage of organic matter (volume) in the layer (%) - real (orgmat)
    //          e) cation exchange capacity in the layer (meq/100 g of soil) - real (cec)
    //          f) percentage of rock fragments by volume in the layer (%) - real (rfg)
    // Line 6: Bedrock restricting layer info (Most of the soils are not going to have any bedrock layer defined so this line ends up being all 0's)
    //          a) flag to indicate if present
    //          b) type
    //          c) anisotropy ratio
    //          d) ksat    
    private void readNewSol(BufferedReader inpf) throws IOException {
        try {
            //Should now be starting with line 4:
            String line4 = readLine(inpf);
            String[] line4Parts = line4.trim().split(" ");
            if (line4Parts.length != 9) {
                throw new IOException("SOL file does not contain a valid line 4.  Expected 9 values on line 4 but found " + line4Parts.length);
            }

            //  Read initial data about soil
            soilName = line4Parts[0];
            soilTexture = line4Parts[1];
            numLayers = Integer.parseInt(line4Parts[2]);
            salb = Double.parseDouble(line4Parts[3]);
            sat = Double.parseDouble(line4Parts[4]);
            ki = Double.parseDouble(line4Parts[5]);
            kr = Double.parseDouble(line4Parts[6]);
            shcrit = Double.parseDouble(line4Parts[7]);
            avke = Double.parseDouble(line4Parts[8]);

            solthk = new double[numLayers];
            sand = new double[numLayers];
            clay = new double[numLayers];
            orgmat = new double[numLayers];
            cec = new double[numLayers];
            rfg = new double[numLayers];
            //  Read each soil horizon/layer present in file
            for (int i = 0; i < numLayers; i++) {
                String horizonLine = readLine(inpf);

                if ((null != horizonLine) && (!horizonLine.isEmpty())) {
                    String[] lineParts = horizonLine.trim().split(" ");

                    if (lineParts.length != 6) {
                        throw new IOException("Invlalid horizon line found in SOL file on line " + (5 + i)
                                + ".  Line does not contain 6 values as expected, but has " + lineParts.length + " values instead.");
                    }

                    solthk[i] = Double.parseDouble(lineParts[0]);
                    sand[i] = Double.parseDouble(lineParts[1]);
                    clay[i] = Double.parseDouble(lineParts[2]);
                    orgmat[i] = Double.parseDouble(lineParts[3]);
                    cec[i] = Double.parseDouble(lineParts[4]);
                    rfg[i] = Double.parseDouble(lineParts[5]);

                } else {
                    throw new IOException("Invalid horizon line found in SOL file on line " + (5 + i) + ".");
                }

            }

            //  Now read bedrock line
            String bedrockLine = readLine(inpf);
            if ((null != bedrockLine) && (!bedrockLine.isEmpty())) {
                String[] lineParts = bedrockLine.trim().split(" ");
                if (lineParts.length != 4) {
                    throw new IOException("SOL file does not contain a valid bedrock line.  Expected 4 values on line 4 but found " + lineParts.length);
                }

                restrictingFlag = Integer.parseInt(lineParts[0]);
                restrictingType = Integer.parseInt(lineParts[1]);
                anisotropyRatio = Double.parseDouble(lineParts[2]);
                ksat = Double.parseDouble(lineParts[2]);
                
            } else {
                throw new IOException("No bedrock line found in this SOL file.");
            }

        } finally {
            try {
                inpf.close();
            } catch (IOException e) {
                LOGGER.log(Level.SEVERE, "Unable to close soil input stream.", e);
            }
        }
        //System.out.println(errorsInSolFile);
    }

    /**
     *
     * @param fileData
     * @throws java.io.IOException
     */
    /* reads ifc file */
    private void readSol(String fileData) throws IOException {
        BufferedReader inpf;
        inpf = new BufferedReader(new StringReader(fileData));

        String firstLine = readLine(inpf);
        if (firstLine.startsWith("2006.2")) {
            comments = readLine(inpf);
            if ((null != comments) && (!comments.isEmpty())) {
                comments = comments.replace("Comments:", "").trim();
            }
            String line3 = readLine(inpf);
            if (null != line3) {
                line3 = line3.trim();
                if (!line3.equalsIgnoreCase("1 1")) {
                    throw new IOException("Invalid SOL File.  Line 3 shold be '1 1' but is: " + line3);
                }
            }
            readNewSol(inpf);
        } else {
            throw new IOException("Invalid SOL File.  Version tag not found or does not match '2006.2'");
        }
    }

}