def setElementValue(parent, name, value, attrib=None): try: elem = findElement(parent, name) elem.text = value if attrib is not None: elem.set('displayName', attrib) except Exception: log.error("Could not set value for element " + name) raise
def findElement(parent, name): try: elem = None for child in parent.getchildren(): if child.tag == name: elem = child return elem except Exception: log.error("Could not find element " + name) raise
def createElement(parent, name): try: found = False for child in parent.getchildren(): if child.tag == name: found = True if not found: parent.append(ET.Element(name)) except Exception: log.error("Could not create element " + name) raise
def CheckField(checkfile, fieldname): try: List = arcpy.ListFields(checkfile, fieldname) if len(List) == 1: exist = 1 else: exist = 0 return exist except Exception: log.error("Error occurred while checking if field " + fieldname + " exists in file " + checkfile) raise
def checkInputFields(inputFields, inputShp): log.info('Checking if all required input fields are present in ' + str(inputShp)) # Checks if the input fields are present in the shapefile for param in inputFields: fieldPresent = False if common.CheckField(inputShp, param): fieldPresent = True else: log.error("Field " + str(param) + " not found in the input shapefile") log.error( "Please ensure this field present in the input shapefile") sys.exit()
def CleanFields(checkfile, fieldstokeep): try: desc = arcpy.Describe(checkfile) List = arcpy.ListFields(checkfile) fieldNameList = [] for field in List: if not field.required: if field.name not in fieldstokeep: fieldNameList.append(field.name) # dBASE tables require a field other than an OID and Shape. If this is # the case, retain an extra field (the first one in the original list) if desc.dataType in ["ShapeFile", "DbaseTable"]: fieldNameList = fieldNameList[1:] arcpy.DeleteField_management(checkfile, fieldNameList) except Exception: log.error( "Error occurred while attempting to clean unwanted fields in file " + checkfile) raise
def function(params): try: pText = common.paramsAsText(params) # Get inputs runSystemChecks = common.strToBool(pText[1]) outputFolder = pText[2] inputShapefile = pText[3] PTFChoice = pText[4] BCPressures = pText[5] fcVal = pText[6] sicVal = pText[7] pwpVal = pText[8] carbonContent = pText[9] carbonConFactor = pText[10] unitsPlot = pText[11] axisChoice = pText[12] # Create output folder if not os.path.exists(outputFolder): os.mkdir(outputFolder) # System checks and setup if runSystemChecks: common.runSystemChecks(outputFolder) # Set up logging output to file log.setupLogging(outputFolder) # Write input params to XML common.writeParamsToXML(params, outputFolder) if PTFChoice == 'Cosby et al. (1984) - Sand and Clay': PTFOption = 'Cosby_1984_SandC_BC' elif PTFChoice == 'Cosby et al. (1984) - Sand, Silt and Clay': PTFOption = 'Cosby_1984_SSC_BC' elif PTFChoice == 'Rawls and Brakensiek (1985)': PTFOption = 'RawlsBrakensiek_1985_BC' log.warning("Rawls and Brakensiek (1985) requires water content at saturation") log.warning("Please ensure the WC_sat field is present in the shapefile") elif PTFChoice == 'Campbell and Shiozawa (1992)': PTFOption = 'CampbellShiozawa_1992_BC' log.warning("Campbell and Shiozava (1992) requires water content at saturation") log.warning("Please ensure the WC_sat field is present in the shapefile") elif PTFChoice == 'Saxton et al. (1986)': PTFOption = 'Saxton_1986_BC' elif PTFChoice == 'Saxton and Rawls (2006)': PTFOption = 'SaxtonRawls_2006_BC' else: log.error('Choice for Brooks-Corey calculation not recognised') sys.exit() # Set carbon content choice if carbonContent == 'Organic carbon': carbContent = 'OC' elif carbonContent == 'Organic matter': carbContent = 'OM' else: log.error('Invalid carbon content option') sys.exit() # Unpack 'BC pressure heads' parameter if BCPressures is None: BCPressArray = [] else: BCPressArray = BCPressures.split(' ') # Pull out PTFinfo PTFInfo = PTFdatabase.checkPTF(PTFOption) PTFType = PTFInfo.PTFType PTFUnit = PTFInfo.PTFUnit PTFOut = [("BCOption", PTFOption), ("PTFType", PTFType), ("UserUnitPlot", unitsPlot), ("carbContent", carbContent)] # Write to XML file PTFXML = os.path.join(outputFolder, "ptfinfo.xml") common.writeXML(PTFXML, PTFOut) # Call Brooks-Corey function brooks_corey.function(outputFolder, inputShapefile, PTFOption, BCPressArray, fcVal, sicVal, pwpVal, carbContent, carbonConFactor) # Set output filename for display BCOut = os.path.join(outputFolder, "BrooksCorey.shp") arcpy.SetParameter(13, BCOut) log.info("Brooks-Corey operations completed successfully") except Exception: log.exception("Brooks-Corey tool failed") raise
def function(params): try: pText = common.paramsAsText(params) # Get inputs runSystemChecks = common.strToBool(pText[1]) outputFolder = pText[2] inputShapefile = pText[3] VGChoice = pText[4] VGPressures = pText[5] fcVal = pText[6] sicVal = pText[7] pwpVal = pText[8] carbonContent = pText[9] carbonConFactor = pText[10] unitsPlot = pText[11] plotAxis = pText[12] MVGChoice = common.strToBool(pText[13]) # Create output folder if not os.path.exists(outputFolder): os.mkdir(outputFolder) common.runSystemChecks(outputFolder) # Set up logging output to file log.setupLogging(outputFolder) # Write input params to XML common.writeParamsToXML(params, outputFolder) # Simplify VGOption if VGChoice == "Wosten et al. (1999) topsoil": VGOption = "Wosten_1999_top" elif VGChoice == "Wosten et al. (1999) subsoil": VGOption = "Wosten_1999_sub" elif VGChoice == "Vereecken et al. (1989)": VGOption = "Vereecken_1989" elif VGChoice == "Zacharias and Wessolek (2007)": VGOption = "ZachariasWessolek_2007" elif VGChoice == "Weynants et al. (2009)": VGOption = "Weynants_2009" elif VGChoice == "Dashtaki et al. (2010)": VGOption = 'Dashtaki_2010_vg' elif VGChoice == "Hodnett and Tomasella (2002)": VGOption = 'HodnettTomasella_2002' else: log.error('Invalid PTF option') sys.exit() # Set carbon content choice if carbonContent == 'Organic carbon': carbContent = 'OC' elif carbonContent == 'Organic matter': carbContent = 'OM' else: log.error('Invalid carbon content option') sys.exit() # Unpack 'VG pressure heads' parameter if VGPressures is None: VGPressArray = [] else: VGPressArray = VGPressures.split(' ') # Pull out PTFinfo PTFInfo = PTFdatabase.checkPTF(VGOption) PTFType = PTFInfo.PTFType PTFUnit = PTFInfo.PTFUnit PTFOut = [("VGOption", VGOption), ("PTFType", PTFType), ("UserUnitPlot", unitsPlot), ("carbContent", carbContent)] # Write to XML file PTFXML = os.path.join(outputFolder, "ptfinfo.xml") common.writeXML(PTFXML, PTFOut) # Call van Genuchten function calc_vg.function(outputFolder, inputShapefile, VGOption, VGPressArray, MVGChoice, fcVal, sicVal, pwpVal, carbContent, carbonConFactor) # Loading shapefile automatically if MVGChoice == True: soilParamOut = os.path.join(outputFolder, "soil_mvg.shp") else: soilParamOut = os.path.join(outputFolder, "soil_vg.shp") arcpy.SetParameter(14, soilParamOut) log.info("van Genuchten operations completed successfully") except Exception: log.exception("van Genuchten tool failed") raise
def runSystemChecks(folder=None, rerun=False): import LUCI_PTFs.lib.progress as progress # Set overwrite output arcpy.env.overwriteOutput = True # Check spatial analyst licence is available if arcpy.CheckExtension("Spatial") == "Available": arcpy.CheckOutExtension("Spatial") else: raise RuntimeError( "Spatial Analyst license not present or could not be checked out") ### Set workspaces so that temporary files are written to the LUCI scratch geodatabase ### if arcpy.ProductInfo() == "ArcServer": log.info('arcpy.env.scratchWorkspace on server: ' + str(arcpy.env.scratchWorkspace)) # Set current workspace arcpy.env.workspace = arcpy.env.scratchGDB else: # If rerunning a tool, check if scratch workspace has been set. If it has, use it as it is (with temporary rasters and feature classes from the previous run). scratchGDB = None if rerun: xmlFile = progress.getProgressFilenames(folder).xmlFile if os.path.exists(xmlFile): scratchGDB = readXML(xmlFile, 'ScratchGDB') if not arcpy.Exists(scratchGDB): log.error('Previous scratch GDB ' + str(scratchGDB) + ' does not exist. Tool cannot be rerun.') log.error('Exiting tool') sys.exit() if scratchGDB is None: # Set scratch path from values in user settings file if values present scratchPath = None try: if os.path.exists(configuration.userSettingsFile): tree = ET.parse(configuration.userSettingsFile) root = tree.getroot() scratchPath = root.find("scratchPath").text except Exception: pass # If any errors occur, ignore them. Just use the default scratch path. # Set scratch path if needed if scratchPath is None: scratchPath = configuration.scratchPath # Create scratch path folder if not os.path.exists(scratchPath): os.makedirs(scratchPath) # Remove old date/time stamped scratch folders if they exist and if they do not contain lock ArcGIS lock files. for root, dirs, files in os.walk(scratchPath): for dir in dirs: # Try to rename folder. If this is possible then no locks are held on it and it can then be removed. try: fullDirPath = os.path.join(scratchPath, dir) renamedDir = os.path.join(scratchPath, 'ready_for_deletion') os.rename(fullDirPath, renamedDir) except Exception: # import traceback # log.warning(traceback.format_exc()) pass else: try: shutil.rmtree(renamedDir) except Exception: # import traceback # log.warning(traceback.format_exc()) pass # Create new date/time stamped scratch folder for the scratch GDB to live in dateTimeStamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") scratchGDBFolder = os.path.join(scratchPath, 'scratch_' + dateTimeStamp) if not os.path.exists(scratchGDBFolder): os.mkdir(scratchGDBFolder) # Create scratch GDB scratchGDB = os.path.join(scratchGDBFolder, 'scratch.gdb') if not os.path.exists(scratchGDB): arcpy.CreateFileGDB_management(os.path.dirname(scratchGDB), os.path.basename(scratchGDB)) # Try to remove old scratch path if still exists try: shutil.rmtree(configuration.oldScratchPath, ignore_errors=True) except Exception: pass # Set scratch and current workspaces arcpy.env.scratchWorkspace = scratchGDB arcpy.env.workspace = scratchGDB # Scratch folder scratchFolder = arcpy.env.scratchFolder if not os.path.exists(scratchFolder): os.mkdir(scratchFolder) # Remove all in_memory data sets arcpy.Delete_management("in_memory") # Check disk space for disk with scratch workspace freeSpaceGb = 3 if getFreeDiskSpaceGb(arcpy.env.scratchWorkspace) < freeSpaceGb: log.warning("Disk containing scratch workspace has less than " + str(freeSpaceGb) + "Gb free space. This may cause this tool to fail.")
def function(outputFolder, inputFolder, KsatOption, carbContent, carbonConFactor): try: # Set temporary variables prefix = os.path.join(arcpy.env.scratchGDB, "moist_") # Set output filename outputShp = os.path.join(outputFolder, "Ksat.shp") ## From the input folder, pull the PTFinfo PTFxml = os.path.join(inputFolder, "ptfinfo.xml") if not os.path.exists(PTFxml): log.error( 'Please run the point-PTF or vg-PTF tool first before running this tool' ) sys.exit() else: PTFType = common.readXML(PTFxml, 'PTFType') if PTFType == "pointPTF": inputShp = os.path.join(inputFolder, "soil_point_ptf.shp") elif PTFType == "vgPTF": inputShp = os.path.join(inputFolder, "soil_vg.shp") else: log.error( 'Please run the point-PTF or vg-PTF tool first before running this tool' ) sys.exit() # Copy the input shapefile to the output folder arcpy.CopyFeatures_management(inputShp, outputShp) # Check if the K_sat field already exists in the shapefile if common.CheckField(outputShp, "K_sat"): log.error('K_sat field already present in the output shapefile') sys.exit() if KsatOption == 'Cosby_1984': warningArray, K_satArray = ksat_PTFs.Cosby_1984( outputFolder, outputShp) elif KsatOption == 'Puckett_1985': warningArray, K_satArray = ksat_PTFs.Puckett_1985( outputFolder, outputShp) elif KsatOption == 'Jabro_1992': warningArray, K_satArray = ksat_PTFs.Jabro_1992( outputFolder, outputShp) elif KsatOption == 'CampbellShiozawa_1994': warningArray, K_satArray = ksat_PTFs.CampbellShiozawa_1994( outputFolder, outputShp) elif KsatOption == 'FerrerJulia_2004_1': warningArray, K_satArray = ksat_PTFs.FerrerJulia_2004_1( outputFolder, outputShp) elif KsatOption == 'FerrerJulia_2004_2': warningArray, K_satArray = ksat_PTFs.FerrerJulia_2004_2( outputFolder, outputShp, carbonConFactor, carbContent) elif KsatOption == 'Ahuja_1989': warningArray, K_satArray = ksat_PTFs.Ahuja_1989( outputFolder, outputShp) elif KsatOption == 'MinasnyMcBratney_2000': warningArray, K_satArray = ksat_PTFs.MinasnyMcBratney_2000( outputFolder, outputShp) elif KsatOption == 'Brakensiek_1984': warningArray, K_satArray = ksat_PTFs.Brakensiek_1984( outputFolder, outputShp) else: log.error("Invalid KsatOption: " + str(KsatOption)) sys.exit() # Write results to output shapefile arcpy.AddField_management(outputShp, "warning", "TEXT") arcpy.AddField_management(outputShp, "K_sat", "DOUBLE", 10, 6) outputFields = ["warning", "K_sat"] recordNum = 0 with arcpy.da.UpdateCursor(outputShp, outputFields) as cursor: for row in cursor: row[0] = warningArray[recordNum] row[1] = K_satArray[recordNum] cursor.updateRow(row) recordNum += 1 log.info( "Results written to the output shapefile inside the output folder") except Exception: arcpy.AddError("Saturated hydraulic conductivity function failed") raise finally: # Remove feature layers from memory try: for lyr in common.listFeatureLayers(locals()): arcpy.Delete_management(locals()[lyr]) exec(lyr + ' = None') in locals() except Exception: pass
def checkPTF(PTFOption): class PTF: def __init__(self, PTFType, PTFPressures, PTFUnit, PTFFields=None): self.PTFType = PTFType self.PTFPressures = PTFPressures self.PTFUnit = PTFUnit self.PTFFields = PTFFields if PTFOption == "Nguyen_2014": PTFType = "pointPTF" PTFPressures = [1, 3, 6, 10, 20, 33, 100, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Adhikary_2008": PTFType = "pointPTF" PTFPressures = [10, 33, 100, 300, 500, 1000, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Rawls_1982": PTFType = "pointPTF" PTFPressures = [10, 20, 33, 50, 100, 200, 400, 700, 1000, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Hall_1977_top": PTFType = "pointPTF" PTFPressures = [5, 10, 33, 200, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Hall_1977_sub": PTFType = "pointPTF" PTFPressures = [5, 10, 33, 200, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "GuptaLarson_1979": PTFType = "pointPTF" PTFPressures = [4, 7, 10, 20, 33, 60, 100, 200, 400, 700, 1000, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Batjes_1996": PTFType = "pointPTF" PTFPressures = [0, 1, 3, 5, 10, 20, 33, 50, 250, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "SaxtonRawls_2006": PTFType = "pointPTF" PTFPressures = [0, 33, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Pidgeon_1972": PTFType = "pointPTF" PTFPressures = [10, 33, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif str(PTFOption[0:8]) == "Lal_1978": PTFType = "pointPTF" PTFPressures = [0, 10, 33, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "AinaPeriaswamy_1985": PTFType = "pointPTF" PTFPressures = [33, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "ManriqueJones_1991": PTFType = "pointPTF" PTFPressures = [33, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "vanDenBerg_1997": PTFType = "pointPTF" PTFPressures = [10, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "TomasellaHodnett_1998": PTFType = "pointPTF" PTFPressures = [0, 1, 3, 6, 10, 33, 100, 500, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Reichert_2009_OM": PTFType = "pointPTF" PTFPressures = [6, 10, 33, 100, 500, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Reichert_2009": PTFType = "pointPTF" PTFPressures = [10, 33, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Botula_2013": PTFType = "pointPTF" PTFPressures = [1, 3, 6, 10, 20, 33, 100, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "ShwethaVarija_2013": PTFType = "pointPTF" PTFPressures = [33, 100, 300, 500, 1000, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Dashtaki_2010_point": PTFType = "pointPTF" PTFPressures = [10, 30, 100, 300, 500, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Santra_2018_OC": PTFType = "pointPTF" PTFPressures = [33, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif PTFOption == "Santra_2018": PTFType = "pointPTF" PTFPressures = [33, 1500] PTFUnit = "kPa" PTFFields = setOutputFields(PTFPressures, PTFUnit) elif str(PTFOption[0:11]) == "Wosten_1999": PTFType = "vgPTF" PTFPressures = "SMRC" PTFUnit = "cm" # original units of Wosten et al. (1999) PTFFields = ["warning"] elif PTFOption == "Vereecken_1989": PTFType = "vgPTF" PTFPressures = "SMRC" PTFUnit = "cm" # original units of Vereecken et al. (1989) PTFFields = ["warning"] elif PTFOption == "ZachariasWessolek_2007": PTFType = "vgPTF" PTFPressures = "SMRC" PTFUnit = "kPa" # original units of Zacharias and Wessolek (2007) PTFFields = ["warning"] elif PTFOption == "Weynants_2009": PTFType = "vgPTF" PTFPressures = "SMRC" PTFUnit = "cm" # original units of Weynants et al. (2009) PTFFields = ["warning"] elif PTFOption == "Dashtaki_2010_vg": PTFType = "vgPTF" PTFPressures = "SMRC" PTFUnit = "cm" # original units of Dashtaki et al. (2010) PTFFields = ["warning"] elif PTFOption == "HodnettTomasella_2002": PTFType = "vgPTF" PTFPressures = "SMRC" PTFUnit = "kPa" # original units of Hodnett and Tomasella (2002) PTFFields = ["warning"] elif PTFOption == "Cosby_1984": PTFType = "ksatPTF" PTFPressures = "Ksat" PTFUnit = "mmhr" PTFFields = ["warning", "K_sat"] elif PTFOption == "Puckett_1985": PTFType = "ksatPTF" PTFPressures = "Ksat" PTFUnit = "mmhr" PTFFields = ["warning", "K_sat"] elif PTFOption == "Jabro_1992": PTFType = "ksatPTF" PTFPressures = "Ksat" PTFUnit = "mmhr" PTFFields = ["warning", "K_sat"] elif PTFOption == "CampbellShiozawa_1994": PTFType = "ksatPTF" PTFPressures = "Ksat" PTFUnit = "mmhr" PTFFields = ["warning", "K_sat"] elif PTFOption == "FerrerJulia_2004_1": PTFType = "ksatPTF" PTFPressures = "Ksat" PTFUnit = "mmhr" PTFFields = ["warning", "K_sat"] elif PTFOption == "FerrerJulia_2004_2": PTFType = "ksatPTF" PTFPressures = "Ksat" PTFUnit = "mmhr" PTFFields = ["warning", "K_sat"] elif PTFOption == "Ahuja_1989": PTFType = "ksatPTF" PTFPressures = "Ksat" PTFUnit = "mmhr" PTFFields = ["warning", "K_sat"] elif PTFOption == "MinasnyMcBratney_2000": PTFType = "ksatPTF" PTFPressures = "Ksat" PTFUnit = "mmhr" PTFFields = ["warning", "K_sat"] elif PTFOption == "Brakensiek_1984": PTFType = "ksatPTF" PTFPressures = "Ksat" PTFUnit = "mmhr" PTFFields = ["warning", "K_sat"] elif PTFOption == "Cosby_1984_SandC_BC": PTFType = "bcPTF" PTFPressures = "bc" PTFUnit = "cm" PTFFields = ["warning", "WC_res", "WC_sat", "lambda_BC", "hb_BC"] elif PTFOption == "Cosby_1984_SSC_BC": PTFType = "bcPTF" PTFPressures = "bc" PTFUnit = "cm" PTFFields = ["warning", "WC_res", "WC_sat", "lambda_BC", "hb_BC"] elif PTFOption == "RawlsBrakensiek_1985_BC": PTFType = "bcPTF" PTFPressures = "bc" PTFUnit = "cm" PTFFields = ["warning", "WC_res", "WC_sat", "lambda_BC", "hb_BC"] elif PTFOption == "CampbellShiozawa_1992_BC": PTFType = "bcPTF" PTFPressures = "bc" PTFUnit = "cm" PTFFields = ["warning", "WC_res", "WC_sat", "lambda_BC", "hb_BC"] elif PTFOption == "Saxton_1986_BC": PTFType = "bcPTF" PTFPressures = "bc" PTFUnit = "kPa" PTFFields = ["warning", "WC_res", "WC_sat", "lambda_BC", "hb_BC"] elif PTFOption == "SaxtonRawls_2006_BC": PTFType = "bcPTF" PTFPressures = "bc" PTFUnit = "kPa" PTFFields = ["warning", "WC_res", "WC_sat", "lambda_BC", "hb_BC"] else: log.error("PTF option not recognised: " + str(PTFOption)) return PTF(PTFType, PTFPressures, PTFUnit, PTFFields)
def writeXML(XMLfile, nodeNameValueList): ''' Writes nodename/value pairs to an XML file. The file is created if it does not alredy exist. These nodes must live as children of the top level node (typically <data>). nodeNameValueList should have the format [(nodename, value), (nodename, value), ...] ''' def createElement(parent, name): try: found = False for child in parent.getchildren(): if child.tag == name: found = True if not found: parent.append(ET.Element(name)) except Exception: log.error("Could not create element " + name) raise def setElementValue(parent, name, value, attrib=None): try: elem = findElement(parent, name) elem.text = value if attrib is not None: elem.set('displayName', attrib) except Exception: log.error("Could not set value for element " + name) raise def findElement(parent, name): try: elem = None for child in parent.getchildren(): if child.tag == name: elem = child return elem except Exception: log.error("Could not find element " + name) raise # WriteXML main function code try: # Create file if does not exist try: if not os.path.exists(XMLfile): root = ET.Element("data") tree = ET.ElementTree(root) tree.write(XMLfile, encoding="utf-8", xml_declaration=True) else: # Open file for reading tree = ET.parse(XMLfile) root = tree.getroot() except Exception: log.error("Problem creating or opening XML file") raise # Loop through node/value list for nodeNameValue in nodeNameValueList: nodeName = nodeNameValue[0] value = nodeNameValue[1] if len(nodeNameValue) == 3: attrib = nodeNameValue[2] else: attrib = None # Check if node exists node = findElement(root, nodeName) if node is None: createElement(root, nodeName) # Create new node setElementValue(root, nodeName, value, attrib) try: # Make XML file more human-readable indentXML(root) # Save the XML file tree.write(XMLfile, encoding='utf-8', xml_declaration=True) except Exception: log.error("Problem saving XML file") raise except Exception: log.error("Data not written to XML file") raise
def pressureFields(outputFolder, inputShp, fieldFC, fieldSIC, fieldPWP): # Check PTF information PTFxml = os.path.join(outputFolder, "ptfinfo.xml") PTFOption = common.readXML(PTFxml, 'VGOption') PTFInfo = PTFdatabase.checkPTF(PTFOption) PTFType = PTFInfo.PTFType PTFPressures = PTFInfo.PTFPressures # Get OIDField OIDField = arcpy.Describe(inputShp).OIDFieldName fcArray = [] sicArray = [] pwpArray = [] # Check the field capacity field if common.CheckField(inputShp, fieldFC): with arcpy.da.SearchCursor(inputShp, [fieldFC, OIDField]) as searchCursor: for row in searchCursor: fc_kPa = row[0] if PTFType == 'vgPTF': if fc_kPa < 6 or fc_kPa > 33: log.warning("Field capacity for soil in row " + str(OIDField) + " should be between 6 to 33 kPa") fcArray.append(fc_kPa) elif PTFType == 'pointPTF': # Check if this pressure point is inside the array if fc_kPa in PTFPressures: fcArray.append(fc_kPa) else: log.error( "Pressure for field capacity NOT present in point-PTF pressures" ) log.error( "Cannot calculate water content at this pressure for field capacity" ) sys.exit() else: log.error("PTF type not recognised: " + str(PTFType)) else: log.error("Field for field capacity not found in input shapefle: " + str(fieldFC)) sys.exit() if fieldSIC is not None: if common.CheckField(inputShp, fieldSIC): with arcpy.da.SearchCursor(inputShp, [fieldSIC, OIDField]) as searchCursor: for row in searchCursor: sic_kPa = row[0] if PTFType == 'vgPTF': ## TODO: Put in a check for the stoma closure pressure ## TODO: Need to know what is a realistic range for the SIC presusre sicArray.append(sic_kPa) elif PTFType == 'pointPTF': # Check if this pressure point is inside the array if sic_kPa in PTFPressures: sicArray.append(sic_kPa) else: log.error( "Pressure for stoma closure due to water stress NOT present in point-PTF pressures" ) log.error( "Cannot calculate water content at this pressure for stoma closure due to water stress" ) sys.exit() else: log.error("PTF type not recognised: " + str(PTFType)) else: log.error( "Field for water stress-induced stomatal closure not found in input shapefle: " + str(fieldFC)) else: log.warning( "Field for water stress-induced stomatal closure not specified") log.warning("Using default value of 100 kPa") defaultSIC = 100.0 # Populate sicArray for i in range(0, len(fcArray)): sicArray.append(defaultSIC) if fieldPWP is not None: if common.CheckField(inputShp, fieldPWP): with arcpy.da.SearchCursor(inputShp, [fieldPWP, OIDField]) as searchCursor: for row in searchCursor: pwp_kPa = row[0] if PTFType == 'vgPTF': if pwp_kPa > 1500: log.warning( "Permanent wilting point for soil in row " + str(OIDField) + " exceeds 1500 kPa") ## ASK B: vg not valid for over 1500 kPa? log.warning( "The van Genuchten equation is not valid for pressures greater than 1500 kPa" ) pwpArray.append(pwp_kPa) elif PTFType == 'pointPTF': # Check if this pressure point is inside the array if pwp_kPa in pwp_kPa: pwpArray.append(pwp_kPa) else: log.error( "Pressure for permanent wilting point NOT present in point-PTF pressures" ) log.error( "Cannot calculate water content at this pressure for permanent wilting point" ) sys.exit() else: log.error("PTF type not recognised: " + str(PTFType)) else: log.error( "Field for permanent wilting point not found in input shapefle: " + str(fieldFC)) else: log.warning("Field for permanent wilting point not specified") log.warning("Using default value of 1500 kPa") defaultPWP = 1500.0 # Populate pwpArray for i in range(0, len(fcArray)): pwpArray.append(defaultPWP) # log.info('DEBUG: fcArray: ' + str(fcArray)) # log.info('DEBUG: sicArray: ' + str(sicArray)) # log.info('DEBUG: pwpArray: ' + str(pwpArray)) return fcArray, sicArray, pwpArray
def function(params): try: pText = common.paramsAsText(params) # Get inputs runSystemChecks = common.strToBool(pText[1]) outputFolder = pText[2] inputShapefile = pText[3] PTFChoice = common.strToBool(pText[4]) PTF = pText[5] VGChoice = common.strToBool(pText[6]) VG = pText[7] VGPressures = pText[8] MVGChoice = common.strToBool(pText[9]) MVG = pText[10] carbonContent = pText[11] carbonConFactor = pText[12] # Rerun parameter may not present when tool run as part of a batch run tool. If it is not, set rerun to False. try: rerun = common.strToBool(pText[13]) except IndexError: rerun = False except Exception: raise # Create output folder if not os.path.exists(outputFolder): os.mkdir(outputFolder) # System checks and setup if runSystemChecks: common.runSystemChecks(outputFolder, rerun) # Set up logging output to file log.setupLogging(outputFolder) # Set up progress log file progress.initProgress(outputFolder, rerun) # Write input params to XML common.writeParamsToXML(params, outputFolder) if PTFChoice == True and VGChoice == False: log.info('Soil water content will be calculated using a PTF') elif PTFChoice == False and VGChoice == True: log.info( 'Soil water content will be calculated using the van Genuchten model' ) elif PTFChoice == False and VGChoice == False: log.error('Method for soil water content not chosen') log.error( 'Please tick box to choose either PTF method or van Genuchten method' ) sys.exit() elif PTFChoice == True and VGChoice == True: log.error('Both PTF and van Genuchten methods chosen') log.error('Please only pick one or the other') sys.exit() # Set option of PTF if PTF == 'Nguyen et al. (2014)': PTFOption = 'Nguyen_2014' elif PTF == 'Adhikary et al. (2008)': PTFOption = 'Adhikary_2014' elif PTF == 'Rawls et al. (1982)': PTFOption = 'Rawls_1982' elif PTF == 'Saxton et al. (1986)': PTFOption = 'Saxton_1986' elif PTF == 'Hall et al. (1977) topsoil': PTFOption = 'Hall_1977_top' elif PTF == 'Hall et al. (1977) subsoil': PTFOption = 'Hall_1977_sub' elif PTF == 'Gupta and Larson (1979)': PTFOption = 'GuptaLarson_1979' elif PTF == 'Batjes (1996)': PTFOption = 'Batjes_1996' elif PTF == 'Saxton and Rawls (2006)': PTFOption = 'SaxtonRawls_2006' elif PTF == 'Pidgeon (1972)': PTFOption = 'Pidgeon_1972' elif PTF == 'Lal (1978)': PTFOption = 'Lal_1978' elif PTF == 'Aina and Periaswamy (1985)': PTFOption = 'AinaPeriaswamy_1985' elif PTF == 'Manrique and Jones (1991)': PTFOption = 'ManriqueJones_1991' elif PTF == 'van Den Berg et al. (1997)': PTFOption = 'vanDenBerg_1997' elif PTF == 'Tomasella and Hodnett (1998)': PTFOption = 'TomasellaHodnett_1998' elif PTF == 'Reichert et al. (2009) - Sand, silt, clay, OM, BD': PTFOption = 'Reichert_2009_OM' elif PTF == 'Reichert et al. (2009) - Sand, silt, clay, BD': PTFOption = 'Reichert_2009' elif PTF == 'Botula Manyala (2013)': PTFOption = 'Botula_2013' elif PTF == 'Shwetha and Varija (2013)': PTFOption = 'ShwethaVarija_2013' elif PTF == 'Dashtaki et al. (2010)': PTFOption = 'Dashtaki_2010' elif PTF == 'Santra et al. (2018)': PTFOption = 'Santra_2018' else: log.error('Invalid PTF option') sys.exit() if VG == "Wosten et al. (1999) topsoil": VGOption = "Wosten_1999_top" elif VG == "Wosten et al. (1999) subsoil": VGOption = "Wosten_1999_sub" elif VG == "Vereecken et al. (1989)": VGOption = "Vereecken_1989" elif VG == "Zacharias and Wessolek (2007)": VGOption = "ZachariasWessolek_2007" elif VG == "Weynants et al. (2009)": VGOption = "Weynants_2009" elif VG == "Dashtaki et al. (2010)": VGOption = 'Dashtaki_2010' elif VG == "Hodnett and Tomasella (2002)": VGOption = 'HodnettTomasella_2002' else: log.error('Invalid PTF option') sys.exit() # Set Mualem-Van Genuchten choice if MVG == "Wosten et al. (1999) topsoil": MVGOption = "Wosten_1999_top" elif MVG == "Wosten et al. (1999) subsoil": MVGOption = "Wosten_1999_sub" elif MVG == 'Weynants et al. (2009)': MVGOption = 'Weynants_2009' else: log.error('Invalid Mualem-Van Genuchten option') sys.exit() # Set carbon content choice if carbonContent == 'Organic carbon': carbContent = 'OC' elif carbonContent == 'Organic matter': carbContent = 'OM' else: log.error('Invalid carbon content option') sys.exit() # Unpack 'VG pressure heads' parameter if VGPressures is None: VGPressArray = [] else: VGPressArray = VGPressures.split(' ') # Call soil parameterisation function SoilParam.function(outputFolder, inputShapefile, PTFChoice, PTFOption, VGChoice, VGOption, VGPressArray, MVGChoice, MVGOption, carbContent, carbonConFactor, rerun) # Loading shapefile automatically soilParamOut = os.path.join(outputFolder, "soilParam.shp") arcpy.SetParameter(14, soilParamOut) log.info("Soil parameterisation operations completed successfully") except Exception: log.exception("Soil parameterisation tool failed") raise
def function(outputFolder, inputShp, VGOption, VGPressArray, MVGChoice, fcVal, sicVal, pwpVal, carbContent, carbonConFactor): try: # Set temporary variables prefix = os.path.join(arcpy.env.scratchGDB, "soil_") # Set output filename if MVGChoice == True: outputShp = os.path.join(outputFolder, "soil_mvg.shp") else: outputShp = os.path.join(outputFolder, "soil_vg.shp") # Copy the input shapefile to the output folder arcpy.CopyFeatures_management(inputShp, outputShp) ############################################## ### Calculate the van Genuchten parameters ### ############################################## # Get the nameArray nameArray = [] with arcpy.da.SearchCursor(outputShp, "LUCIname") as searchCursor: for row in searchCursor: name = row[0] nameArray.append(name) # Initialise the van Genuchten parameter arrays # All VG PTFs should return these arrays WC_residualArray = [] WC_satArray = [] alpha_VGArray = [] n_VGArray = [] m_VGArray = [] # Call VG PTF here depending on VGOption if str(VGOption[0:11]) == "Wosten_1999": # Has option to calculate Mualem-van Genuchten WC_residualArray, WC_satArray, alpha_VGArray, n_VGArray, m_VGArray, l_MvGArray, K_satArray = vg_PTFs.Wosten_1999(outputShp, VGOption, carbonConFactor, carbContent, MVGChoice) elif VGOption == "Vereecken_1989": WC_residualArray, WC_satArray, alpha_VGArray, n_VGArray, m_VGArray = vg_PTFs.Vereecken_1989(outputShp, VGOption, carbonConFactor, carbContent) elif VGOption == "ZachariasWessolek_2007": WC_residualArray, WC_satArray, alpha_VGArray, n_VGArray, m_VGArray = vg_PTFs.ZachariasWessolek_2007(outputShp, VGOption, carbonConFactor, carbContent) elif VGOption == "Weynants_2009": # Has option to calculate Mualem-van Genuchten WC_residualArray, WC_satArray, alpha_VGArray, n_VGArray, m_VGArray, l_MvGArray, K_satArray = vg_PTFs.Weynants_2009(outputShp, VGOption, carbonConFactor, carbContent, MVGChoice) elif VGOption == "Dashtaki_2010_vg": WC_residualArray, WC_satArray, alpha_VGArray, n_VGArray, m_VGArray = vg_PTFs.Dashtaki_2010(outputShp, VGOption, carbonConFactor, carbContent) elif VGOption == "HodnettTomasella_2002": WC_residualArray, WC_satArray, alpha_VGArray, n_VGArray, m_VGArray = vg_PTFs.HodnettTomasella_2002(outputShp, VGOption, carbonConFactor, carbContent) else: log.error("Van Genuchten option not recognised: " + str(VGOption)) sys.exit() # Write VG parameter results to output shapefile vanGenuchten.writeVGParams(outputShp, WC_residualArray, WC_satArray, alpha_VGArray, n_VGArray, m_VGArray) # Plot VG parameters vanGenuchten.plotVG(outputFolder, WC_residualArray, WC_satArray, alpha_VGArray, n_VGArray, m_VGArray, nameArray, fcVal, sicVal, pwpVal) ############################################### ### Calculate water content using VG params ### ############################################### # Calculate water content at default pressures WC_1kPaArray = [] WC_3kPaArray = [] WC_10kPaArray = [] WC_33kPaArray = [] WC_100kPaArray = [] WC_200kPaArray = [] WC_1000kPaArray = [] WC_1500kPaArray = [] for x in range(0, len(nameArray)): WC_1kPa = vanGenuchten.calcVGfxn(1.0, WC_residualArray[x], WC_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x]) WC_3kPa = vanGenuchten.calcVGfxn(3.0, WC_residualArray[x], WC_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x]) WC_10kPa = vanGenuchten.calcVGfxn(10.0, WC_residualArray[x], WC_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x]) WC_33kPa = vanGenuchten.calcVGfxn(33.0, WC_residualArray[x], WC_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x]) WC_100kPa = vanGenuchten.calcVGfxn(100.0, WC_residualArray[x], WC_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x]) WC_200kPa = vanGenuchten.calcVGfxn(200.0, WC_residualArray[x], WC_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x]) WC_1000kPa = vanGenuchten.calcVGfxn(1000.0, WC_residualArray[x], WC_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x]) WC_1500kPa = vanGenuchten.calcVGfxn(1500.0, WC_residualArray[x], WC_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x]) WC_1kPaArray.append(WC_1kPa) WC_3kPaArray.append(WC_3kPa) WC_10kPaArray.append(WC_10kPa) WC_33kPaArray.append(WC_33kPa) WC_100kPaArray.append(WC_100kPa) WC_200kPaArray.append(WC_200kPa) WC_1000kPaArray.append(WC_1000kPa) WC_1500kPaArray.append(WC_1500kPa) common.writeOutputWC(outputShp, WC_1kPaArray, WC_3kPaArray, WC_10kPaArray, WC_33kPaArray, WC_100kPaArray, WC_200kPaArray, WC_1000kPaArray, WC_1500kPaArray) # Write water content at user-input pressures # Initialise the pressure head array x = np.array(VGPressArray) vgPressures = x.astype(np.float) # For the headings headings = ['Name'] for pressure in vgPressures: headName = 'WC_' + str(pressure) + "kPa" headings.append(headName) wcHeadings = headings[1:] # Initialise water content arrays wcArrays = [] # Calculate soil moisture content at custom VG pressures for x in range(0, len(nameArray)): wcValues = vanGenuchten.calcPressuresVG(nameArray[x], WC_residualArray[x], WC_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x], vgPressures) wcArrays.append(wcValues) # Write to output CSV outCSV = os.path.join(outputFolder, 'WaterContent.csv') with open(outCSV, 'wb') as csv_file: writer = csv.writer(csv_file) writer.writerow(headings) for i in range(0, len(nameArray)): row = wcArrays[i] writer.writerow(row) msg = 'Output CSV with water content saved to: ' + str(outCSV) log.info(msg) csv_file.close() ################################################## ### Calculate water content at critical points ### ################################################## # Initialise water content arrays wc_satCalc = [] wc_fcCalc = [] wc_sicCalc = [] wc_pwpCalc = [] wc_DW = [] wc_RAW = [] wc_NRAW = [] wc_PAW = [] for i in range(0, len(nameArray)): wc_sat = vanGenuchten.calcVGfxn(0, WC_residualArray[i], WC_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i]) wc_fc = vanGenuchten.calcVGfxn(float(fcVal), WC_residualArray[i], WC_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i]) wc_sic = vanGenuchten.calcVGfxn(float(sicVal), WC_residualArray[i], WC_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i]) wc_pwp = vanGenuchten.calcVGfxn(float(pwpVal), WC_residualArray[i], WC_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i]) drainWater = wc_sat - wc_fc readilyAvailWater = wc_fc - wc_sic notRAW = wc_sic - wc_pwp PAW = wc_fc - wc_pwp checks_PTFs.checkNegValue("Drainable water", drainWater, nameArray[i]) checks_PTFs.checkNegValue("Readily available water", readilyAvailWater, nameArray[i]) checks_PTFs.checkNegValue("Not readily available water", notRAW, nameArray[i]) checks_PTFs.checkNegValue("Not readily available water", PAW, nameArray[i]) wc_satCalc.append(wc_sat) wc_fcCalc.append(wc_fc) wc_sicCalc.append(wc_sic) wc_pwpCalc.append(wc_pwp) wc_DW.append(drainWater) wc_RAW.append(readilyAvailWater) wc_NRAW.append(notRAW) wc_PAW.append(PAW) common.writeOutputCriticalWC(outputShp, wc_satCalc, wc_fcCalc, wc_sicCalc, wc_pwpCalc, wc_DW, wc_RAW, wc_NRAW, wc_PAW) ############################################ ### Calculate using Mualem-van Genuchten ### ############################################ if MVGChoice == True: if VGOption in ["Wosten_1999_top", "Wosten_1999_sub", "Weynants_2009"]: # Allow for calculation of MVG log.info("Calculating and plotting MVG") # Write l_MvGArray to outputShp arcpy.AddField_management(outputShp, "l_MvG", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "l_MvG") as cursor: for row in cursor: row[0] = l_MvGArray[recordNum] cursor.updateRow(row) recordNum += 1 # Plot MVG vanGenuchten.plotMVG(outputFolder, K_satArray, alpha_VGArray, n_VGArray, m_VGArray, l_MvGArray, WC_satArray, WC_residualArray, nameArray) # Calculate K at default pressures # Calculate at the pressures using the function K_1kPaArray = [] K_3kPaArray = [] K_10kPaArray = [] K_33kPaArray = [] K_100kPaArray = [] K_200kPaArray = [] K_1000kPaArray = [] K_1500kPaArray = [] for i in range(0, len(nameArray)): K_1kPa = vanGenuchten.calcKhfxn(1.0, K_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i], l_MvGArray[i]) K_3kPa = vanGenuchten.calcKhfxn(3.0, K_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i], l_MvGArray[i]) K_10kPa = vanGenuchten.calcKhfxn(10.0, K_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i], l_MvGArray[i]) K_33kPa = vanGenuchten.calcKhfxn(33.0, K_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i], l_MvGArray[i]) K_100kPa = vanGenuchten.calcKhfxn(100.0, K_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i], l_MvGArray[i]) K_200kPa = vanGenuchten.calcKhfxn(200.0, K_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i], l_MvGArray[i]) K_1000kPa = vanGenuchten.calcKhfxn(1000.0, K_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i], l_MvGArray[i]) K_1500kPa = vanGenuchten.calcKhfxn(1500.0, K_satArray[i], alpha_VGArray[i], n_VGArray[i], m_VGArray[i], l_MvGArray[i]) K_1kPaArray.append(K_1kPa) K_3kPaArray.append(K_3kPa) K_10kPaArray.append(K_10kPa) K_33kPaArray.append(K_33kPa) K_100kPaArray.append(K_100kPa) K_200kPaArray.append(K_200kPa) K_1000kPaArray.append(K_1000kPa) K_1500kPaArray.append(K_1500kPa) # Write to the shapefile MVGFields = ["K_1kPa", "K_3kPa", "K_10kPa", "K_33kPa", "K_100kPa", "K_200kPa", "K_1000kPa", "K_1500kPa"] # Add fields for field in MVGFields: arcpy.AddField_management(outputShp, field, "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, MVGFields) as cursor: for row in cursor: row[0] = K_1kPaArray[recordNum] row[1] = K_3kPaArray[recordNum] row[2] = K_10kPaArray[recordNum] row[3] = K_33kPaArray[recordNum] row[4] = K_100kPaArray[recordNum] row[5] = K_200kPaArray[recordNum] row[6] = K_1000kPaArray[recordNum] row[7] = K_1500kPaArray[recordNum] cursor.updateRow(row) recordNum += 1 log.info("Unsaturated hydraulic conductivity at default pressures written to output shapefile") # Calculate K at custom pressures # Initialise the pressure head array x = np.array(VGPressArray) vgPressures = x.astype(np.float) # For the headings headings = ['Name'] for pressure in vgPressures: headName = 'K_' + str(pressure) + "kPa" headings.append(headName) kHeadings = headings[1:] # Initialise K arrays kArrays = [] # Calculate K content at custom VG pressures for x in range(0, len(nameArray)): kValues = vanGenuchten.calcPressuresMVG(nameArray[x], K_satArray[x], alpha_VGArray[x], n_VGArray[x], m_VGArray[x], l_MvGArray[x], vgPressures) kArrays.append(kValues) # Write to output CSV outCSV = os.path.join(outputFolder, 'K_MVG.csv') with open(outCSV, 'wb') as csv_file: writer = csv.writer(csv_file) writer.writerow(headings) for i in range(0, len(nameArray)): row = kArrays[i] writer.writerow(row) msg = 'Output CSV with unsaturated hydraulic conductivity saved to: ' + str(outCSV) log.info(msg) csv_file.close() else: log.error("Selected PTF does not calculate Mualem-van Genuchten parameters") log.error("Please select a different PTF") sys.exit() except Exception: arcpy.AddError("van Genuchten function failed") raise finally: # Remove feature layers from memory try: for lyr in common.listFeatureLayers(locals()): arcpy.Delete_management(locals()[lyr]) exec(lyr + ' = None') in locals() except Exception: pass
def function(params): try: pText = common.paramsAsText(params) # Get inputs runSystemChecks = common.strToBool(pText[1]) outputFolder = pText[2] inputFolder = pText[3] # Get equation of choice Ksat = pText[4] carbonContent = pText[5] carbonConFactor = pText[6] # Create output folder if not os.path.exists(outputFolder): os.mkdir(outputFolder) # System checks and setup if runSystemChecks: common.runSystemChecks(outputFolder) # Set up logging output to file log.setupLogging(outputFolder) # Write input params to XML common.writeParamsToXML(params, outputFolder) # Set saturated hydraulic conductivity option if Ksat == 'Cosby et al. (1984)': KsatOption = 'Cosby_1984' elif Ksat == 'Puckett et al. (1985)': KsatOption = 'Puckett_1985' elif Ksat == 'Jabro (1992)': KsatOption = 'Jabro_1992' elif Ksat == 'Campbell and Shiozawa (1994)': KsatOption = 'CampbellShiozawa_1994' elif Ksat == 'Ferrer Julia et al. (2004) - Sand': KsatOption = 'FerrerJulia_2004_1' elif Ksat == 'Ferrer Julia et al. (2004) - Sand, clay, OM': KsatOption = 'FerrerJulia_2004_2' elif Ksat == 'Ahuja et al. (1989)': KsatOption = 'Ahuja_1989' elif Ksat == 'Minasny and McBratney (2000)': KsatOption = 'MinasnyMcBratney_2000' elif Ksat == 'Brakensiek et al. (1984)': KsatOption = 'Brakensiek_1984' elif Ksat == 'Wosten et al. (1999)': KsatOption = 'Wosten_1999' log.info( '===========================================================================' ) log.info( 'Wosten et al. (1999) already calculated Ksat in the previous step' ) log.info( 'Please check the output shapefile of the previous step for the K_sat field' ) log.info( '===========================================================================' ) sys.exit() else: log.error('Invalid Ksat option') sys.exit() # Set carbon content choice if carbonContent == 'Organic carbon': carbContent = 'OC' elif carbonContent == 'Organic matter': carbContent = 'OM' else: log.error('Invalid carbon content option') sys.exit() # Pull out PTFinfo PTFInfo = PTFdatabase.checkPTF(KsatOption) PTFType = PTFInfo.PTFType PTFUnit = PTFInfo.PTFUnit PTFOut = [("KsatOption", KsatOption), ("PTFType", PTFType), ("carbContent", carbContent)] # Write to XML file PTFXML = os.path.join(outputFolder, "ksat_ptfinfo.xml") common.writeXML(PTFXML, PTFOut) CalcKsat.function(outputFolder, inputFolder, KsatOption, carbContent, carbonConFactor) # Set output filename for display KsatOut = os.path.join(outputFolder, "Ksat.shp") arcpy.SetParameter(7, KsatOut) log.info( "Saturated hydraulic conductivity operations completed successfully" ) except Exception: log.exception("Saturated hydraulic conductivity tool failed") raise
def function(outputFolder, inputShp, PTFOption, fcVal, sicVal, pwpVal, carbContent, carbonConFactor): try: # Set temporary variables prefix = os.path.join(arcpy.env.scratchGDB, "soil_") # Set output filename outputShp = os.path.join(outputFolder, "soil_point_ptf.shp") # Copy the input shapefile to the output folder arcpy.CopyFeatures_management(inputShp, outputShp) #################################### ### Calculate the water contents ### #################################### # Get the nameArray nameArray = [] with arcpy.da.SearchCursor(outputShp, "LUCIname") as searchCursor: for row in searchCursor: name = row[0] nameArray.append(name) # Get PTF fields PTFxml = os.path.join(outputFolder, "ptfinfo.xml") PTFFields = common.readXML(PTFxml, 'PTFFields') PTFPressures = common.readXML(PTFxml, 'PTFPressures') PTFUnit = common.readXML(PTFxml, 'PTFUnit') # Call point-PTF here depending on PTFOption if PTFOption == "Nguyen_2014": results = point_PTFs.Nguyen_2014(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "Adhikary_2008": results = point_PTFs.Adhikary_2008(outputFolder, outputShp) elif PTFOption == "Rawls_1982": results = point_PTFs.Rawls_1982(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "Hall_1977_top": results = point_PTFs.Hall_1977_top(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "Hall_1977_sub": results = point_PTFs.Hall_1977_sub(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "GuptaLarson_1979": results = point_PTFs.GuptaLarson_1979(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "Batjes_1996": results = point_PTFs.Batjes_1996(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "SaxtonRawls_2006": results = point_PTFs.SaxtonRawls_2006(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "Pidgeon_1972": results = point_PTFs.Pidgeon_1972(outputFolder, outputShp, carbonConFactor, carbContent) elif str(PTFOption[0:8]) == "Lal_1978": results = point_PTFs.Lal_1978(outputFolder, outputShp, PTFOption) elif PTFOption == "AinaPeriaswamy_1985": results = point_PTFs.AinaPeriaswamy_1985(outputFolder, outputShp) elif PTFOption == "ManriqueJones_1991": results = point_PTFs.ManriqueJones_1991(outputFolder, outputShp) elif PTFOption == "vanDenBerg_1997": results = point_PTFs.vanDenBerg_1997(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "TomasellaHodnett_1998": results = point_PTFs.TomasellaHodnett_1998(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "Reichert_2009_OM": results = point_PTFs.Reichert_2009_OM(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "Reichert_2009": results = point_PTFs.Reichert_2009(outputFolder, outputShp) elif PTFOption == "Botula_2013": results = point_PTFs.Botula_2013(outputFolder, outputShp) elif PTFOption == "ShwethaVarija_2013": results = point_PTFs.ShwethaVarija_2013(outputFolder, outputShp) elif PTFOption == "Dashtaki_2010_point": results = point_PTFs.Dashtaki_2010(outputFolder, outputShp) elif PTFOption == "Santra_2018_OC": results = point_PTFs.Santra_2018_OC(outputFolder, outputShp, carbonConFactor, carbContent) elif PTFOption == "Santra_2018": results = point_PTFs.Santra_2018(outputFolder, outputShp) else: log.error("PTF option not recognised") sys.exit() # Plots plots.plotPTF(outputFolder, outputShp, PTFOption, nameArray, results) ###################################################### ### Calculate water content at critical thresholds ### ###################################################### satStatus = False fcStatus = False sicStatus = False pwpStatus = False wc_satCalc = [] wc_fcCalc = [] wc_sicCalc = [] wc_pwpCalc = [] if PTFOption == "Reichert_2009_OM": log.info( 'For Reichert et al. (2009) - Sand, silt, clay, OM, BD saturation is at 6kPa' ) satField = "WC_6kPa" else: satField = "WC_0" + str(PTFUnit) fcField = "WC_" + str(int(fcVal)) + str(PTFUnit) sicField = "WC_" + str(int(sicVal)) + str(PTFUnit) pwpField = "WC_" + str(int(pwpVal)) + str(PTFUnit) wcFields = [] wcArrays = [] if satField in PTFFields: # Saturation set to 0kPa # PTFs with 0kPa: ## Saxton_1986, Batjes_1996, SaxtonRawls_2006 ## Lal_1978_Group1, Lal_1978_Group2 ## TomasellaHodnett_1998 log.info('Field with WC at saturation found!') with arcpy.da.SearchCursor(outputShp, satField) as searchCursor: for row in searchCursor: wc_sat = row[0] if wc_sat > 1.0: log.warning('Water content at saturation over 1.0') wc_satCalc.append(wc_sat) satStatus = True wcFields.append("wc_satCalc") wcArrays.append(wc_satCalc) # Add sat field to output shapefile arcpy.AddField_management(outputShp, "wc_satCalc", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "wc_satCalc") as cursor: for row in cursor: row[0] = wc_satCalc[recordNum] cursor.updateRow(row) recordNum += 1 else: log.warning('Field with WC at saturation not found') satStatus = False if fcField in PTFFields: log.info('Field with WC at field capacity found!') with arcpy.da.SearchCursor(outputShp, fcField) as searchCursor: for row in searchCursor: wc_fc = row[0] wc_fcCalc.append(wc_fc) fcStatus = True wcFields.append("wc_fcCalc") wcArrays.append(wc_fcCalc) # Add FC field to output shapefile arcpy.AddField_management(outputShp, "wc_fcCalc", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "wc_fcCalc") as cursor: for row in cursor: row[0] = wc_fcCalc[recordNum] cursor.updateRow(row) recordNum += 1 else: log.warning('Field with WC at field capacity not found') fcStatus = False if sicField in PTFFields: log.info( 'Field with WC at water stress-induced stomatal closure found!' ) with arcpy.da.SearchCursor(outputShp, sicField) as searchCursor: for row in searchCursor: wc_sic = row[0] wc_sicCalc.append(wc_sic) sicStatus = True wcFields.append("wc_sicCalc") wcArrays.append(wc_sicCalc) # Add sic field to output shapefile arcpy.AddField_management(outputShp, "wc_sicCalc", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "wc_sicCalc") as cursor: for row in cursor: row[0] = wc_sicCalc[recordNum] cursor.updateRow(row) recordNum += 1 else: log.warning( 'Field with WC at water stress-induced stomatal closure not found' ) sicStatus = False if pwpField in PTFFields: log.info('Field with WC at permanent wilting point found!') with arcpy.da.SearchCursor(outputShp, pwpField) as searchCursor: for row in searchCursor: wc_pwp = row[0] if wc_pwp < 0.01: log.warning( 'WARNING: Water content at PWP is below 0.01') elif wc_pwp < 0.05: log.warning('Water content at PWP is below 0.05') wc_pwpCalc.append(wc_pwp) pwpStatus = True wcFields.append("wc_pwpCalc") wcArrays.append(wc_pwpCalc) # Add pwp field to output shapefile arcpy.AddField_management(outputShp, "wc_pwpCalc", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "wc_pwpCalc") as cursor: for row in cursor: row[0] = wc_pwpCalc[recordNum] cursor.updateRow(row) recordNum += 1 else: log.warning('Field with WC at permanent wilting point not found') pwpStatus = False drainWater = [] PAW = [] RAW = [] NRAW = [] if satStatus == True and fcStatus == True: # drainWater = wc_sat - wc_fc drainWater = point_PTFs.calcWaterContent(wc_satCalc, wc_fcCalc, 'drainable water', nameArray) log.info('Drainable water calculated') wcFields.append("wc_DW") wcArrays.append(drainWater) # Add DW field to output shapefile arcpy.AddField_management(outputShp, "wc_DW", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "wc_DW") as cursor: for row in cursor: row[0] = drainWater[recordNum] cursor.updateRow(row) recordNum += 1 if fcStatus == True and pwpStatus == True: # PAW = wc_fc - wc_pwp PAW = point_PTFs.calcWaterContent(wc_fcCalc, wc_pwpCalc, 'plant available water', nameArray) log.info('Plant available water calculated') wcFields.append("wc_PAW") wcArrays.append(PAW) # Add PAW field to output shapefile arcpy.AddField_management(outputShp, "wc_PAW", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "wc_PAW") as cursor: for row in cursor: row[0] = PAW[recordNum] cursor.updateRow(row) recordNum += 1 pawStatus = True if fcStatus == True and sicStatus == True: # readilyAvailWater = wc_fc - wc_sic RAW = point_PTFs.calcWaterContent(wc_fcCalc, wc_sicCalc, 'readily available water', nameArray) log.info('Readily available water calculated') wcFields.append("wc_RAW") wcArrays.append(RAW) # Add wc_RAW field to output shapefile arcpy.AddField_management(outputShp, "wc_RAW", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "wc_RAW") as cursor: for row in cursor: row[0] = RAW[recordNum] cursor.updateRow(row) recordNum += 1 elif pawStatus == True: # If PAW exists, get RAW = 0.5 * RAW PAW = point_PTFs.calcWaterContent(wc_fcCalc, wc_pwpCalc, 'plant available water', nameArray) RAW = [(float(i) * 0.5) for i in PAW] log.info('Readily available water calculated based on PAW') wcFields.append("wc_RAW") wcArrays.append(RAW) # Add wc_RAW field to output shapefile arcpy.AddField_management(outputShp, "wc_RAW", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "wc_RAW") as cursor: for row in cursor: row[0] = RAW[recordNum] cursor.updateRow(row) recordNum += 1 else: log.info('Readily available water not calculated') if sicStatus == True and pwpStatus == True: # notRAW = wc_sic - wc_pwp NRAW = point_PTFs.calcWaterContent(wc_sicCalc, wc_pwpCalc, 'not readily available water', nameArray) log.info('Not readily available water calculated') wcFields.append("wc_NRAW") wcArrays.append(NRAW) # Add sat field to output shapefile arcpy.AddField_management(outputShp, "wc_NRAW", "DOUBLE", 10, 6) recordNum = 0 with arcpy.da.UpdateCursor(outputShp, "wc_NRAW") as cursor: for row in cursor: row[0] = NRAW[recordNum] cursor.updateRow(row) recordNum += 1 log.info( 'Water contents at critical thresholds written to output shapefile' ) except Exception: arcpy.AddError("Point-PTFs function failed") raise finally: # Remove feature layers from memory try: for lyr in common.listFeatureLayers(locals()): arcpy.Delete_management(locals()[lyr]) exec(lyr + ' = None') in locals() except Exception: pass
def function(outputFolder, inputShp, PTFOption, BCPressArray, fcVal, sicVal, pwpVal, carbContent, carbonConFactor): try: # Set temporary variables prefix = os.path.join(arcpy.env.scratchGDB, "bc_") tempSoils = prefix + "tempSoils" # Set output filename outputShp = os.path.join(outputFolder, "BrooksCorey.shp") # Copy the input shapefile to the output folder arcpy.CopyFeatures_management(inputShp, outputShp) # Get the nameArray nameArray = [] with arcpy.da.SearchCursor(outputShp, "LUCIname") as searchCursor: for row in searchCursor: name = row[0] nameArray.append(name) # PTFs should return: WC_res, WC_sat, lambda_BC, hb_BC if PTFOption == "Cosby_1984_SandC_BC": warning, WC_res, WC_sat, lambda_BC, hb_BC = bc_PTFs.Cosby_1984_SandC_BC( outputShp, PTFOption) elif PTFOption == "Cosby_1984_SSC_BC": warning, WC_res, WC_sat, lambda_BC, hb_BC = bc_PTFs.Cosby_1984_SSC_BC( outputShp, PTFOption) elif PTFOption == "RawlsBrakensiek_1985_BC": warning, WC_res, WC_sat, lambda_BC, hb_BC = bc_PTFs.RawlsBrakensiek_1985_BC( outputShp, PTFOption) elif PTFOption == "CampbellShiozawa_1992_BC": warning, WC_res, WC_sat, lambda_BC, hb_BC = bc_PTFs.CampbellShiozawa_1992_BC( outputShp, PTFOption) elif PTFOption == "Saxton_1986_BC": warning, WC_res, WC_sat, lambda_BC, hb_BC = bc_PTFs.Saxton_1986_BC( outputShp, PTFOption) elif PTFOption == "SaxtonRawls_2006_BC": warning, WC_res, WC_sat, lambda_BC, hb_BC = bc_PTFs.SaxtonRawls_2006_BC( outputShp, PTFOption, carbonConFactor, carbContent) else: log.error("Brooks-Corey option not recognised: " + str(PTFOption)) sys.exit() # Write to shapefile brooksCorey.writeBCParams(outputShp, warning, WC_res, WC_sat, lambda_BC, hb_BC) log.info("Brooks-Corey parameters written to output shapefile") # Create plots brooksCorey.plotBrooksCorey(outputFolder, WC_res, WC_sat, hb_BC, lambda_BC, nameArray, fcVal, sicVal, pwpVal) ############################################### ### Calculate water content using BC params ### ############################################### # Check for any soils that we were not able to calculate BC parameters for # lambda_BC[i] == -9999 errors = [] for i in range(0, len(lambda_BC)): if lambda_BC[i] == -9999: log.warning('Invalid lambda found for ' + str(nameArray[i])) errors.append(i) # Calculate water content at default pressures WC_1kPaArray = [] WC_3kPaArray = [] WC_10kPaArray = [] WC_33kPaArray = [] WC_100kPaArray = [] WC_200kPaArray = [] WC_1000kPaArray = [] WC_1500kPaArray = [] for i in range(0, len(nameArray)): pressures = [1.0, 3.0, 10.0, 33.0, 100.0, 200.0, 1000.0, 1500.0] if lambda_BC[i] != -9999: bc_WC = brooksCorey.calcBrooksCoreyFXN(pressures, hb_BC[i], WC_res[i], WC_sat[i], lambda_BC[i]) else: bc_WC = [-9999] * len(pressures) WC_1kPaArray.append(bc_WC[0]) WC_3kPaArray.append(bc_WC[1]) WC_10kPaArray.append(bc_WC[2]) WC_33kPaArray.append(bc_WC[3]) WC_100kPaArray.append(bc_WC[4]) WC_200kPaArray.append(bc_WC[5]) WC_1000kPaArray.append(bc_WC[6]) WC_1500kPaArray.append(bc_WC[7]) common.writeOutputWC(outputShp, WC_1kPaArray, WC_3kPaArray, WC_10kPaArray, WC_33kPaArray, WC_100kPaArray, WC_200kPaArray, WC_1000kPaArray, WC_1500kPaArray) # Write water content at user-input pressures # Initialise the pressure head array x = np.array(BCPressArray) bcPressures = x.astype(np.float) # For the headings headings = ['Name'] for pressure in bcPressures: headName = 'WC_' + str(pressure) + "kPa" headings.append(headName) wcHeadings = headings[1:] wcArrays = [] # Calculate soil moisture content at custom VG pressures for i in range(0, len(nameArray)): if lambda_BC[i] != -9999: wcValues = brooksCorey.calcBrooksCoreyFXN( bcPressures, hb_BC[i], WC_res[i], WC_sat[i], lambda_BC[i]) else: wcValues = [-9999] * len(bcPressures) wcValues.insert(0, nameArray[i]) wcArrays.append(wcValues) # Write to output CSV outCSV = os.path.join(outputFolder, 'WaterContent.csv') with open(outCSV, 'wb') as csv_file: writer = csv.writer(csv_file) writer.writerow(headings) for i in range(0, len(nameArray)): row = wcArrays[i] writer.writerow(row) msg = 'Output CSV with water content saved to: ' + str(outCSV) log.info(msg) csv_file.close() ################################################## ### Calculate water content at critical points ### ################################################## # Initialise water content arrays wc_satCalc = [] wc_fcCalc = [] wc_sicCalc = [] wc_pwpCalc = [] wc_DW = [] wc_RAW = [] wc_NRAW = [] wc_PAW = [] wcCriticalPressures = [0.0, fcVal, sicVal, pwpVal] for x in range(0, len(nameArray)): if lambda_BC[x] != -9999: wcCriticals = brooksCorey.calcBrooksCoreyFXN( wcCriticalPressures, hb_BC[x], WC_res[x], WC_sat[x], lambda_BC[x]) wc_sat = wcCriticals[0] wc_fc = wcCriticals[1] wc_sic = wcCriticals[2] wc_pwp = wcCriticals[3] drainWater = wc_sat - wc_fc readilyAvailWater = wc_fc - wc_sic notRAW = wc_sic - wc_pwp PAW = wc_fc - wc_pwp checks_PTFs.checkNegValue("Drainable water", drainWater, nameArray[i]) checks_PTFs.checkNegValue("Readily available water", readilyAvailWater, nameArray[i]) checks_PTFs.checkNegValue("Not readily available water", notRAW, nameArray[i]) checks_PTFs.checkNegValue("Not readily available water", PAW, nameArray[i]) else: wc_sat = -9999 wc_fc = -9999 wc_sic = -9999 wc_pwp = -9999 drainWater = -9999 readilyAvailWater = -9999 notRAW = -9999 PAW = -9999 wc_satCalc.append(wc_sat) wc_fcCalc.append(wc_fc) wc_sicCalc.append(wc_sic) wc_pwpCalc.append(wc_pwp) wc_DW.append(drainWater) wc_RAW.append(readilyAvailWater) wc_NRAW.append(notRAW) wc_PAW.append(PAW) common.writeOutputCriticalWC(outputShp, wc_satCalc, wc_fcCalc, wc_sicCalc, wc_pwpCalc, wc_DW, wc_RAW, wc_NRAW, wc_PAW) except Exception: arcpy.AddError("Brooks-Corey function failed") raise finally: # Remove feature layers from memory try: for lyr in common.listFeatureLayers(locals()): arcpy.Delete_management(locals()[lyr]) exec(lyr + ' = None') in locals() except Exception: pass
def plotBrooksCorey(outputFolder, WC_resArray, WC_satArray, hbArray, lambdaArray, nameArray, fcValue, sicValue, pwpValue): # Create Brooks-Corey plots import matplotlib.pyplot as plt import numpy as np # Check what unit the user wants to output PTFUnit = common.getInputValue(outputFolder, 'Pressure_units_plot') # Check what axis was chosen AxisChoice = common.getInputValue(outputFolder, 'Plot_axis') # Check for any soils that we were not able to calculate BC parameters for errors = [] for i in range(0, len(lambdaArray)): if lambdaArray[i] == -9999: log.warning('Invalid lambda found for ' + str(nameArray[i])) errors.append(i) # Define output folder for CSVs outFolder = os.path.join(outputFolder, 'BC_waterContents') if not os.path.exists(outFolder): os.mkdir(outFolder) ################################ ### Plot 0: individual plots ### ################################ # Plot 0: pressure on the y-axis and water content on the x-axis for i in [x for x in range(0, len(nameArray)) if x not in errors]: outName = 'bc_' + str(nameArray[i]) + '.png' outPath = os.path.join(outputFolder, outName) title = 'Brooks-Corey plot for ' + str(nameArray[i]) # Set pressure vector psi_kPa = np.linspace(0.0, 1500.0, 1501) # Calculate WC over that pressure vector bc_WC = calcBrooksCoreyFXN(psi_kPa, hbArray[i], WC_resArray[i], WC_satArray[i], lambdaArray[i]) common.writeWCCSV(outFolder, nameArray[i], psi_kPa, bc_WC, 'Pressures_kPa', 'WaterContents') ## Figure out what to do about multipliers if PTFUnit == 'kPa': pressureUnit = 'kPa' psi_plot = psi_kPa fc_plot = float(fcValue) * -1.0 sic_plot = float(sicValue) * -1.0 pwp_plot = float(pwpValue) * -1.0 elif PTFUnit == 'cm': pressureUnit = 'cm' psi_plot = 10.0 * psi_kPa fc_plot = float(fcValue) * -10.0 sic_plot = float(sicValue) * -10.0 pwp_plot = float(pwpValue) * -10.0 elif PTFUnit == 'm': pressureUnit = 'm' psi_plot = 0.1 * psi_kPa fc_plot = float(fcValue) * -0.1 sic_plot = float(sicValue) * -0.1 pwp_plot = float(pwpValue) * -0.1 # Convert psi_plot to negative for plotting psi_neg = -1.0 * psi_plot if AxisChoice == 'Y-axis': plt.plot(psi_neg, bc_WC, label=str(nameArray[i])) plt.xscale('symlog') plt.axvline(x=fc_plot, color='g', linestyle='dashed', label='FC') plt.axvline(x=sic_plot, color='m', linestyle='dashed', label='SIC') plt.axvline(x=pwp_plot, color='r', linestyle='dashed', label='PWP') plt.legend(loc="best") plt.title(title) plt.xlabel('Pressure (' + str(pressureUnit) + ')') plt.ylabel('Volumetric water content') plt.savefig(outPath, transparent=False) plt.close() log.info('Plot created for soil ' + str(nameArray[i])) elif AxisChoice == 'X-axis': plt.plot(bc_WC, psi_neg, label=str(nameArray[i])) plt.yscale('symlog') plt.axhline(y=fc_plot, color='g', linestyle='dashed', label='FC') plt.axhline(y=sic_plot, color='m', linestyle='dashed', label='SIC') plt.axhline(y=pwp_plot, color='r', linestyle='dashed', label='PWP') plt.legend(loc="best") plt.title(title) plt.ylabel('Pressure (' + str(pressureUnit) + ')') plt.xlabel('Volumetric water content') plt.savefig(outPath, transparent=False) plt.close() log.info('Plot created for soil ' + str(nameArray[i])) else: log.error( 'Invalid choice for axis plotting, please select Y-axis or X-axis' ) sys.exit() ######################### ### Plot 1: all soils ### ######################### outPath = os.path.join(outputFolder, 'plotBC_logPressure.png') title = 'Brooks-Corey plots of ' + str( len(nameArray)) + ' soils (log scale)' # Define pressure vector psi_kPa = np.linspace(0.0, 1500.0, 1501) for i in [x for x in range(0, len(nameArray)) if x not in errors]: # Calculate WC over pressure vector bc_WC = calcBrooksCoreyFXN(psi_kPa, hbArray[i], WC_resArray[i], WC_satArray[i], lambdaArray[i]) if PTFUnit == 'kPa': pressureUnit = 'kPa' psi_plot = psi_kPa elif PTFUnit == 'cm': pressureUnit = 'cm' psi_plot = 10.0 * psi_kPa elif PTFUnit == 'm': pressureUnit = 'm' psi_plot = 0.1 * psi_kPa # Convert psi to negative for plotting purposes psi_neg = -1.0 * psi_plot plt.plot(psi_neg, bc_WC, label=str(nameArray[i])) if AxisChoice == 'Y-axis': plt.xscale('symlog') plt.title(title) plt.axvline(x=fc_plot, color='g', linestyle='dashed', label='FC') plt.axvline(x=sic_plot, color='m', linestyle='dashed', label='SIC') plt.axvline(x=pwp_plot, color='r', linestyle='dashed', label='PWP') plt.ylabel('Water content') plt.xlabel('Pressure (' + str(pressureUnit) + ')') plt.legend(ncol=2, fontsize=12, loc="best") plt.savefig(outPath, transparent=False) plt.close() log.info('Plot created with water content on the y-axis') elif AxisChoice == 'X-axis': plt.yscale('symlog') plt.title(title) plt.axhline(y=fc_plot, color='g', linestyle='dashed', label='FC') plt.axhline(y=sic_plot, color='m', linestyle='dashed', label='SIC') plt.axhline(y=pwp_plot, color='r', linestyle='dashed', label='PWP') plt.xlabel('Water content') plt.ylabel('Pressure (' + str(pressureUnit) + ')') plt.legend(ncol=2, fontsize=12, loc="best") plt.savefig(outPath, transparent=False) plt.close() log.info('Plot created with water content on the y-axis') else: log.error( 'Invalid choice for axis plotting, please select Y-axis or X-axis') sys.exit()