8.3.6. Domain definition helpers
8.3.6.1. Introduction
One of ParFlow’s strengths is its customizability; you can practically define any type of hydrologic problem with it.
One of the downsides of that, however, is that setting all the keys can be cumbersome, especially when starting a run from scratch.
With the new DomainBuilder
, Python-PFTools helps condense the setting of keys for many common problem definitions.
8.3.6.2. Usage of DomainBuilder
First, we’ll show some usage examples of loading tables of parameters within a ParFlow Python script:
from parflow import Run
from parflow.tools.builders import DomainBuilder
LW_Test = Run("LW_Test", __file__)
# ----------------------------------------------------------------------------
bounds = [
0.0, 41000.0,
0.0, 41000.0,
0.0, 100.0
]
domain_patches = 'x_lower x_upper y_lower y_upper z_lower z_upper'
zero_flux_patches = 'x_lower x_upper y_lower y_upper z_lower'
DomainBuilder(LW_Test) \
.no_wells() \
.no_contaminants() \
.water('domain') \
.variably_saturated() \
.box_domain('box_input', 'domain', bounds, domain_patches) \
.homogeneous_subsurface('domain', specific_storage=1.0e-5, isotropic=True) \
.zero_flux(zero_flux_patches, 'constant', 'alltime') \
.slopes_mannings('domain', slope_x='LW.slopex.pfb', slope_y='LW.slopey.pfb', mannings=5.52e-6) \
.ic_pressure('domain', patch='z_upper', pressure='press.init.pfb')
In this example, the 10 lines associated with the instantiation of the DomainBuilder
class generate about 70 keys!
As is possible with any other key setting, you can always overwrite the keys as necessary; the DomainBuilder
is designed to help you get started.
Once you instantitate the DomainBuilder
object on a Run
object, each method will set various keys with the given arguments, which are described below.
8.3.6.3. Full API
DomainBuilder(run, name='domain')
Instantiates the
DomainBuilder
object on theRun
objectrun
.- param
run
A
Run
object- param
name
Defines the below key:
run.Domain.GeomName = name
The following examples of the method usage assume that the name of the
Run
object isrun
. All arguments for methods that are passed in as tokens in keys are denoted by{argument}
.- param
no_wells()
Sets the key
run.Wells.Names = ''
no_contaminants()
Sets the key
run.Contaminants.Names = ''
water(self, geom_name=None)
- param
geom_name
Value for
run.PhaseSources.water.GeomNames
key.
The following keys are set by this function:
run.Gravity = 1.0 run.Phase.Names = 'water' run.Phase.water.Density.Type = 'Constant' run.Phase.water.Density.Value = 1.0 run.Phase.water.Viscosity.Type = 'Constant' run.Phase.water.Viscosity.Value = 1.0 run.Phase.water.Mobility.Type = 'Constant' run.Phase.water.Mobility.Value = 1.0 run.PhaseSources.water.Type = 'Constant' # if geom_name is provided, it will set these keys: run.PhaseSources.water.GeomNames = geom_name run.PhaseSources.water.Geom.{geom_name}.Value = 0.0
- param
variably_saturated()
This function sets the following keys:
run.Solver = 'Richards' run.Solver.Nonlinear.MaxIter = 10 run.Solver.Nonlinear.ResidualTol = 1e-5 run.Solver.Nonlinear.EtaChoice = 'EtaConstant' run.Solver.Nonlinear.EtaValue = 1e-5 run.Solver.Nonlinear.UseJacobian = True run.Solver.Nonlinear.DerivativeEpsilon = 1e-2 run.Solver.Linear.Preconditioner = 'PFMG'
fully_saturated()
This function sets the following keys:
run.Solver = 'Impes'
homogeneous_subsurface(domain_name, perm=None, porosity=None, specific_storage=None, rel_perm=None, saturation=None, isotropic=False)
- param
domain_name
Value for
run.Geom.Perm.Names
key- param
perm
Value for
run.Geom.{domain_name}.Perm.Value
key- param
porosity
Value for
run.Geom.{domain_name}.Porosity.Value
key- param
specific_storage
Value for
run.Geom.{domain_name}.SpecificStorage.Value
- param
rel_perm
If provided, must be a dictionary with the following key/value pairs:
{'Type': 'VanGenuchten', 'Alpha': 3.5, 'N': 2.0}
If'Type' = 'VanGenuchten'
, the dictionary values are used to set therun.Geom.{domain_name}.RelPerm.Alpha
andrun.Geom.{domain_name}.RelPerm.N
keys, respectively.- param
saturation
If provided, must be a dictionary with the following key/value pairs:
{'Type': 'VanGenuchten', 'Alpha': 3.5, 'N': 2.0, 'SRes': 0.1, 'SSat': 1.0}
Alpha
andN
are optional, and can default to the value of the corresponding properties inrel_perm
. If'Type' = 'VanGenuchten'
, the dictionary values are used to set therun.Geom.{domain_name}.Saturation.Alpha
,run.Geom.{domain_name}.Saturation.N
,run.Geom.{domain_name}.Saturation.SRes
, andrun.Geom.{domain_name}.Saturation.SSat
keys- param
isotropic
If
True
, will setrun.Perm.TensorType
key to'TensorByGeom'
.
This function sets the following keys:
# If perm is a value, it will set these keys: # Appending domain_name to the list of Geom.Perm.Names run.Geom.Perm.Names = domain_name run.Geom.{domain_name}.Perm.Type = 'Constant' run.Geom.{domain_name}.Perm.Value = perm # If perm is a file name, it will set these keys: run.Geom.{domain_name}.Perm.FileName = perm # If the file name is a PFB file: run.Geom.{domain_name}.Perm.Type = 'PFBFile' # If the file name is a NetCDF file: run.Geom.{domain_name}.Perm.Type = 'NCFile' # If porosity is a value, it will set these keys: # Appending domain_name to the list of Geom.Porosity.Names run.Geom.Porosity.GeomNames = domain_name run.Geom.{domain_name}.Porosity.Type = 'Constant' run.Geom.{domain_name}.Porosity.Value = porosity # If porosity is a file name, it will set these keys: run.Geom.{domain_name}.Porosity.FileName = porosity # If the file name is a PFB file: run.Geom.{domain_name}.Porosity.Type = 'PFBFile' # If the file name is a NetCDF file: run.Geom.{domain_name}.Porosity.Type = 'NCFile' # If specific_storage is provided, it will set these keys: # Appending domain_name to the list of SpecificStorage.GeomNames run.SpecificStorage.GeomNames = domain_name run.SpecificStorage.Type = 'Constant' run.Geom.{domain_name}.SpecificStorage.Value = specific_storage # If rel_perm is provided, it must be a dictionary with the following key/value pairs: # {'Type': 'VanGenuchten', 'Alpha': 3.5, 'N': 2.0} # Asing this dictionary, it will set the following keys: # Appending domain_name to the list of Phase.RelPerm.GeomNames run.Phase.RelPerm.GeomNames = domain_name # If Type = VanGenuchten, it will set the following keys: self.run.Geom.{domain_name}.RelPerm.Alpha = rel_perm['Alpha'] self.run.Geom.{domain_name}.RelPerm.N = rel_perm['N'] # If saturation is provided, it must be a dictionary with the following key/value pairs: # {'Type': 'VanGenuchten', 'Alpha': 3.5, 'N': 2.0, 'SRes': 0.1, 'SSat': 1.0} # Alpha and N are optional, and can default to the value of the corresponding properties in rel_perm # Using this dictionary, it will set the following keys: # Appending domain_name to the list of Phase.Saturation.GeomNames run.Phase.Saturation.GeomNames = domain_name # If Type = VanGenuchten, it will set the following keys: run.Geom.{domain_name}.Saturation.Alpha = saturation['Alpha'] run.Geom.{domain_name}.Saturation.N = saturation['N'] run.Geom.{domain_name}.Saturation.SRes = saturation['SRes'] run.Geom.{domain_name}.Saturation.SSat = saturation['SSat'] # If isotropic is True, it will set these keys: run.Perm.TensorType = 'TensorByGeom' # Appending domain_name to the list of Geom.Perm.TensorByGeom.Names run.Geom.Perm.TensorByGeom.Names = domain_name run.Geom.{domain_name}.Perm.TensorValX = 1.0 run.Geom.{domain_name}.Perm.TensorValY = 1.0 run.Geom.{domain_name}.Perm.TensorValZ = 1.0
- param
box_domain(box_input, domain_geom_name, bounds=None, patches=None)
- param
box_input
Value for
run.GeomInput.Names
key- param
domain_geom_name
Value for
run.Geom.{domain_geom_name}
- param
bounds
A list of values in the format
[lower_x, upper_x, lower_y, upper_y, lower_z, upper_z]
, that set theLower.X
,Upper.X
,Lower.Y
,Upper.Y
,Lower.Z
, andUpper.Z
keys for therun.Geom.{domain_geom_name}
- param
patches
Value for
run.Geom.{domain_geom_name}.Patches
This function sets the following keys:
# Append box_input to the GeomInput.Names run.GeomInput.Names = box_input run.GeomInput.{box_input}.InputType = 'Box' run.GeomInput.{box_input}.GeomName = domain_geom_name # If bounds is not provided, it will default to using the ComputationalGrid keys to define the boundaries: run.Geom.{domain_geom_name}.Lower.X = 0.0 run.Geom.{domain_geom_name}.Lower.Y = 0.0 run.Geom.{domain_geom_name}.Lower.Z = 0.0 run.Geom.{domain_geom_name}.Upper.X = run.ComputationalGrid.DX * run.ComputationalGrid.NX run.Geom.{domain_geom_name}.Upper.Y = run.ComputationalGrid.DY * run.ComputationalGrid.NY run.Geom.{domain_geom_name}.Upper.Z = run.ComputationalGrid.DZ * run.ComputationalGrid.NZ # Bounds should be provided as a list of coordinates in this order: # [lower_x, upper_x, lower_y, upper_y, lower_z, upper_z] run.Geom.{domain_geom_name}.Lower.X = bounds[0] run.Geom.{domain_geom_name}.Upper.X = bounds[1] run.Geom.{domain_geom_name}.Lower.Y = bounds[2] run.Geom.{domain_geom_name}.Upper.Y = bounds[3] run.Geom.{domain_geom_name}.Lower.Z = bounds[4] run.Geom.{domain_geom_name}.Upper.Z = bounds[5] # If patches is provided as a single string of the box domain patches (e.g., 'left right ...'), it will set this key: run.Geom.{domain_geom_name}.Patches = patches
- param
slopes_mannings(self, domain_geom_name, slope_x=None, slope_y=None, mannings=None)
- param
domain_geom_name
Is appended to the value of the
run.TopoSlopesX.GeomNames
key- param
slope_x
If the value of
slope_x
is a number, this parameter sets the value for therun.TopoSlopesX.Geom.{domain_geom_name}.Value
key. If it is a filename, this parameter sets the value for therun.TopoSlopesX.FileName
key.- param
slope_y
If the value of
slope_y
is a number, this parameter sets the value for therun.TopoSlopesY.Geom.{domain_geom_name}.Value
key. If it is a filename, this parameter sets the value for therun.TopoSlopesY.FileName
key.- param
mannings
If the value of
mannings
is a number, this parameter sets the value for therun.Mannings.Geom.{domain_geom_name}.Value
key. If it is a filename, this parameter sets the value for therun.Mannings.FileName = mannings
key.
This function sets the following keys:
# If slope_x is provided, it will set these keys: # Appending domain_name to the list of TopoSlopesX.GeomNames run.TopoSlopesX.GeomNames = domain_geom_name # If slope_x is a number, it will set these keys: run.TopoSlopesX.Type = 'Constant' run.TopoSlopesX.Geom.{domain_geom_name}.Value = slope_x # If slope_x is a file name, it will set these keys: run.TopoSlopesX.FileName = slope_x # If the file name is a PFB file: run.TopoSlopesX.Type = 'PFBFile' # If the file name is a NetCDF file: run.TopoSlopesX.Type = 'NCFile' # If slope_y is provided, it will set these keys: # Appending domain_name to the list of TopoSlopesY.GeomNames run.TopoSlopesY.GeomNames = domain_geom_name # If slope_y is a number, it will set these keys: run.TopoSlopesY.Type = 'Constant' run.TopoSlopesY.Geom.{domain_geom_name}.Value = slope_y # If slope_y is a file name, it will set these keys: run.TopoSlopesY.FileName = slope_y # If the file name is a PFB file: run.TopoSlopesY.Type = 'PFBFile' # If the file name is a NetCDF file: run.TopoSlopesY.Type = 'NCFile' # If mannings is provided, it will set these keys: # Appending domain_name to the list of Mannings.GeomNames run.Mannings.GeomNames = domain_geom_name # If mannings is a number, it will set these keys: run.Mannings.Type = 'Constant' run.Mannings.Geom.{domain_geom_name}.Value = mannings # If mannings is a file name, it will set these keys: run.Mannings.FileName = mannings # If the file name is a PFB file: run.Mannings.Type = 'PFBFile' # If the file name is a NetCDF file: run.Mannings.Type = 'NCFile'
- param
zero_flux(self, patches, cycle_name, interval_name)
:parampatches
: Values forrun.BCPressure.PatchNames
key :paramcycle_name
: Value forrun.Patch[patch].BCPressure.Cycle
key :paraminterval_name
: Value forrun.Patch[patch].BCPressure[interval_name]
keyThis function sets the following keys:
run.BCPressure.PatchNames += [patch] run.Patch[patch].BCPressure.Type = 'FluxConst' run.Patch[patch].BCPressure.Cycle = cycle_name run.Patch[patch].BCPressure[interval_name].Value = 0.0
ic_pressure(self, domain_geom_name, patch, pressure)
:paramdomain_geom_name
: Value forrun.ICPressure.GeomNames
key :parampatch
: Value forrun.Geom.{domain_geom_name}.ICPressure.RefPatch
key :parampressure
: Value forrun.Geom.domain.ICPressure.FileName
keyThis function sets the following keys:
run.ICPressure.GeomNames = domain_geom_name run.Geom.{domain_geom_name}.ICPressure.RefPatch = patch # If pressure is a PFB file, it will set the following keys: run.ICPressure.Type = 'PFBFile' run.Geom.domain.ICPressure.FileName = pressure
clm(met_file_name, top_patch, cycle_name, interval_name)
:parammet_file_name
: Value forrun.Solver.CLM.MetFileName
key :paramtop_patch
: Value forrun.Patch.{top_patch}
key :paramcycle_name
: Value forrun.Patch.{top_patch}.BCPressure.Cycle
key :paraminterval_name
: Value forrun.Patch.{top_patch}.BCPressure.{interval_name}
keyThis function sets the following keys:
# Ensure time step is hourly run.TimeStep.Type = 'Constant' run.TimeStep.Value = 1.0 # Ensure OverlandFlow is the top boundary condition run.Patch.{top_patch}.BCPressure.Type = 'OverlandFlow' run.Patch.{top_patch}.BCPressure.Cycle = cycle_name run.Patch.{top_patch}.BCPressure.{interval_name}.Value = 0.0 # Set CLM keys run.Solver.LSM = 'CLM' run.Solver.CLM.CLMFileDir = "." run.Solver.PrintCLM = True run.Solver.CLM.Print1dOut = False run.Solver.BinaryOutDir = False run.Solver.CLM.DailyRST = True run.Solver.CLM.SingleFile = True run.Solver.CLM.CLMDumpInterval = 24 run.Solver.CLM.WriteLogs = False run.Solver.CLM.WriteLastRST = True run.Solver.CLM.MetForcing = '1D' run.Solver.CLM.MetFileName = met_file_name run.Solver.CLM.MetFilePath = "." run.Solver.CLM.MetFileNT = 24 run.Solver.CLM.IstepStart = 1.0 run.Solver.CLM.EvapBeta = 'Linear' run.Solver.CLM.VegWaterStress = 'Saturation' run.Solver.CLM.ResSat = 0.1 run.Solver.CLM.WiltingPoint = 0.12 run.Solver.CLM.FieldCapacity = 0.98 run.Solver.CLM.IrrigationType = 'none'
well(name, type, x, y, z_upper, z_lower, cycle_name, interval_name, action='Extraction', saturation=1.0, phase='water', hydrostatic_pressure=None, value=None)
:paramname
: Name to be appended torun.Wells.Names
key :paramtype
: Value forrun.Wells.{name}.Type
key :paramx
: Value forrun.Wells.{name}.X
key :paramy
: Value forrun.Wells.{name}.Y
key :paramz_upper
: Value forrun.Wells.{name}.ZUpper
key :paramz_lower
: Value forrun.Wells.{name}.ZLower
key :paramcycle_name
: Value forrun.Wells.{name}.Cycle
key :paraminterval_name
: Value forrun.Wells.{name}.{interval_name}
:paramaction
: Value forrun.Wells.{name}.Action = action
key :paramsaturation
: Value forrun.Wells.{name}.{interval_name}.Saturation.{phase}.Value
key :paramphase
: Value forrun.Wells.{name}.{interval_name}.Injection.Flux.{phase}
key :paramhydrostatic_pressure
: Value forrun.Wells.{name}.{interval_name}.Pressure.Value
key :paramvalue
: Value forrun.Wells.{name}.{interval_name}.Injection.Flux.{phase}.Value
keyThis function sets the following keys:
# Append name to Wells.Names run.Wells.Names += [name] run.Wells.{name}.InputType = 'Vertical' run.Wells.{name}.Action = action run.Wells.{name}.Type = type run.Wells.{name}.X = x run.Wells.{name}.Y = y run.Wells.{name}.ZUpper = z_upper run.Wells.{name}.ZLower = z_lower run.Wells.{name}.Method = 'Standard' run.Wells.{name}.Cycle = cycle_name run.Wells.{name}.{interval_name}.Saturation.{phase}.Value = saturation # If type is set to 'Pressure', set Pressure.Value run.Wells.{name}.{interval_name}.Pressure.Value = hydrostatic_pressure # For extraction wells (run.Wells.{name}.Action = 'Extraction'), set these keys: # If type is set to 'Pressure' and value is provided, set Extraction.Pressure.Value run.Wells.{name}.{interval_name}.Extraction.Pressure.Value = value # If type is set to 'Flux' and value is provided, set Extraction.Flux.{phase}.Value run.Wells.{name}.{interval_name}.Extraction.Flux.{phase}.Value = value # For injection wells (run.Wells.{name}.Action = 'Injection'), set these keys: # if type is set to 'Pressure' and value is provided, set Injection.Pressure.Value run.Wells.{name}.{interval_name}.Injection.Pressure.Value = value # If type is set to 'Flux' and value is provided, set Injection.Flux.{phase}.Value run.Wells.{name}.{interval_name}.Injection.Flux.{phase}.Value = value
spinup_timing(self, initial_step, dump_interval)
: :paraminitial_step
: Value forrun.TimeStep.InitialStep
key :paramdump_interval
: Value forrun.TimingInfo.DumpInterval
keyThis function sets the following keys:
run.TimingInfo.BaseUnit = 1 run.TimingInfo.StartCount = 0 run.TimingInfo.StartTime = 0.0 run.TimingInfo.StopTime = 10000000 run.TimingInfo.DumpInterval = dump_interval run.TimeStep.Type = 'Growth' run.TimeStep.InitialStep = initial_step run.TimeStep.GrowthFactor = 1.1 run.TimeStep.MaxStep = 1000000 run.TimeStep.MinStep = 0.1