IFC.java [tools/WepsSoilsIfcCreator/src/usda/weru/soil] Revision: 0963adc11caf5d7616128736008ebbc7f276df4c  Date: Wed Sep 02 15:16:53 MDT 2015
package usda.weru.soil;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.awt.*;
import java.util.*;

//import java.lang.*;
import java.text.*;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import java.beans.*;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import usda.weru.util.*;

public class IFC // extends Records
        
{
    private static final Logger LOGGER = Logger.getLogger(IFC.class.getName()); 
    //Logs for errors and warnings.
    WepsMessageLog c_log = new WepsMessageLog();
    
//    String	filnam = null;	// file name for ifc data
//    String	inpnam = null;
    String	errorsInIfcFile = "";	// list of variables adjusted on output
    String	mySavedFilename = null;
    
// defintion for identifying info
    
    static final	int	MaxInfo = 11;
    
    public String	state = "state";				// state
    public String	county = "county";			// county
    public String	soilSurveyAreaName = "survey name";			// soil survey area name
    public String	soilSurveyID = "survey ID";			// soil surver ID
    public String	mapUnitSymbol = "map symbol";			// Map Unit Sysmbol
    public String	componentName = "component name";				// Component name
    public String	componentPercent = "component percent";				// component percent
    public String	taxOrder = "tax order";			// taxorder
    public int		nsl;			// number of soil layers
    public String	surfaceTexture = "surface texture";			// surface texture
    public String	localPhase = "local phase";		//
    public int		soilLossTolerance			= 0;
    
// defintion for surface characteristics
    
    public final	int	MaxSurf = 16;
    public double	crustThickness = 0.01;			// sct - soil crust thickness
    public double	crustDensity = Double.NaN;			// scd - soil crust density
    public double	crustStability = Double.NaN;			// scs - soil crust stability
    public double	crustFraction = 0;		// scf - soil crust fraction
    public double	crustLooseMaterialMass = 0;			// lmcm - loose material on crust - mass
    public double	crustLooseMaterialFraction = 0;			// lmcf - loose material on crust - fraction
    public double	randomRoughness = 4.0;				// rr - random roughness
    public double	roughnessOrientation = 0;				// ro - roughness orientation
    public double	roughnessHeight = 0;				// rh - roughness height
    public double	roughnessSpacing = 10.0;				// rs - roughness spacing
    public double	roughnessWidth = 10.0;				// rw - roughness width
    public double	surfaceAlbedo = Double.NaN;				// sa - soil albedo
    //A negative slope is ignored by weps.
    public double	surfaceSlope = -1;				// ss - soil slope
    public double	surfaceFragmentCover	= 0;
    public double	bedrockDepth			= 9999;
    public double	impermiableDepth	= 9999;
//	double	waterTableDepth		= 1000000;
    
    // array of surface variables to interface with grid12
//	double	survar[] = {sct, scd, scs, scf, lmcm, lmcf, rr,ro,rh,rs,rw,cng,cnp,sa,cns,crh,crsd,crsf};
    
//  definition for ifc layers
    
    static final	int	MaxLayr = 30;
    public double	layerThickness[];			// thickness in mm
    public double	layerDepthBottom[];		// depth of bottom of layer
    public double	layerDepthTop[];		// depth of top of layer
    public double	fractionSand[];			// % sand
    public double	fractionSilt[];			// % silt
    public double	fractionClay[];			// % clay
    public double	fractionRock[];			// rock %
    public double	veryCoarseSandFraction[];			// sand fraction coarse
    public double	coarseSandFraction[];			// sand fraction coarse
    public double	mediumSandFraction[];			// sand fraction medium
    public double	fineSandFraction[];			// sand fraction fine
    public double	veryFineSandFraction[];			// sand fraction very find
//	double	waterDispersableClay[];			// water dispersible clay
    public double	dryBulkDensity[];		// bulk density dry
    public double	initialBulkDensity[];		// initial density dry
    public double	wetBulkDensity[];			// bulk density 1/3 bar
    public double	aggregateMeanDiameter[];		// aggregate mean diameter
    public double	aggregateStdDeviation[];		// aggregate standard deviation
    public double	maxAggregateSize[];		// max aggregate size
    public double	minAggregateSize[];		// min aggregate size
    public double	aggregateDensity[];		// aggregate density
    public double	aggregateStability[];		// aggregate stability
    public double	initialSWC[];			// initial soil water content (swc)
    public double	saturatedSWC[];			// saturated swc
    public double	fieldCapacitySWC[];			// field capacity swc
    public double	wiltingPointSWC[];			// wilting point swc
    public double	tenthBarSWC[];			// 0.1 bar on sand soil
    public double	soilCB[];			// soil CB
    public double	airEntryPotential[];			// air entry potential
    public double	saturatedHydraulicConductivity[];			// sat hydraulic conductivity
    public double	organicMaterial[];			// organic matter
    public double	soilpH[];			// soil pH
    public double	calciumCarbonateEquivalent[];		// calcium carbonate equiv
    public double	cationExchangeCapacity[];			// cation exchange capacity
    public double	linearExtensibility[];			// linear extensibility
    
    private	boolean	interact = false;
    
    /********************************************************************** wjr */
    
    public IFC() {
    }
    
    /********************************************************************** wjr */
    
    IFC(int inpnsl) {
        initIfc(inpnsl);
    }
    
    /********************************************************************** wjr */
    
    IFC(NASIS nasinp) {
        Util.debugPrint(true, nasinp.compname);
        errorsInIfcFile = nasinp.errIncFile;
        nsl = nasinp.adjlay;
        copyNasData(nasinp);
        convertUnits();
        calculateFactors();
        ER_crustLooseMaterialFraction.setHighValue(crustFraction);
        ER_crustFraction.setLowValue(crustLooseMaterialFraction);
        //System.out.println("IFC_IFC num_lay: " + nsl + errorsInIfcFile);
        
    }
    
    
    /********************************************************************** wjr */
    
    
    public void sendErrorsToInternalVariable(){
        for(WepsMessage message : c_log.getMessages(WepsMessage.MessageSeverity.ERROR, WepsMessage.MessageSeverity.WARNING)){
            errorsInIfcFile += "# " + message.toString();
            if(!errorsInIfcFile.endsWith("\n")) {
                errorsInIfcFile += "\n";
            }
        }
    }
    
    private void initIfc(int inpnsl) {
        
        nsl = inpnsl;
        
        double[] tmpArr = new double[inpnsl];
        for (int idx = 0; idx < inpnsl; idx++) {
            tmpArr[idx] = Double.NaN;
            //tmpArr[idx] = 0;
        }
        
// create layer arrays
//	layerDepthTop = new double[inpnsl];			// depth to top of layer
        layerDepthTop = (double[]) tmpArr.clone();			// depth to top of layer
        layerDepthBottom = (double[]) tmpArr.clone();			// depth to bottom of layer
        layerThickness = (double[]) tmpArr.clone();			// thickness in mm
        fractionSand = (double[]) tmpArr.clone();			// % sand
        fractionSilt = (double[]) tmpArr.clone();			// % silt
        fractionClay = (double[]) tmpArr.clone();			// % clay
        fractionRock = (double[]) tmpArr.clone();			// rock %
        veryCoarseSandFraction = (double[]) tmpArr.clone();			// sand fraction coarse
        coarseSandFraction = (double[]) tmpArr.clone();			// sand fraction coarse
        mediumSandFraction = (double[]) tmpArr.clone();			// sand fraction medium
        fineSandFraction = (double[]) tmpArr.clone();			// sand fraction fine
        veryFineSandFraction = (double[]) tmpArr.clone();			// sand fraction very find
        dryBulkDensity = (double[]) tmpArr.clone();			// bulk density dry
        initialBulkDensity = (double[]) tmpArr.clone();			// bulk density dry
        wetBulkDensity = (double[]) tmpArr.clone();			// bulk density 1/3 bar
        aggregateMeanDiameter = (double[]) tmpArr.clone();			// aggregate mean diameter
        aggregateStdDeviation = (double[]) tmpArr.clone();			// aggregate standard deviation
        maxAggregateSize = (double[]) tmpArr.clone();		// max aggregate size
        minAggregateSize = (double[]) tmpArr.clone();		// min aggregate size
        aggregateDensity = (double[]) tmpArr.clone();		// aggregate density
        aggregateStability = (double[]) tmpArr.clone();		// aggregate stability
        initialSWC = (double[]) tmpArr.clone();			// initial soil water content (swc)
        saturatedSWC = (double[]) tmpArr.clone();			// saturated swc
        fieldCapacitySWC = (double[]) tmpArr.clone();			// field capacity swc
        wiltingPointSWC = (double[]) tmpArr.clone();			// wilting point swc
        tenthBarSWC = (double[]) tmpArr.clone();			// 0.1 bar on sand soil
        soilCB = (double[]) tmpArr.clone();			// soil CB
        airEntryPotential = (double[]) tmpArr.clone();			// air entry potential
        saturatedHydraulicConductivity = (double[]) tmpArr.clone();			// sat hydraulic conductivity
        organicMaterial = (double[]) tmpArr.clone();			// organic matter
        soilpH = (double[]) tmpArr.clone();			// soil pH
        calciumCarbonateEquivalent = (double[]) tmpArr.clone();			// calcium carbonate equiv
        cationExchangeCapacity = (double[]) tmpArr.clone();			// cation exchange capacity
        linearExtensibility = (double[]) tmpArr.clone();			// linear extensibility
        
    }
    
    
    /***********************************************************************************************************/
    
    private void writeArray(PrintWriter outprt, String nam, double arr[], int numdig) {
        
        outprt.println("# " + nam);
//	for (int ldx = 0 ; ldx < arr.length ; ldx++)
        for (int ldx = 0 ; ldx < nsl; ldx++) {	// check to make sure nsl is correct
            if (Double.isNaN(arr[ldx])) {
                System.out.println("#" + nam + "=NaN");
                throw new ArithmeticException("Soil property not found in one or more layers - " + nam);
            }
            System.out.println("#" + nam + "=" + Util.formatDouble(arr[ldx],numdig));
            outprt.print(Util.formatDouble(arr[ldx],numdig) + "     ");
        }
        outprt.println();
    }
    
    /***********************************************************************************************************/
    
    private void writeValue(PrintWriter outprt, String nam, double val, int numdig) {
        outprt.println("# " + nam);
        if (Double.isNaN(val)) {
            throw new ArithmeticException("Soil property not found in one or more layers - " + nam);
        }
        outprt.println(Util.formatDouble(val,numdig));
    }
    
    /***********************************************************************************************************/
    
    private void writeValue(PrintWriter outprt, String nam, int val) {
        outprt.println("# " + nam);
        outprt.println(val);
    }
    
    /***********************************************************************************************************/
    
    private void writeValue(PrintWriter outprt, String nam, String val) {
        outprt.println("# " + nam);
        outprt.println(val);
    }
    
    /**
     *
     * @return
     */
    
