SOLFile.java [tools/MetaModelTools/src/data/interpretors] Revision: ec5f4cade4553a8341e1cd241b111bfdb77a87a8  Date: Fri Jan 10 10:59:55 MST 2020
/*
 * $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'");
    }
  }

}