    public String getFileName() {
        StringBuffer filnam = new StringBuffer();
        filnam.append(componentName).append("_");
        filnam.append(mapUnitSymbol).append("_");
        filnam.append(componentPercent).append("_");
        filnam.append(surfaceTexture);
        return filnam.toString();
    }
    
    /**
     *
     * @param path
     * @param changes
     */
    /* private void writeIfc() */
    
    public void writeNewIfc(String path, PropertyChangeSupport changes) throws ArithmeticException {
        
        /* String loadFilename = new String(componentName + "_" + mapUnitSymbol + "_" + componentPercent + "_" + surfaceTexture);
         
        //System.out.println("i_wIFC-2: " + dir + " Initial SoilFile :" + loadFilename );
         
        String filnam1 = loadFilename.replace('\'', '_');
        String filnam = filnam1.replace('\"', '_'); */
        // ========================================================
//	String filnam = new String(componentName + "_" + mapUnitSymbol + "_" + componentPercent + "_" + surfaceTexture);
        if (new File(path).isDirectory()) {
            StringBuffer filnam = new StringBuffer();
            filnam.append(componentName).append("_");
            filnam.append(mapUnitSymbol).append("_");
            filnam.append(componentPercent).append("_");
            filnam.append(surfaceTexture);
            
            for (int idx = 0; idx < filnam.length(); idx++){
                if (!Character.isLetterOrDigit(filnam.charAt(idx))) filnam.setCharAt(idx, '_');
            }
            path = new File(path).getAbsolutePath().concat(java.io.File.separator).concat(filnam.toString());
            //path = new File(path).getAbsolutePath().concat("\\").concat(filnam.toString());
            //writeNewIfc(new File(path).getAbsolutePath());
        }
//	try {
        writeNewIfc(path);
//	} catch (java.lang.ArithmeticException e) {
//		return;
//	}
        
        
        try {
            if (!path.endsWith(".ifc")) {
                path += ".ifc";
            }
            if (changes != null) 
            {
                // this used to fire a property change event
//                changes.firePropertyChange(usda.weru.weps.RunFileData.SoilFile,
//                    null,
//                    new File(path).getCanonicalPath());                
            }       
//        } catch (IOException e) {
        } catch (Exception e) {            
        }
    }
    
    /***********************************************************************************************************/
    
    private	String	writeNotes() {
        StringTokenizer st = new StringTokenizer(errorsInIfcFile, "\n");

        StringBuffer sb = new StringBuffer("# Notes:\n");
        while (st.hasMoreTokens()) {
            sb.append("# " + st.nextToken() + "\n");
        }
        
        return sb.toString();
    }
    
    /**
     *
     * @param filePath
     */
    /* private void writeNewIfc() */
    
//public void writeIfc(String dir, String filnam)
    public boolean writeNewIfc(String filePath) throws ArithmeticException {
        
        //System.out.println("IFC_wNI: " + filePath);
//	try {
        
// grid is commented out - this is GUI related        
//        updateRecordFromGrid();
//	} catch(NullPointerException f) {
//		Util.debugPrint(true, f.toString());
//		f.printStackTrace();
//	}
        
//	try {
        adjustIfc();
//	} catch(NullPointerException f) {
//		Util.debugPrint(true, f.toString());
//		f.printStackTrace();
//	}
        
//	try {
        if (chkSoilandSandPcts()) {  
            System.err.println("Output file not writtem: Error in soil or sand fractions.");
//            JOptionPane.showMessageDialog(new JPanel(),
//                    "Output file not written",
//                    "Error in soil or sand fractions", JOptionPane.ERROR_MESSAGE);
            errorsInIfcFile = "";
            return false;
        }
//	} catch(NullPointerException f) {
//		Util.debugPrint(true, f.toString());
//		f.printStackTrace();
//	}
        
        PrintWriter outprt = null;
        
        try {
            
            if (!filePath.endsWith(".ifc")){
                filePath += ".ifc";
            }
            
            outprt = new PrintWriter(new FileWriter(new File(filePath)));
            
            outprt.println("Version: 1.0");
            outprt.println("#");
            outprt.println("# Soil ID");
            outprt.println(soilSurveyID + "-" + mapUnitSymbol + "-" + componentName + "-" + componentPercent + "-" + surfaceTexture +
                    "-" + state + "-" + county + "-" + soilSurveyAreaName);
            outprt.println("#");
            
            writeValue(outprt, idList[9].title, localPhase);  // local phase
            writeValue(outprt, idList[8].title, taxOrder);  // tax order
            
            writeValue(outprt, idList[11].title,soilLossTolerance);
            writeValue(outprt, surfaceList[12].title,surfaceAlbedo, 3);
            writeValue(outprt, surfaceList[13].title,surfaceSlope, 3);
            writeValue(outprt, surfaceList[14].title,surfaceFragmentCover, 3);
            
            outprt.println("#");
            writeValue(outprt, surfaceList[15].title, bedrockDepth,   0 );
            writeValue(outprt, surfaceList[16].title, impermiableDepth, 0);
            outprt.println("#");
            
            writeValue(outprt, layerList[0].title, nsl);  // number of layers
            writeArray(outprt, layerList[1].title,layerThickness,0);  // soil characteristics by layer
            outprt.println("#");
            
            writeArray(outprt,layerList[3].title,fractionSand,3);				// soil fractions
            writeArray(outprt,layerList[4].title,fractionSilt,3);
            writeArray(outprt,layerList[5].title,fractionClay,3);
            writeArray(outprt,layerList[6].title,fractionRock,3);
            writeArray(outprt,layerList[7].title,veryCoarseSandFraction,3);
            writeArray(outprt,layerList[8].title,coarseSandFraction,3);
            writeArray(outprt,layerList[9].title,mediumSandFraction,3);
            writeArray(outprt,layerList[10].title,fineSandFraction,3);
            writeArray(outprt,layerList[11].title,veryFineSandFraction,3);
            outprt.println("#");
            
            writeArray(outprt,layerList[12].title,wetBulkDensity,3);
            writeArray(outprt,layerList[2].title,organicMaterial,4);				// soil chemical properties
            writeArray(outprt,layerList[27].title,soilpH,2);
            writeArray(outprt,layerList[28].title,calciumCarbonateEquivalent,2);
            writeArray(outprt,layerList[29].title,cationExchangeCapacity,2);
            writeArray(outprt,layerList[30].title,linearExtensibility, 3);
            outprt.println("#");
            
            writeArray(outprt,layerList[14].title,aggregateMeanDiameter,3);	// aggregate characteristics
            writeArray(outprt,layerList[15].title,aggregateStdDeviation,3);
            writeArray(outprt,layerList[16].title,maxAggregateSize,3);
            writeArray(outprt,layerList[17].title,minAggregateSize,3);
            writeArray(outprt,layerList[18].title,aggregateDensity,3);
            writeArray(outprt,layerList[19].title,aggregateStability,3);
            outprt.println("#");
            
            writeValue(outprt, surfaceList[1].title,crustThickness, 3);  // crust and surface characteristics
            writeValue(outprt, surfaceList[2].title,crustDensity, 3);
            writeValue(outprt, surfaceList[3].title,crustStability, 2);
            writeValue(outprt, surfaceList[4].title,crustFraction, 2);
            writeValue(outprt, surfaceList[5].title,crustLooseMaterialMass, 2);
            writeValue(outprt, surfaceList[6].title,crustLooseMaterialFraction, 2);
            outprt.println("#");
            
            writeValue(outprt, surfaceList[7].title,randomRoughness, 2);
            writeValue(outprt, surfaceList[8].title,roughnessOrientation, 2);
            writeValue(outprt, surfaceList[9].title,roughnessHeight, 2);
            writeValue(outprt, surfaceList[10].title,roughnessSpacing, 2);
            writeValue(outprt, surfaceList[11].title,roughnessWidth, 2);
            outprt.println("#");
            
            writeArray(outprt,layerList[13].title,initialBulkDensity,3);  // hydrology by layers
            writeArray(outprt,layerList[20].title,initialSWC,3);  // hydrology by layers
            writeArray(outprt,layerList[21].title,saturatedSWC,3);
            writeArray(outprt,layerList[22].title,fieldCapacitySWC,3);
            writeArray(outprt,layerList[23].title,wiltingPointSWC,3);
            outprt.println("#");
            
            writeArray(outprt,layerList[24].title,soilCB,3);
            writeArray(outprt,layerList[25].title,airEntryPotential,3);
            writeArray(outprt,layerList[26].title,saturatedHydraulicConductivity,10);
            outprt.println("#");
            
            outprt.println(writeNotes());
            outprt.close();
            return true;
//		errorsInIfcFile = "";
        } catch(IOException  e) {
            Util.debugPrint(true, e.toString());
            return false;
        } catch(NullPointerException f) {
            Util.debugPrint(true, f.toString());
            f.printStackTrace();
            return false;
        } catch (ArithmeticException g) {
            g.printStackTrace();
            System.err.println("Output file not written: NaN (not a number) attempted to be written to IFC file- file=" + filePath);
//            JOptionPane.showMessageDialog(new JPanel(),
//                    "NaN (not a number) attempted to be written to IFC file\n" + g.getMessage(),
//                    "Output file not written",
//                    JOptionPane.ERROR_MESSAGE);
            outprt.close();
            (new File(filePath)).delete();
            return false;
            //System.out.println("IFC_wF: not written before throw");
            //throw new ArithmeticException("File not Written, NAN error, Message cleared");
//		throw new Exception("File not Written, NAN error, Message cleared");
        }
    }
    
    /***********************************************************************************************************/
    /* 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;
        if (line.charAt(0) == '#') line = readLine(inpf);
        return line;
    }
    
    /***********************************************************************************************************/
    /* reads in a single double */
    
    private	double	readDouble(BufferedReader inpf) {
        String	line = readLine(inpf);
        return Double.valueOf(line.trim()).doubleValue();
    }
    
    /***********************************************************************************************************/
    /* reads in a line of doubles */
    
    private	double[]	readDoubles(BufferedReader inpf, int numlay) {
        double rtnval[] = new double[numlay];
        String line = readLine(inpf);
        java.util.StringTokenizer st = new java.util.StringTokenizer(line, " ");
        for (int ldx = 0; ldx < numlay; ldx++) {
            String dblstr = st.nextToken();
            rtnval[ldx] = Double.valueOf(dblstr.trim()).doubleValue();
        }
        return rtnval;
        
    }
    
    /***********************************************************************************************************/
    /* parse Soil ID line */
    private	void	prsSoilID(String inplin, boolean newFlg)
    
    {
        if (!newFlg) {
            if (!inplin.startsWith("Soil ID ")) return;
            inplin = inplin.substring(8);
        }
        soilSurveyID = inplin.substring(0,inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        mapUnitSymbol = inplin.substring(0,inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        componentName = inplin.substring(0,inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        componentPercent = inplin.substring(0,inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        surfaceTexture = inplin.substring(0,inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        state = inplin.substring(0,inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        county = inplin.substring(0,inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        soilSurveyAreaName = inplin.trim();
    }
    
    /***********************************************************************************************************/
    /* reads ifc file */
    private void	readNewIFC(BufferedReader inpf) {
        try{
            prsSoilID(readLine(inpf), true);

            localPhase = readLine(inpf);
            taxOrder = readLine(inpf);

    //	soilLossTolerance = Integer.valueOf(readLine(inpf).trim()).intValue();
            soilLossTolerance = Double.valueOf(readLine(inpf).trim()).intValue();
    //	soilLossTolerance = readDouble(inpf);
            surfaceAlbedo = readDouble(inpf);
            surfaceSlope = readDouble(inpf);
            surfaceFragmentCover = readDouble(inpf);

            bedrockDepth = readDouble(inpf);
            impermiableDepth = readDouble(inpf);

            nsl = Integer.valueOf(readLine(inpf).trim()).intValue();
            layerThickness = readDoubles(inpf, nsl);
            layerDepthTop = new double[nsl];
            layerDepthBottom = new double[nsl];

            fractionSand = readDoubles(inpf, nsl);
            fractionSilt = readDoubles(inpf, nsl);
            fractionClay = readDoubles(inpf, nsl);
            fractionRock = readDoubles(inpf, nsl);
            veryCoarseSandFraction = readDoubles(inpf, nsl);
            coarseSandFraction = readDoubles(inpf, nsl);
            mediumSandFraction = readDoubles(inpf, nsl);
            fineSandFraction = readDoubles(inpf, nsl);
            veryFineSandFraction = readDoubles(inpf, nsl);
            wetBulkDensity = readDoubles(inpf, nsl);
    //	dryBulkDensity = readDoubles(inpf, nsl);

            organicMaterial = readDoubles(inpf, nsl);
            soilpH = readDoubles(inpf, nsl);
            calciumCarbonateEquivalent = readDoubles(inpf, nsl);
            cationExchangeCapacity = readDoubles(inpf, nsl);
            linearExtensibility = readDoubles(inpf, nsl);

            aggregateMeanDiameter = readDoubles(inpf, nsl);
            aggregateStdDeviation = readDoubles(inpf, nsl);
            maxAggregateSize = readDoubles(inpf, nsl);
            minAggregateSize = readDoubles(inpf, nsl);
            aggregateDensity = readDoubles(inpf, nsl);
            aggregateStability = readDoubles(inpf, nsl);

            crustThickness = readDouble(inpf);
            crustDensity = readDouble(inpf);
            crustStability = readDouble(inpf);
            crustFraction = readDouble(inpf);
            crustLooseMaterialMass = readDouble(inpf);
            crustLooseMaterialFraction = readDouble(inpf);

            randomRoughness = readDouble(inpf);
            roughnessOrientation = readDouble(inpf);
            roughnessHeight = readDouble(inpf);
            roughnessSpacing = readDouble(inpf);
            roughnessWidth = readDouble(inpf);

            initialBulkDensity = readDoubles(inpf, nsl);
            initialSWC = readDoubles(inpf, nsl);
            saturatedSWC = readDoubles(inpf, nsl);
            fieldCapacitySWC = readDoubles(inpf, nsl);
            wiltingPointSWC = readDoubles(inpf, nsl);

            soilCB = readDoubles(inpf, nsl);
            airEntryPotential = readDoubles(inpf, nsl);
            saturatedHydraulicConductivity = readDoubles(inpf, nsl);

            //System.out.println("I_rIF:");
            try {
                while (true) {
                    String inpLin = inpf.readLine();
                    if (inpLin.charAt(0) != '#') continue;
                    if (inpLin.trim().equals("# Notes:")) continue;
                    errorsInIfcFile += inpLin.substring(1).trim() + '\n';
                }
            } catch (Exception e) {
            }
        }
        finally{
            try{
                inpf.close();
            }
            catch(Exception e){
                LOGGER.log(Level.SEVERE, "Unable to close soil input stream.", e);
            }
        }
        //System.out.println(errorsInIfcFile);
    }
    
    public void	readIfc(String fname) throws FileNotFoundException {
        readIfc(new File(fname));
    }
    
    /**
     *
     * @param fname
     * @throws java.io.FileNotFoundException
     */
    /* reads ifc file */
    
    public void	readIfc(File file) throws FileNotFoundException {
        BufferedReader inpf = null;
        inpf = new BufferedReader(new FileReader(file));
        
        String firstLine = readLine(inpf);
        if (firstLine.startsWith("Version")) {
            readNewIFC(inpf);
            return;
        }
        else{
            JOptionPane.showMessageDialog(new JPanel(),
                "Old format soil file cannot be read\nCreate new soil file",
                "Error - soil file not usable", JOptionPane.ERROR_MESSAGE);
            try{
                inpf.close();
            }
            catch(Exception e){
                LOGGER.log(Level.SEVERE, "Unable to close soil file: " + file.getAbsolutePath(), e);
            }
        }
        
        
        
    }
    
//    /***********************************************************************************************************/
//    
//    private	void	updateRecordFromGrid() {
//        
//        int col;
//        
//        if (GridID == null) {
//            return;
//        }
//        for (col = 1; col <= MaxInfo; col++) {
//            String label;
//            try {
//                label = GridID.getValue(0, col);
//            } catch (NullPointerException e) {
//                label = "Error " + col;
//            }
//            switch (col) {
//                case  1 : state = label; break;
//                case  2 : county = label; break;
//                case  3 : soilSurveyAreaName = label; break;
//                case  4 : soilSurveyID = label; break;
//                case  5 : mapUnitSymbol = label; break;
//                case  6 : componentName = label; break;
//                case  7 : componentPercent = label; break;
//                case  8 : taxOrder = label; break;
//                case  9 : localPhase = label; break;
//                case 10: surfaceTexture = label; break;
//                case 11: soilLossTolerance = Integer.valueOf(label.trim()).intValue(); break;
//            }
//        }
//        
//        for (col = 1; col <= MaxSurf; col++) {
//            String label;
//            try {
//                label = GridSurfProp.getValue(0, col);
//            } catch (NullPointerException e) {
//                label = "NaN";
//            }
//            double updval = 0;
//            updval = Double.valueOf(label.trim()).doubleValue();
//////System.out.println("IFC_uRFG: " + col + " " + label + " " + up);
//            switch(col) {
//                case  1: crustThickness = updval; break;
//                case  2: crustDensity = updval; break;
//                case  3: crustStability = updval; break;
//                case  4: crustFraction = updval; break;
//                case  5: crustLooseMaterialMass = updval; break;
//                case  6: crustLooseMaterialFraction = updval; break;
//                case  7: randomRoughness = updval; break;
//                case  8: roughnessOrientation = updval; break;
//                case  9: roughnessHeight = updval; break;
//                case 10: roughnessSpacing = updval; break;
//                case 11: roughnessWidth = updval; break;
//                case 12: surfaceAlbedo = updval; break;
//                case 13: surfaceSlope = updval; break;
//                case 14: surfaceFragmentCover = updval; break;
//                case 15: bedrockDepth = updval; break;
//                case 16: impermiableDepth = updval; break;
//            }
//        }
//        
//        Util.debugPrint(true, "nsl " + nsl);
//        
//        layerThickness = new double[nsl];			// thickness in mm
//        layerDepthTop =  new double[nsl];
//        layerDepthBottom =  new double[nsl];
//        fractionSand = new double[nsl];			// % sand
//        fractionSilt = new double[nsl];			// % silt
//        fractionClay = new double[nsl];			// % clay
//        fractionRock = new double[nsl];			// rock %
//        veryCoarseSandFraction = new double[nsl];			// sand fraction coarse
//        coarseSandFraction = new double[nsl];			// sand fraction coarse
//        mediumSandFraction = new double[nsl];			// sand fraction medium
//        fineSandFraction = new double[nsl];			// sand fraction fine
//        veryFineSandFraction = new double[nsl];			// sand fraction very find
//        dryBulkDensity = new double[nsl];		// bulk density dry
//        wetBulkDensity = new double[nsl];			// bulk density 1/3 bar
//        initialBulkDensity = new double[nsl];			// bulk density 1/3 bar
//        aggregateMeanDiameter = new double[nsl];		// aggregate mean diameter
//        aggregateStdDeviation = new double[nsl];		// aggregate standard deviation
//        maxAggregateSize = new double[nsl];		// max aggregate size
//        minAggregateSize = new double[nsl];		// min aggregate size
//        aggregateDensity = new double[nsl];		// aggregate density
//        aggregateStability = new double[nsl];		// aggregate stability
//        initialSWC = new double[nsl];			// initial soil water content (swc)
//        saturatedSWC = new double[nsl];			// saturated swc
//        fieldCapacitySWC = new double[nsl];			// field capacity swc
//        wiltingPointSWC = new double[nsl];			// wilting point swc
//        tenthBarSWC = new double[nsl];			// 0.1 bar on sand soil
//        soilCB = new double[nsl];			// soil CB
//        airEntryPotential = new double[nsl];			// air entry potential
//        saturatedHydraulicConductivity = new double[nsl];			// sat hydraulic conductivity
//        organicMaterial = new double[nsl];			// organic matter
//        soilpH = new double[nsl];			// soil pH
//        calciumCarbonateEquivalent = new double[nsl];		// calcium carbonate equiv
//        cationExchangeCapacity = new double[nsl];			// cation exchange capacity
//        linearExtensibility = new double[nsl];
//        
//        for (int row = 0; row < nsl; row++) {
//            for (col = 1; col <= MaxLayr; col++) {
//                String label;
//                try {
//                    label = GridLayrProp.getValue(row, col);
//                } catch (NullPointerException e) {
//                    label = "NaN";
//                }
//                double updval = Double.valueOf(label.trim()).doubleValue();
////			//System.out.print(GridLayrProp.getValue(row, col) + " ");
//                switch (col) {
//                    case  1 : layerThickness[row] = updval; break;			// thickness in mm
//                    case  2 : organicMaterial[row] = updval; break;			// organic matter
//                    case  3 : fractionSand[row] = updval; break;			// % sand
//                    case  4 : fractionSilt[row] = updval; break;			// % silt
//                    case  5 : fractionClay[row] = updval; break;			// % clay
//                    case  6 : fractionRock[row] = updval; break;			// rock %
//                    case  7 : veryCoarseSandFraction[row] = updval; break;			// sand fraction coarse
//                    case  8 : coarseSandFraction[row] = updval; break;			// sand fraction coarse
//                    case  9 : mediumSandFraction[row] = updval; break;			// sand fraction medium
//                    case 10 : fineSandFraction[row] = updval; break;			// sand fraction fine
//                    case 11 : veryFineSandFraction[row] = updval; break;			// sand fraction very find
////				case 12 : dryBulkDensity[row] = updval; break;		// bulk density dry
//                    case 12 : wetBulkDensity[row] = updval; break;			// bulk density 1/3 bar
//                    case 13 : initialBulkDensity[row] = updval; break;			// bulk density 1/3 bar
//                    case 14 : aggregateMeanDiameter[row] = updval; break;		// aggregate mean diameter
//                    case 15 : aggregateStdDeviation[row] = updval; break;		// aggregate standard deviation
//                    case 16 : maxAggregateSize[row] = updval; break;		// max aggregate size
//                    case 17 : minAggregateSize[row] = updval; break;		// min aggregate size
//                    case 18 : aggregateDensity[row] = updval; break;		// aggregate density
//                    case 19 : aggregateStability[row] = updval; break;		// aggregate stability
//                    case 20 : initialSWC[row] = updval; break;			// initial soil water content (swc)
//                    case 21 : saturatedSWC[row] = updval; break;			// saturated swc
//                    case 22 : fieldCapacitySWC[row] = updval; break;			// field capacity swc
//                    case 23 : wiltingPointSWC[row] = updval; break;			// wilting point swc
//                    case 24 : soilCB[row] = updval; break;			// soil CB
//                    case 25 : airEntryPotential[row] = updval; break;			// air entry potential
//                    case 26 : saturatedHydraulicConductivity[row] = updval; break;			// sat hydraulic conductivity
//                    case 27 : soilpH[row] = updval; break;			// soil pH
//                    case 28 : calciumCarbonateEquivalent[row] = updval; break;		// calcium carbonate equiv
//                    case 29 : cationExchangeCapacity[row] = updval; break;			// cation exchange capacity
//                    case 30 : linearExtensibility[row] = updval; break;			//
//                }
//            }
//        }
//        //System.out.println("IFC_uRGF: " + NotesDisplay.getText());
//        errorsInIfcFile = NotesDisplay.getText();
//    }
//    
//    /**
//     *
//     * @param col
//     * @param row
//     * @param typ
//     * @param label
//     * @return
//     */
//    /* updates surface variables */
//    
//    public	boolean	updateRecordFromGrid(int col, int row, int typ, String label) {
//        interact = true;			// update from grid has occurred
//        double updval = 0;
//        switch (typ) {
//            case 1 : row -= GridID.getHeaderRowCount(); break;
//            case 2 : row -= GridSurfProp.getHeaderRowCount(); break;
//            case 3 : row -= GridLayrProp.getHeaderRowCount(); break;
//        }
//        
//        ER_crustLooseMaterialFraction.hiValue = crustFraction;
//        ER_crustFraction.loValue = crustLooseMaterialFraction;
//        
//        int chkRng = checkRange(row, col, typ, label);
//        if (chkRng != 0) return false;
//        switch (typ) {
//            case 1 :
//                checkRange(row, col, typ, label);
//                switch (col) {
//                    case 1 : state = label; break;
//                    case 2 : county = label; break;
//                    case 3 : soilSurveyAreaName = label; break;
//                    case 4 : soilSurveyID = label; break;
//                    case 5 : mapUnitSymbol = label; break;
//                    case 6 : componentName = label; break;
//                    case 7 : componentPercent = label; break;
//                    case 8 : taxOrder = label; break;
//                    case 9 : localPhase = label; break;
//                    case 10: surfaceTexture = label; break;
//                    case 11: soilLossTolerance = Integer.valueOf(label.trim()).intValue(); break;
//                }
//                break;
//            case 2:
//                updval = Double.valueOf(label.trim()).doubleValue();
//                switch(col) {
//                    case  1: crustThickness = updval; break;
//                    case  2: crustDensity = updval; break;
//                    case  3: crustStability = updval; break;
//                    case  4: crustFraction = updval; break;
//                    case  5: crustLooseMaterialMass = updval; break;
//                    case  6: crustLooseMaterialFraction = updval; break;
//                    case  7: randomRoughness = updval; break;
//                    case  8: roughnessOrientation = updval; break;
//                    case  9: roughnessHeight = updval; break;
//                    case 10: roughnessSpacing = updval; break;
//                    case 11: roughnessWidth = updval; break;
//                    case 12: surfaceAlbedo = updval; break;
//                    case 13: surfaceSlope = updval; break;
//                    case 14: surfaceFragmentCover = updval; break;
//                    case 15: bedrockDepth = updval; break;
//                    case 16: impermiableDepth = updval; break;
//                }
//                break;
//            case 3 :
//                updval = Double.valueOf(label.trim()).doubleValue();
//                try {
//                    switch (col) {
//                        case  1 : layerThickness[row] = updval; break;			// thickness in mm
//                        case  2 : organicMaterial[row] = updval; break;			// organic matter
//                        case  3 : fractionSand[row] = updval; break;			// % sand
//                        case  4 : fractionSilt[row] = updval; break;			// % silt
//                        case  5 : fractionClay[row] = updval; break;			// % clay
//                        case  6 : fractionRock[row] = updval; break;			// rock %
//                        case  7 : veryCoarseSandFraction[row] = updval; break;			// sand fraction coarse
//                        case  8 : coarseSandFraction[row] = updval; break;			// sand fraction coarse
//                        case  9 : mediumSandFraction[row] = updval; break;			// sand fraction medium
//                        case 10 : fineSandFraction[row] = updval; break;			// sand fraction fine
//                        case 11 : veryFineSandFraction[row] = updval; break;			// sand fraction very find
//                        case 12 : wetBulkDensity[row] = updval; break;			// bulk density 1/3 bar
//                        case 13 : initialBulkDensity[row] = updval; break;			// bulk density 1/3 bar
//                        case 14 : aggregateMeanDiameter[row] = updval; break;		// aggregate mean diameter
//                        case 15 : aggregateStdDeviation[row] = updval; break;		// aggregate standard deviation
//                        case 16 : maxAggregateSize[row] = updval; break;		// max aggregate size
//                        case 17 : minAggregateSize[row] = updval; break;		// min aggregate size
//                        case 18 : aggregateDensity[row] = updval; break;		// aggregate density
//                        case 19 : aggregateStability[row] = updval; break;		// aggregate stability
//                        case 20 : initialSWC[row] = updval; break;			// initial soil water content (swc)
//                        case 21 : saturatedSWC[row] = updval; break;			// saturated swc
//                        case 22 : fieldCapacitySWC[row] = updval; break;			// field capacity swc
//                        case 23 : wiltingPointSWC[row] = updval; break;			// wilting point swc
//                        case 24 : soilCB[row] = updval; break;			// soil CB
//                        case 25 : airEntryPotential[row] = updval; break;			// air entry potential
//                        case 26 : saturatedHydraulicConductivity[row] = updval; break;			// sat hydraulic conductivity
//                        case 27 : soilpH[row] = updval; break;			// soil pH
//                        case 28 : calciumCarbonateEquivalent[row] = updval; break;		// calcium carbonate equiv
//                        case 29 : cationExchangeCapacity[row] = updval; break;			// cation exchange capacity
//                        case 30 : linearExtensibility[row] = updval; break;			//
//                    }
//                } catch (java.lang.ArrayIndexOutOfBoundsException e) {}
//                break;
//        }
//        return true;
//        
////	rtnval[ldx] = Double.valueOf(dblstr.trim()).doubleValue();
//    }
//    
//    /**
//     * wjr
//     * @param type
//     * @return
//     */
//    
//    public	String[][]	getGridValues(int type)
//    
//    {
//        switch (type) {
//            case 1 : {
//                int jdx = 0;
//                String[][] gridValues = new String[1][];
//                gridValues[0] = new String[MaxInfo+1];
//                gridValues[0][jdx++] = "blank";
//                gridValues[0][jdx++] = state;
//                gridValues[0][jdx++] = county;
//                gridValues[0][jdx++] = soilSurveyAreaName;
//                gridValues[0][jdx++] = soilSurveyID;
//                gridValues[0][jdx++] = mapUnitSymbol;
//                gridValues[0][jdx++] = componentName;
//                gridValues[0][jdx++] = componentPercent;
//                gridValues[0][jdx++] = taxOrder;
//                gridValues[0][jdx++] = localPhase;
//                gridValues[0][jdx++] = surfaceTexture;
//                gridValues[0][jdx++] = Integer.toString(soilLossTolerance);
//                return gridValues;
//            }
//            case 2 : {
//                int jdx = 0;
//                String[][] gridValues = new String[1][];
//                gridValues[0] = new String[MaxSurf+1];
//                gridValues[0][jdx++] = "blank";
//                gridValues[0][jdx++] = Util.formatDouble(crustThickness, 3);
//                gridValues[0][jdx++] = Util.formatDouble(crustDensity, 3);
//                gridValues[0][jdx++] = Util.formatDouble(crustStability, 3);
//                gridValues[0][jdx++] = Util.formatDouble(crustFraction, 3);
//                gridValues[0][jdx++] = Util.formatDouble(crustLooseMaterialMass, 3);
//                gridValues[0][jdx++] = Util.formatDouble(crustLooseMaterialFraction, 3);
//                gridValues[0][jdx++] = Util.formatDouble(randomRoughness, 3);
//                gridValues[0][jdx++] = Util.formatDouble(roughnessOrientation, 3);
//                gridValues[0][jdx++] = Util.formatDouble(roughnessHeight, 3);
//                gridValues[0][jdx++] = Util.formatDouble(roughnessSpacing, 3);
//                gridValues[0][jdx++] = Util.formatDouble(roughnessWidth, 3);
//                gridValues[0][jdx++] = Util.formatDouble(surfaceAlbedo, 3);
//                gridValues[0][jdx++] = Util.formatDouble(surfaceSlope, 3);
//                gridValues[0][jdx++] = Util.formatDouble(surfaceFragmentCover, 3);
//                gridValues[0][jdx++] = Util.formatDouble(bedrockDepth, 0);
//                gridValues[0][jdx++] = Util.formatDouble(impermiableDepth, 0);
//                return gridValues;
//            }
//            case 3 : {
//                String[][] gridValues = new String[nsl][];
//                for (int ldx = 0, jdx = 0; ldx < nsl; ldx++, jdx = 0) {
//                    gridValues[ldx] = new String[MaxLayr+1];
////				gridValues[ldx][jdx++] = Integer.toString(ldx + 1);
//////System.out.println("nsl " + nsl + " ldx " + ldx + " jdx " + jdx + " layerThickness.length " + lthk.length);
//                    gridValues[ldx][jdx++] = "blank";
//                    gridValues[ldx][jdx++] = Util.formatDouble(layerThickness[ldx], 0);
//                    gridValues[ldx][jdx++] = Util.formatDouble(organicMaterial[ldx], 4);
//                    gridValues[ldx][jdx++] = Util.formatDouble(fractionSand[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(fractionSilt[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(fractionClay[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(fractionRock[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(veryCoarseSandFraction[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(coarseSandFraction[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(mediumSandFraction[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(fineSandFraction[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(veryFineSandFraction[ldx], 3);
////				gridValues[ldx][jdx++] = Util.formatDouble(dryBulkDensity[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(wetBulkDensity[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(initialBulkDensity[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(aggregateMeanDiameter[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(aggregateStdDeviation[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(maxAggregateSize[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(minAggregateSize[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(aggregateDensity[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(aggregateStability[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(initialSWC[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(saturatedSWC[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(fieldCapacitySWC[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(wiltingPointSWC[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(soilCB[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(airEntryPotential[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(saturatedHydraulicConductivity[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(soilpH[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(calciumCarbonateEquivalent[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(cationExchangeCapacity[ldx], 3);
//                    gridValues[ldx][jdx++] = Util.formatDouble(linearExtensibility[ldx], 3);
////				gridValues[ldx][jdx++] = "0.0";
//                }
//                return gridValues;
//            }
//        }
//        return null;
//    }
    /********************************************************************** wjr */
    
    static final ErrorRange[] idList = {
        new ErrorRange("Dummy"),														// 0
        new ErrorRange("State"),														// 1
        new ErrorRange("County"),														// 2
        new ErrorRange("Soil Survery Area Name"),										// 3
        new ErrorRange("Soil Survery ID"),												// 4
        new ErrorRange("Map Unit Symbol"),												// 5
        new ErrorRange("Component Name"),												// 6
        new ErrorRange("Component Percent", 0.0, 100.0),								// 7
        new ErrorRange("Soil Order"),													// 8
        new ErrorRange("Local Phase"),											// 9
        new ErrorRange("Surface texture"),																// 15
        new ErrorRange("Soil Loss Tolerance (tons/acre/year)", 0, 5),								// 16
    };
    
    static final ErrorRange[] layerList = {
        new ErrorRange("Number of layers", 1.0, 100.0),									// 0
        new ErrorRange("Layer thickness (mm)", 0.0, 20000.0),							// 1
        new ErrorRange("Organic matter (kg/kg)", 0.0, 1.0),								// 2
        new ErrorRange("Sand fraction", 0.0, 1.0),										// 3
        new ErrorRange("Silt fraction", 0.0, 1.0),										// 4
        new ErrorRange("Clay fraction", 0.0, 1.0),										// 5
        new ErrorRange("Rock fragments", 0.0, 1.0),										// 6
        new ErrorRange("Sand fraction very coarse", 0.0, 1.0),							// 7
        new ErrorRange("Sand fraction coarse", 0.0, 1.0),								// 8
        new ErrorRange("Sand fraction medium", 0.0, 1.0),								// 9
        new ErrorRange("Sand fraction fine", 0.0, 1.0),									// 10
        new ErrorRange("Sand fraction very fine", 0.0, 1.0),							// 11
        new ErrorRange("Bulk Density (1/3 bar)(Mg/m^3)", 0.1, 10.0),						// 12
        new ErrorRange("Initial Bulk Density (1/3 bar)(Mg/m^3)", 0.1, 10.0),				// 13
        new ErrorRange("Aggregate geometric mean diameter (mm)", 0.03, 30.0),			// 14
        new ErrorRange("Aggregate geometric standard deviation", 1.0, 20.0),			// 15
        new ErrorRange("Maximum aggregate size (mm)", 1.0, 1000.0),						// 16
        new ErrorRange("Minimum aggregate size (mm)", 0.001, 5.0),						// 17
        new ErrorRange("Aggregate density (Mg/m^3)", 0.6, 2.5),							// 18
        new ErrorRange("Aggregate stability (ln(J/m^2))", 0.1, 7.0),					// 19
        new ErrorRange("Initial soil water content (m^3/m^3)", 0.011, 0.379),			// 20
        new ErrorRange("Saturation soil water content (m^3/m^3)", 0.208, 0.550),		// 21
        new ErrorRange("Field capacity water content (m^3/m^3)", 0.012, 0.335),			// 22
        new ErrorRange("Wilting point water content (m^3/m^3)", 0.005, 0.242),			// 23
        new ErrorRange("Soil CB value (exponent to Campbell's SWRC)", 0.917, 27.027),	// 24
        new ErrorRange("Air entry potential (J/kg)", -17.91, 0.0),						// 25
        new ErrorRange("Saturated hydraulic conductivity (m/s)", 0.0, 0.001),			// 26
        new ErrorRange("Soil PH (0-14)", 0.0, 14.0),									// 27
        new ErrorRange("Calcium carbonate equivalent (CaCO3)", 0.0, 1.0),				// 28
        new ErrorRange("Cation exchange capacity (CEC) (meq/100g)", 0.0, 400.0),		// 29
        new ErrorRange("Linear extensibility", 0.0, 30.0),								// 30
        new ErrorRange("end", 0.0,0.0)};
    
    static final ErrorRange[] surfaceList = {
//	new ErrorRange("0", 0.0, 0.0), // 0
        new ErrorRange("Dummy", 0.0, 23.0),																// 0
        new ErrorRange("Crust thickness (mm)", 0.0, 23.0),												// 1
        new ErrorRange("Crust density (Mg/m^3)", 0.6, 2.0),												// 2
        new ErrorRange("Crust stability (ln(J/m^2))", 0.1, 7.0),										// 3
        new ErrorRange("Crust surface fraction (m^2/m^2)", 0.0, 1.0),									// 4
        new ErrorRange("Mass of loose material on crust (kg/m^2)", 0.0, 3.0),							// 5
        new ErrorRange("Fraction of loose material on crust (m^2/m^2)", 0.0, 1.0),						// 6
        new ErrorRange("Random roughness (mm)", 1.0, 30.0),												// 7
        new ErrorRange("Ridge orientation (deg)", 0.0, 179.99),											// 8
        new ErrorRange("Ridge height (mm)", 0.0, 500.0),												// 9
        new ErrorRange("Spacing between ridge tops (mm)", 10.0, 2000.0),								// 10
        new ErrorRange("Ridge width (mm)", 10.0, 4000.0),												// 11
        new ErrorRange("Dry soil albedo (fraction)", 0.02, 1.0),										// 12
        new ErrorRange("Slope gradient (fraction)", 0.0, 0.999),										// 13
        new ErrorRange("Surface fragment cover or surface layer fragments (area fraction)", 0.0, 0.999),// 14
        new ErrorRange("Depth to bedrock (mm)", 0.0, 99999),											// 15
        new ErrorRange("Depth to root restricting layer (mm)", 0.0, 99999),								// 16
        new ErrorRange("end", 0.0, 0.0)};
    
    static final ErrorRange ER_crustLooseMaterialFraction = surfaceList[6];				// loose material fraction
    static final ErrorRange ER_crustFraction = surfaceList[4];				// soil crust surface fraction
    
    /**
     *
     * @param row
     * @param col
     * @param type
     * @param label
     * @return
     */
    public int checkRange(int row, int col, int type, String label) {
        ErrorRange[] rangeList = null;
        switch (type) {
            case 1 : rangeList = idList; break;
            case 2 : rangeList = surfaceList; break;
            case 3 : rangeList = layerList; break;
        }
        return rangeList[col].errorBox(label);
    }
    
    /**
     *
     * @param type
     * @return
     */
    public ErrorRange[] getToolTipText(int type)
    
    {
        switch (type) {
            case 1 : return idList.clone();
            case 2 : return surfaceList.clone();
            case 3 : return layerList.clone();
        }
        return null;
    }
    
    /********************************************************************** wjr */
    
    private boolean	chkSoilandSandPcts()
    
    {
        NumberFormat.getInstance().setMaximumFractionDigits(4);
        for (int ldx = 0; ldx < nsl; ldx++) {
            if (Math.abs(fractionSand[ldx] + fractionSilt[ldx] + fractionClay[ldx] - 1.0) > 0.0001) {
                WepsMessage msg = WepsMessage.warningMessage("Bad soil fractions for layer " + (ldx+1) + " sand " + Util.formatDouble(fractionSand[ldx], 4) + " silt " + Util.formatDouble(fractionSilt[ldx], 4) + " clay " + Util.formatDouble(fractionClay[ldx], 4));
                c_log.logMessage(msg);
                if (interact) {
                    System.err.println("Error: Sand, silt and clay fractions do not add to 1.0 on layer " + (ldx+1) + ".\nCheck soil fractions.");
//                    JOptionPane.showMessageDialog(new JPanel(),
//                            "Sand, silt and clay fractions do not add to 1.0 on layer " + (ldx+1),
//                            "Check soil fractions", JOptionPane.ERROR_MESSAGE);
                    return true;
                }
                
            }
            
            if (veryCoarseSandFraction[ldx] + coarseSandFraction[ldx] + mediumSandFraction[ldx] +
                    fineSandFraction[ldx] + veryFineSandFraction[ldx] > fractionSand[ldx] + 0.0001) {
                WepsMessage msg = WepsMessage.warningMessage("sand fractions exceed total sand for layer " + (ldx+1) + " sand " + Util.formatDouble(fractionSand[ldx], 4) +
                        " veryCoarseSandFraction " + Util.formatDouble(veryCoarseSandFraction[ldx], 4) +
                        " coarseSandFraction " + Util.formatDouble(coarseSandFraction[ldx], 4) +
                        " mediumSandFraction " + Util.formatDouble(mediumSandFraction[ldx], 4) +
                        " fineSandFraction " + Util.formatDouble(fineSandFraction[ldx], 4) +
                        " veryFineSandFraction " + Util.formatDouble(veryFineSandFraction[ldx], 4));
                c_log.logMessage(msg);
                if (interact) {
                    System.err.println("Error: Sand fractions exceed total soil-sand fraction on layer " + (ldx+1) + ".\nCheck sand fractions.");
//                    JOptionPane.showMessageDialog(new JPanel(),
//                            "Sand fractions exceed total soil-sand fraction on layer " + (ldx+1),
//                            "Check sand fractions", JOptionPane.ERROR_MESSAGE);
                    return true;
                }
            }
        }
        return false;
    }
    
    /********************************************************************** wjr */
    /* adjust values in all rows noting errors */
    
    public	void	adjustIfc()
    
    {
        double rtnval;
        
        for (int ldx = 0; ldx < nsl; ldx++) {
            rtnval = layerList[14].adjValue(aggregateMeanDiameter[ldx]);
            if (rtnval != aggregateMeanDiameter[ldx]) {
                
                String msgText = layerList[14].title + " adjusted: old value " +
                        Util.formatDouble(aggregateMeanDiameter[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateMeanDiameter[ldx] = rtnval;
            }
            
            rtnval = layerList[15].adjValue(aggregateStdDeviation[ldx]);
            if (rtnval != aggregateStdDeviation[ldx]) {
                String msgText =  layerList[15].title + " adjusted: old value " +
                        Util.formatDouble(aggregateStdDeviation[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateStdDeviation[ldx] = rtnval;
            }
            
            rtnval = layerList[16].adjValue(maxAggregateSize[ldx]);
            if (rtnval != maxAggregateSize[ldx]) {
                String msgText =  layerList[16].title + " adjusted: old value " +
                        Util.formatDouble(maxAggregateSize[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                maxAggregateSize[ldx] = rtnval;
            }
            
            rtnval = layerList[17].adjValue(minAggregateSize[ldx]);
            if (rtnval != minAggregateSize[ldx]) {
                String msgText =  layerList[17].title + " adjusted: old value " +
                        Util.formatDouble(minAggregateSize[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                minAggregateSize[ldx] = rtnval;
            }
            
            rtnval = layerList[18].adjValue(aggregateDensity[ldx]);
            if (rtnval != aggregateDensity[ldx]) {
                String msgText =  layerList[18].title + " adjusted: old value " +
                        Util.formatDouble(aggregateDensity[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateDensity[ldx] = rtnval;
            }
            
            rtnval = layerList[19].adjValue(aggregateStability[ldx]);
            if (rtnval != aggregateStability[ldx]) {
                String msgText =  layerList[19].title + " adjusted: old value " +
                        Util.formatDouble(aggregateStability[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateStability[ldx] = rtnval;
            }
        }
        rtnval = surfaceList[2].adjValue(crustDensity);
        if (rtnval != crustDensity) {
            String msgText =  surfaceList[2].title + " adjusted: old value " +
                    Util.formatDouble(crustDensity, 4) + " new value " + rtnval;
            c_log.logMessage(WepsMessage.warningMessage(msgText));
            crustDensity = rtnval;
        }
        rtnval = surfaceList[3].adjValue(crustStability);
        if (rtnval != crustStability) {
            String msgText =  surfaceList[3].title + " adjusted: old value " +
                    Util.formatDouble(crustStability, 4) + " new value " + rtnval;
            c_log.logMessage(WepsMessage.warningMessage(msgText));
            crustStability = rtnval;
        }
        
    }
    
    /**
     * wjr
     * @param pj
     */
    
    public	void	printIfc(PrintJob pj) {
        int	vpos = 40;
        int	hpos = 20;
        int	vheight = 12;
        Graphics po = pj.getGraphics();
        po.setFont(new Font("monospaced", Font.BOLD, 20));
        po.drawString("Initial Field Conditions Data", hpos, 35);
        po.setFont(new Font("monospaced", Font.PLAIN, vheight - 2));
//        Dimension pagedim = pj.getPageDimension();
////System.out.println("page dim " + pagedim.height + " " + pagedim.width);
        
        po.drawString("Soil ID " + soilSurveyID + "-" + mapUnitSymbol + "-" + componentName + "-" + componentPercent + "-" + surfaceTexture +
                "-" + state + "-" + county + "-" + soilSurveyAreaName, hpos, vpos += vheight);
        po.drawString("Taxorder " + taxOrder, hpos, vpos += vheight);
        po.drawString("Number of soil layers " + nsl, hpos, vpos += vheight);
        
        printArray(po, layerList[1].title, layerThickness, 0, hpos, vpos += vheight);  // soil characteristics by layer
        printArray(po, layerList[2].title, organicMaterial, 3, hpos, vpos += vheight);
        printArray(po, layerList[3].title, fractionSand, 3, hpos, vpos += vheight);
        printArray(po, layerList[4].title, fractionSilt, 3, hpos, vpos += vheight);
        printArray(po, layerList[5].title, fractionClay, 3, hpos, vpos += vheight);
        printArray(po, layerList[6].title, fractionRock, 3, hpos, vpos += vheight);
        printArray(po, layerList[7].title, veryCoarseSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[8].title, coarseSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[9].title, mediumSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[10].title, fineSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[11].title, veryFineSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[12].title, wetBulkDensity, 3, hpos, vpos += vheight);
        printArray(po, layerList[13].title, initialBulkDensity, 3, hpos, vpos += vheight);
        printArray(po, layerList[14].title, aggregateMeanDiameter, 3, hpos, vpos += vheight);
        printArray(po, layerList[15].title, aggregateStdDeviation, 3, hpos, vpos += vheight);
        printArray(po, layerList[16].title, maxAggregateSize, 3, hpos, vpos += vheight);
        printArray(po, layerList[17].title, minAggregateSize, 3, hpos, vpos += vheight);
        printArray(po, layerList[18].title, aggregateDensity, 3, hpos, vpos += vheight);
        printArray(po, layerList[19].title, aggregateStability, 3, hpos, vpos += vheight);
        
//po.dispose();
        
        printValue(po, surfaceList[0].title,crustThickness, 3, hpos, vpos += vheight);  // crust and surface characteristics
        printValue(po, surfaceList[1].title,crustDensity, 3, hpos, vpos += vheight);
        printValue(po, surfaceList[2].title,crustStability, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[3].title,crustFraction, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[4].title,crustLooseMaterialMass, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[5].title,crustLooseMaterialFraction, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[6].title,randomRoughness, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[7].title,roughnessOrientation, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[8].title,roughnessHeight, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[9].title,roughnessSpacing, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[10].title,roughnessWidth, 2, hpos, vpos += vheight);
        
        printArray(po,layerList[20].title,initialSWC,3, hpos, vpos += vheight);  // hydrology by layers
        printArray(po,layerList[21].title,saturatedSWC,3, hpos, vpos += vheight);
        printArray(po,layerList[22].title,fieldCapacitySWC,3, hpos, vpos += vheight);
        printArray(po,layerList[23].title,wiltingPointSWC,3, hpos, vpos += vheight);
        printArray(po,layerList[24].title,soilCB,3, hpos, vpos += vheight);
        printArray(po,layerList[25].title,airEntryPotential,3, hpos, vpos += vheight);
        printArray(po,layerList[26].title,saturatedHydraulicConductivity,10, hpos, vpos += vheight);
        
        printValue(po, surfaceList[11].title,surfaceAlbedo, 3, hpos, vpos += vheight);
        printValue(po, surfaceList[12].title,surfaceSlope, 3, hpos, vpos += vheight);
        
        printArray(po,layerList[27].title,soilpH,2, hpos, vpos += vheight);
        printArray(po,layerList[28].title,calciumCarbonateEquivalent,2, hpos, vpos += vheight);
        printArray(po,layerList[29].title,cationExchangeCapacity,2, hpos, vpos += vheight);
        printArray(po,layerList[30].title,linearExtensibility, 3, hpos, vpos += vheight);
        
        po.dispose();
    }
    
    /********************************************************************** wjr */
    
    private void printArray(Graphics po, String nam, double arr[], int numdig, int hpos, int vpos) {
        
        StringBuffer sb = new StringBuffer(nam + " ");
        for (int ldx = 0 ; ldx < arr.length ; ldx++)
            sb.append(Util.formatDouble(arr[ldx],numdig) + "  ");
        po.drawString(sb.toString(), hpos, vpos);
    }
    
    /***********************************************************************************************************/
    
    private void printValue(Graphics po, String nam, double val, int numdig, int hpos, int vpos) {
        String outstr = nam;
        outstr += " " + Util.formatDouble(val,numdig);
        po.drawString(outstr, hpos,vpos);
    }
    
    /********************************************************************** wjr */
    
    
    private void copyNasData(NASIS nasinp) {
        
        initIfc(nsl);						// create ifc structure
////System.out.println("cND: nsl = " + nsl);
        
        layerDepthBottom = (double[]) nasinp.hzdepb.clone();
        layerThickness[0] = nasinp.hzdepb[0];
        for (int ldx = 1; ldx < nsl; ldx++) {					// fill in top depth & thickness
            layerDepthTop[ldx] = nasinp.hzdepb[ldx-1];					// current top is previous bottom
            layerThickness[ldx] = nasinp.hzdepb[ldx] - layerDepthTop[ldx];	// thickness is bottom - top
        }
        
        fractionClay = (double[]) nasinp.claytotal.clone();			// clay
        fractionSand = (double[]) nasinp.sandtotal.clone();			// sand
        for (int ldx = 0; ldx < nsl; ldx++) {				// remainder is silt
            if (fractionClay[ldx] < 1) fractionClay[ldx] = 1;				// define minimum clay to be 1%
            if (fractionSand[ldx] > 99) fractionSand[ldx] = 99;				// define maximum sand to be 99%
            fractionSilt[ldx] = 100 - (fractionClay[ldx] + fractionSand[ldx]);
            if (fractionSilt[ldx] < 0) fractionSilt[ldx] = Double.NaN;
        }
        fractionRock = (double[]) nasinp.fragvol.clone();				// rock %
        veryCoarseSandFraction = (double[]) nasinp.sandvco.clone();				// coarseSandFraction
        coarseSandFraction = (double[]) nasinp.sandco.clone();				// coarseSandFraction
        mediumSandFraction = (double[]) nasinp.sandmed.clone();				// mediumSandFraction
        fineSandFraction = (double[]) nasinp.sandfine.clone();				// fineSandFraction
        veryFineSandFraction = (double[]) nasinp.sandvf.clone();				// veryFineSandFraction
//	dryBulkDensity = (double[]) nasinp.dbovendry.clone();			// dryBulkDensity
        wetBulkDensity = (double[]) nasinp.dbthirdbar.clone();			// wetBulkDensity
//	initialBulkDensity = new double[nsl];							// initial BulkDensity
        initialBulkDensity = (double[]) nasinp.dbthirdbar.clone();			// wetBulkDensity
//	for (int ldx = 0; ldx < nsl; ldx++) {
//		initialBulkDensity[ldx] = (wetBulkDensity[ldx] + dryBulkDensity[ldx]) / 2;
//	}
        tenthBarSWC = (double[]) nasinp.wtenthbar.clone();			// b1ss
        fieldCapacitySWC = (double[]) nasinp.wthirdbar.clone();			// fieldCapacitySWC
        wiltingPointSWC = (double[]) nasinp.w15thbar.clone();				// wiltingPointSWC
        saturatedHydraulicConductivity = (double[]) nasinp.ksat.clone();					// satk
        organicMaterial = (double[]) nasinp.om.clone();						// om
        linearExtensibility = (double[]) nasinp.lep.clone();					// lep
        /**
         * double[] phtmp = new double[nasinp.numlay];
         * //System.out.println("IFC_cN: " + nasinp.numlay);
         * for (int ldx = 0; ldx < nasinp.numlay; ldx++)
         * phtmp[ldx] = (!Double.isNaN(nasinp.ph1to1h2o[ldx])) ?
         * nasinp.ph1to1h2o[ldx] : nasinp.ph01mcacl2[ldx];			// ph
         *
         */
        double[] phtmp = new double[nasinp.adjlay];
        //System.out.println("IFC_cN: " + nasinp.adjlay);
        for (int ldx = 0; ldx < nasinp.adjlay; ldx++){
            phtmp[ldx] = (!Double.isNaN(nasinp.ph1to1h2o[ldx])) ? nasinp.ph1to1h2o[ldx] : nasinp.ph01mcacl2[ldx];			// ph
        }
        
        soilpH = phtmp;
//	if (nasinp.ph1to1h2o[0] > 0)									// ph
//		ph = nasinp.ph1to1h2o/*.clone()*/;
//	elsep
//		ph = nasinp.ph01mcacl2/*.clone()*/;
        //System.out.println("IFC_cN: " + soilpH.length + " " + soilpH);
        
        
        double[] cectmp = new double[nasinp.adjlay];
        for (int ldx = 0; ldx < nasinp.adjlay; ldx++)
            cectmp[ldx] = (!Double.isNaN(nasinp.cec7[ldx])) ?
                nasinp.cec7[ldx] : nasinp.ecec[ldx];			// cec
        cationExchangeCapacity = cectmp;
        
// I think this should be commented out because of above code to deal with populated cec7 and ecec fields varying by layer
// So, I will do so and test it - LEW
//	if (nasinp.cec7[0] > 0)											// cec
//		cec = nasinp.cec7/*.clone()*/;
//	else
//		cec = nasinp.ecec/*.clone()*/;
        
////System.out.println("cND: " + nasinp.calciumCarbonateEquivalent[cdx]
        calciumCarbonateEquivalent = nasinp.caco3/*.clone()*/;				// caco3
        
        state = nasinp.state;
        county = nasinp.county;
        soilSurveyAreaName = nasinp.ssaname;
        soilSurveyID = nasinp.ssaid;
        mapUnitSymbol = nasinp.musym;
        componentName = nasinp.compname;
        componentPercent = nasinp.comppct;
        taxOrder = nasinp.taxorder;
        surfaceAlbedo = nasinp.albedodry;
        surfaceSlope = nasinp.slope;
        surfaceTexture = nasinp.texture[0];				// surface texture
        localPhase = nasinp.localphase;
        
        //1143.2
        bedrockDepth = nasinp.bedrockDepth;
        impermiableDepth = nasinp.impermiableDepth;
        
        soilLossTolerance = (int) nasinp.losstolerance;
        
    }
    
    /********************************************************************** wjr */
    
    private void convertUnits()
    
    {
        
////System.out.println("split nsl: " + nsl);
        for (int ldx = 0; ldx < nsl; ldx++)	{
            layerThickness[ldx] *= 10.;				// thk				// cvt from cm to mm
            layerDepthBottom[ldx] *= 10.;				// depb
            layerDepthTop[ldx] *= 10.;				// dept
            fractionSand[ldx] /= 100.;				// sand				// cvt from % to fraction
            fractionClay[ldx] /= 100.;				// clay
            fractionSilt[ldx] /= 100.;				// silt
            fractionRock[ldx] /= 100.;				// rock
            veryCoarseSandFraction[ldx] /= 100.;				// sand coarse
            coarseSandFraction[ldx] /= 100.;				// sand coarse
            mediumSandFraction[ldx] /= 100.;				// sand medium
            fineSandFraction[ldx] /= 100.;				// sand fine
            veryFineSandFraction[ldx] /= 100.;				// sand very fine
//		[ldx]/= 100.;					// water dispersible clay
            fieldCapacitySWC[ldx] /= 100.;				// field capacity swc
            wiltingPointSWC[ldx] /= 100.;				// wilting point swc
            organicMaterial[ldx] /= 100.;				// organic matter
            calciumCarbonateEquivalent[ldx] /= 100.;				// caco3
            saturatedHydraulicConductivity[ldx] /= 1000000.;			// saturation k		// cvt from ppm to p
            //linearExtensibility[ldx] /= 100;				// linear extensibility, 1143.3 commented out so that units remain as LEP
        }
        
        surfaceSlope /= 100;							// surface slope from % to fraction
        bedrockDepth *= 10;                                                           //Bedrockdepth cm -> mm
        impermiableDepth *= 10;                                                       //Restrictive Depth cm -> mm
    }
    
    /***********************************************************************************************************/
    
    public void	estimateFactors() {
        c_log.clear();
        //System.out.println("IFC_eF:");
        double depth = 0;
        try {
            //  grid is commented out - GUI related
            //            updateRecordFromGrid();
        } catch(NullPointerException f) {
            Util.debugPrint(true, f.toString());
            f.printStackTrace();
        }
        
        //Check for required variables
        boolean errors = false;
        for (int ldx = 0; ldx < nsl; ldx++) {
            errors = true;
            if (layerList[1].errorBox(layerThickness[ldx]) != 0) break;
            if (layerList[2].errorBox(organicMaterial[ldx]) != 0) break;
            if (layerList[3].errorBox(fractionSand[ldx]) != 0) break;
            if (layerList[5].errorBox(fractionClay[ldx]) != 0) break;
            if (layerList[11].errorBox(veryFineSandFraction[ldx]) != 0) break;
            if (layerList[12].errorBox(wetBulkDensity[ldx]) != 0) break;
            if (layerList[28].errorBox(calciumCarbonateEquivalent[ldx]) != 0) break;
            errors = false;
        }
        if (errors){
            throw new IllegalStateException();
        }
        
        
        //End check
        
        for (int ldx = 0; ldx < nsl; ldx++) {				// remainder is silt
            if (Double.isNaN(fractionSilt[ldx])) fractionSilt[ldx] = 0.0;
            if (Double.isNaN(veryCoarseSandFraction[ldx])) veryCoarseSandFraction[ldx] = 0.0;
            if (Double.isNaN(coarseSandFraction[ldx])) coarseSandFraction[ldx] = 0.0;
            if (Double.isNaN(mediumSandFraction[ldx])) mediumSandFraction[ldx] = 0.0;
            if (Double.isNaN(fineSandFraction[ldx])) fineSandFraction[ldx] = 0.0;
            if (Double.isNaN(fractionRock[ldx])) fractionRock[ldx] = 0.0;
            
            if (fractionClay[ldx] < .01) fractionClay[ldx] = .01;				// define minimum clay to be 1%
            if (fractionSand[ldx] > .99) fractionSand[ldx] = .99;				// define maximum sand to be 99%
            fractionSilt[ldx] = 1 - (fractionClay[ldx] + fractionSand[ldx]);
            if (fractionSilt[ldx] < 0) fractionSilt[ldx] = Double.NaN;
            
            layerDepthTop[ldx] = depth;
            depth += layerThickness[ldx];
            layerDepthBottom[ldx] = depth;
            
            if (Double.isNaN(initialBulkDensity[ldx])) initialBulkDensity[ldx] = wetBulkDensity[ldx];
        }
        
        
//	if (Double.isNaN(surfaceAlbedo)) {
//		surfaceAlbedo = 0.6/Math.exp(0.4*organicMaterial[0]);
//	}
        
        calculateFactors(true);
        
        try {
            adjustIfc();
        } catch(NullPointerException f) {
            Util.debugPrint(true, f.toString());
            f.printStackTrace();
        }
        errorsInIfcFile += "\n# SOIL VALUES ESTIMATED\n";
        errorsInIfcFile += "# " + new Date().toString() + "\n";
        for (WepsMessage message : c_log.getMessages()){
            errorsInIfcFile += "# " + message.toString() + "\n";
        }
        c_log.clear();
    }
    
    
    
    
    /***********************************************************************************************************/
    
    /* split2() computes the 60+ parameters which are not computed in split()   */
    private void calculateFactors() {
        calculateFactors(false);
    }
    
    private void calculateFactors(boolean force) {
        
        for(int ldx=0; ldx < nsl; ldx++) {									// parameters by layer
            // formula from 12/6/95 memo from LJH to JT
            
            double rtnval = 0;
            
            aggregateMeanDiameter[ldx] = Math.exp(1.343 - 2.235*fractionSand[ldx]-			// aggregate geometric mean diameter
                    1.226*fractionSilt[ldx] - 0.0238*fractionSand[ldx]/fractionClay[ldx] +
                    33.6*organicMaterial[ldx] + 6.85*calciumCarbonateEquivalent[ldx]) * (1 + 0.006 * layerDepthBottom[ldx]);
            rtnval = layerList[14].adjValue(aggregateMeanDiameter[ldx]);
            if (rtnval != aggregateMeanDiameter[ldx]) {
                String msgText = layerList[14].title + " adjusted: old value " +
                        Util.formatDouble(aggregateMeanDiameter[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateMeanDiameter[ldx] = rtnval;
            }
            
            aggregateStdDeviation[ldx] = 1/(0.012448+0.002463*aggregateMeanDiameter[ldx]+(0.093467/(Math.pow(aggregateMeanDiameter[ldx],0.5))));
            rtnval = layerList[15].adjValue(aggregateStdDeviation[ldx]);
            if (rtnval != aggregateStdDeviation[ldx]) {
                String msgText =  layerList[15].title + " adjusted: old value " +
                        Util.formatDouble(aggregateStdDeviation[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateStdDeviation[ldx] = rtnval;
            }
            
            maxAggregateSize[ldx] = Math.pow(aggregateStdDeviation[ldx],(1.52*(Math.pow(aggregateMeanDiameter[ldx],-0.449))))*aggregateMeanDiameter[ldx];
            rtnval = layerList[16].adjValue(maxAggregateSize[ldx]);
            if (rtnval != maxAggregateSize[ldx]) {
                String msgText =  layerList[16].title + " adjusted: old value " +
                        Util.formatDouble(maxAggregateSize[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                maxAggregateSize[ldx] = rtnval;
            }
            
            minAggregateSize[ldx] = 0.01;												// minimum aggregate size
            
//		if (layerDepthBottom[ldx] >=300) aggregateDensity[ldx] = 2.0;					// aggregate density
//		else aggregateDensity[ldx]= 2.01*(0.72 + 0.00092*layerDepthBottom[ldx]);
            aggregateDensity[ldx] = 1.8;
            rtnval = layerList[18].adjValue(aggregateDensity[ldx]);
            if (rtnval != aggregateDensity[ldx]) {
                String msgText =  layerList[18].title + " adjusted: old value " +
                        Util.formatDouble(aggregateDensity[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateDensity[ldx] = rtnval;
            }
            
            
            aggregateStability[ldx] = (fractionClay[ldx] > 0.5) ? 2.73 : 0.83 + 15.7*fractionClay[ldx]-
                    23.8 * Math.pow(fractionClay[ldx],2);								// aggregate stability
            rtnval = layerList[19].adjValue(aggregateStability[ldx]);
            if (rtnval != aggregateStability[ldx]) {
                String msgText =  layerList[19].title + " adjusted: old value " +
                        Util.formatDouble(aggregateStability[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateStability[ldx] = rtnval;
            }
            
/* saxton95.for
 * calculate cb, thetas & pote.  do not calc satk, thetaw or thetaf as they
 * come from input file.
 */
            
            double sax_e = -3.140, sax_f = -2.22e-3, sax_g = -3.484e-5;			// coef used to calc CB
            double sax_m = -0.108, sax_n = 0.341;								// coef used to calc POTE  (not used in this code)
            double sax_x = 0.332, sax_y = -7.251e-4, sax_z = 0.1276;			// coef used to calc THETAS
            
            saturatedSWC[ldx] = sax_x + sax_y*fractionSand[ldx] * 100. +			// saturated soil water content
                    sax_z*(Math.log(fractionClay[ldx]*100.)/Math.log(10.));
            rtnval = layerList[21].adjValue(saturatedSWC[ldx]);
            if (rtnval != saturatedSWC[ldx]) {
                String msgText =  layerList[21].title + " adjusted: old value " +
                        Util.formatDouble(saturatedSWC[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                saturatedSWC[ldx] = rtnval;
            }
            
            soilCB[ldx] = - (sax_e +											// cb(k) == ifc3_layer[][23]
                    (sax_f * Math.pow(fractionClay[ldx]*100., 2.0)) +
                    (sax_g * Math.pow(fractionSand[ldx]*100., 2.0) * fractionClay[ldx]*100.));
            rtnval = layerList[24].adjValue(soilCB[ldx]);
            if (rtnval != soilCB[ldx]) {
                String msgText =  layerList[24].title + " adjusted: old value " +
                        Util.formatDouble(soilCB[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                soilCB[ldx] = rtnval;
            }
            
            
            double sax_a = 100 * Math.exp(-4.396 -								// calc A factor for pote
                    0.0715*(fractionClay[ldx]*100.) -								// using two steps because that is how
                    (4.880e-4)* Math.pow(fractionSand[ldx]*100., 2) -				// saxton95 does it
                    (4.285e-5)* Math.pow(fractionSand[ldx]*100., 2)*(fractionClay[ldx]*100.));
            
            airEntryPotential[ldx] = -sax_a * Math.pow(saturatedSWC[ldx],-soilCB[ldx]); // calc pote
            rtnval = layerList[25].adjValue(airEntryPotential[ldx]);
            if (rtnval != airEntryPotential[ldx]) {
                String msgText =  layerList[25].title + " adjusted: old value " +
                        Util.formatDouble(airEntryPotential[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                airEntryPotential[ldx] = rtnval;
            }
            
            
////System.out.println("saxton " + fractionClay[ldx] + " " + wetBulkDensity[ldx]);
            
            if (force || fieldCapacitySWC[ldx] == 0.0 || Double.isNaN(fieldCapacitySWC[ldx])) {
                fieldCapacitySWC[ldx] = Math.pow((33.0 / sax_a), (1 / -soilCB[ldx]));
////System.out.println("saxton " + fieldCapacitySWC[ldx]);
//			fieldCapacitySWC[ldx] /= wetBulkDensity[ldx];					// convert from volumetric to gravimetric
                rtnval = layerList[22].adjValue(fieldCapacitySWC[ldx]);
                if (rtnval != fieldCapacitySWC[ldx]) {
                    String msgText =  layerList[22].title + " adjusted: old value " +
                            Util.formatDouble(fieldCapacitySWC[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    fieldCapacitySWC[ldx] = rtnval;
                } else {
                    String msgText = "field capacity layer " + (ldx+1) +
                            " input as 0.0 or NaN; replaced with estimate " + Util.formatDouble(fieldCapacitySWC[ldx], 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
                
            }
            
            if (force || wiltingPointSWC[ldx] == 0.0 || Double.isNaN(wiltingPointSWC[ldx])) {
                wiltingPointSWC[ldx] = Math.pow((1500.0 / sax_a), (1 / -soilCB[ldx]));
//			wiltingPointSWC[ldx] /= wetBulkDensity[ldx];					// convert from volumetric to gravimetric
//			NumberFormat.getInstance().setMaximumFractionDigits(4);
                rtnval = layerList[23].adjValue(wiltingPointSWC[ldx]);
                if (rtnval != wiltingPointSWC[ldx]) {
                    String msgText =  layerList[23].title + " adjusted: old value " +
                            Util.formatDouble(wiltingPointSWC[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    wiltingPointSWC[ldx] = rtnval;
                } else {
                    String msgText = "wilting point layer " + (ldx+1) +
                            " input as 0.0 or NaN; replaced with estimate " + Util.formatDouble(wiltingPointSWC[ldx],4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
            }
            
/*		if (tenthBarSWC[ldx] == 0.0) {
                        tenthBarSWC[ldx] = Math.pow((10.0 / sax_a), (1 / -soilCB[ldx]));
                        tenthBarSWC[ldx] /= wetBulkDensity[ldx];					// convert from volumetric to gravimetric
                }*/
            
            if (force || saturatedHydraulicConductivity[ldx] == 0.0 || Double.isNaN(saturatedHydraulicConductivity[ldx])) {
                double sk = 9.6 - 0.81*Math.log(fractionSilt[ldx]*100.)/Math.log(10.) -
                        1.09*Math.log(fractionClay[ldx]*100.)/Math.log(10.) - 4.64 * initialBulkDensity[ldx];
                saturatedHydraulicConductivity[ldx] = Math.pow(10, sk) * 0.24 * (1.0/86400);
                rtnval = layerList[26].adjValue(saturatedHydraulicConductivity[ldx]);
                if (rtnval != saturatedHydraulicConductivity[ldx]) {
                    String msgText =  layerList[26].title + " adjusted: old value " +
                            Util.formatDouble(saturatedHydraulicConductivity[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    saturatedHydraulicConductivity[ldx] = rtnval;
                } else {
                    String msgText = "satk layer " + (ldx+1) +
                            " input as 0.0 or NaN; replaced with estimate " +
                            Util.formatDouble(saturatedHydraulicConductivity[ldx], 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
            }
            
            if (force || soilpH[ldx] == 0.0 || Double.isNaN(soilpH[ldx])) {
                rtnval = 7;
                String msgText =  layerList[27].title + " adjusted: old value " +
                        Util.formatDouble(soilpH[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                soilpH[ldx] = rtnval;
            }
            
            if (force || cationExchangeCapacity[ldx] == 0.0 || Double.isNaN(cationExchangeCapacity[ldx])) {
                cationExchangeCapacity[ldx] = fractionClay[ldx]*100*0.5 + organicMaterial[ldx]*100.*2.0;
                rtnval = layerList[29].adjValue(cationExchangeCapacity[ldx]);
                if (rtnval != cationExchangeCapacity[ldx]) {
                    String msgText =  layerList[29].title + " adjusted: old value " +
                            Util.formatDouble(cationExchangeCapacity[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    cationExchangeCapacity[ldx] = rtnval;
                } else {
                    String msgText =  "cec layer " + (ldx+1) +
                            " input as 0.0 or NaN; replaced with estimate " +
                            Util.formatDouble(cationExchangeCapacity[ldx], 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
            }
            
            if (force || linearExtensibility[ldx] == 0.0 || Double.isNaN(linearExtensibility[ldx])) {
                double bsd = SoilUtil.estimateSettledBulkDensity(fractionClay[ldx], fractionSand[ldx], organicMaterial[ldx]);
                
                if (wetBulkDensity[ldx] > bsd){
                    bsd = wetBulkDensity[ldx];
                    String msgText =  "Settled bulk density adjusted: Set to wet bulk density.";
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                } else{
                    String msgText =  "Settled bulk density estimated: " + Util.formatDouble(bsd, 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
                
                linearExtensibility[ldx] = SoilUtil.estimateLinearExtensibility(bsd, wetBulkDensity[ldx]);
                rtnval = layerList[30].adjValue(linearExtensibility[ldx]);
                if (rtnval != linearExtensibility[ldx]) {
                    String msgText =  layerList[30].title + " adjusted: old value " +
                            Util.formatDouble(linearExtensibility[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    linearExtensibility[ldx] = rtnval;
                } else {
                    String msgText =  "cec layer " + (ldx+1) +
                            " input as 0.0 or NaN; replaced with estimate " +
                            Util.formatDouble(linearExtensibility[ldx], 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
            }
//		saturatedSWC[ldx] /= wetBulkDensity[ldx];					// convert from volumetric to gravimetric
            
            initialSWC[ldx] = (fieldCapacitySWC[ldx] + wiltingPointSWC[ldx]) / 2;			// initial soil water content
            
        }
        
        // parameters not by layer
        crustThickness = 0.01;											// soil crust thickness
        crustDensity = aggregateDensity[0];								// soil crust density
        crustStability = aggregateStability[0];								// soil crust stability
        randomRoughness = 4;												// random roughness
        if (force || surfaceAlbedo == 0.0  || Double.isNaN(surfaceAlbedo)) {
            surfaceAlbedo = 0.6 / (Math.exp(0.4 * organicMaterial[0] * 100.0));
            String msgText = "dry albedo input as 0.0 or NaN; replaced with estimate" +
                    Util.formatDouble(surfaceAlbedo, 4);
            c_log.logMessage(WepsMessage.warningMessage(msgText));
		System.err.println("Calculation of surface Albedo organicmatr=" + organicMaterial[0] + " sa=" + surfaceAlbedo);
        }
        
        
        
    }
    
//    /**
//     * wjr
//     * @param numRows
//     * @param chggrid
//     */
//    
//    public	void	rowsChanged(int numRows, Grid chggrid)
//    
//    {
//        //System.out.println("rC: " + numRows);
//        GridID.updateValue(0,8, " " + numRows);
//        nsl = numRows;
//    }
//    
//    /********************************************************************** wjr */
//    
//    Grid		GridID = null;
//    Grid		GridSurfProp = null;
//    Grid		GridLayrProp = null;
//    JTextArea	NotesDisplay = null;
//    
    /**
     *
     * @param id
     * @param surf
     * @param layr
     * @param notes
     */
//    public	void	setGrids(Grid id, Grid surf, Grid layr, JTextArea notes)
//    
//    {
//        GridID = id;
//        GridSurfProp = surf;
//        GridLayrProp = layr;
//        NotesDisplay = notes;
//    }
    
    /**
     * wjr
     * @param filetmp
     */
    
    public void setFilename1(String filetmp){
        mySavedFilename = filetmp;
    }
    
    /**
     *
     * @return
     */
    public String getFilename1(){
        return mySavedFilename;
    }
    
//    private void logMessage(WepsMessage.MessageSeverity severity, String message){
//        logMessage(new WepsMessage(severity, message));
//    }
    private void logMessage(WepsMessage message){
        c_log.logMessage(message);
    }
    
    public WepsMessageLog getLog(){
        return c_log;
    }
    
//    private void logSubstitutionMessage(WepsMessage.MessageSeverity severity, String dataElement, String header, Object newValue){
//        logSubstitutionMessage(severity, dataElement, header, newValue,-1);
//    }
//    
//    private void logSubstitutionMessage(WepsMessage.MessageSeverity severity, String dataElement, String header, Object newValue, int layer){
//        String layerTag = "";
//        if (layer > -1){
//            layerTag = " from layer " + (layer + 1);
//        }
//        WepsMessage tempMessage = new WepsMessage(severity, dataElement + " (" + header + ") is missing" + layerTag + ".  Null value was substituted with '" + newValue.toString() + "'.");
//        logMessage(tempMessage);
//        
//    }
//    
//    private void logEstimatedMessage(WepsMessage.MessageSeverity severity, String dataElement, String header, Object newValue){
//        logEstimatedMessage(severity, dataElement, header, newValue, -1);
//    }
    
//    private void logEstimatedMessage(WepsMessage.MessageSeverity severity, String dataElement, String header, Object newValue, int layer){
//        String layerTag = "";
//        if (layer > -1){
//            layerTag = " from layer " + (layer + 1);
//        }
//        WepsMessage tempMessage = new WepsMessage(severity, dataElement + " (" + header + ") is missing" + layerTag + ".  Value was estimated to '" + newValue.toString() + "'.");
//        logMessage(tempMessage);
//    }
//    
}

/*	alfisols
                        andisols
                        aridisols
                        entisols
                        gelisols
                        histosols
                        inceptisols
                        mollisols
                        oxisols
                        spodosols
                        ultisols
                        vertisols
                        other*/