Source code for dpest.utils.parg_inctyp
[docs]
def parg_inctyp(pst_path, updates):
"""
Updates INCTYP values for one or more parameter groups in a PEST control (.pst) file.
The ``INCTYP`` field specifies the increment type used by PEST for derivative
calculations in the ``* parameter groups`` section. Typical values are
``relative`` and ``absolute``. This function modifies the ``* parameter groups``
section of an existing ``.pst`` file in place.
**Required Arguments:**
=======
* **pst_path** (*str*):
Path to the ``.pst`` PEST control file to modify.
* **updates** (*dict*):
Dictionary mapping parameter group names to new ``INCTYP`` values.
Example::
{
"PART_SEED": "relative",
"SEED_COMP": "absolute"
}
**Returns:**
=======
* ``None``
The function updates the ``* parameter groups`` section in place.
**Examples:**
=======
1. **Update INCTYP for two parameter groups:**
.. code-block:: python
from dpest.utils import parg_inctyp
parg_inctyp(
pst_path = "A-1_input/PEST_CONTROL.pst",
updates = {
"PART_SEED": "relative",
"SEED_COMP": "relative"
}
)
2. **Set one parameter group to absolute increments:**
.. code-block:: python
from dpest.utils import parg_inctyp
parg_inctyp(
pst_path = "PEST_CONTROL.pst",
updates = {
"SEED_COMP": "absolute"
}
)
"""
try:
import os
# Validate pst_path
if not os.path.isfile(pst_path):
raise FileNotFoundError(f"File not found: {pst_path}")
# Validate updates
if not isinstance(updates, dict) or len(updates) == 0:
raise ValueError("`updates` must be a non-empty dictionary.")
allowed_values = {"absolute", "relative"}
validated_updates = {}
for group_name, new_value in updates.items():
if not isinstance(group_name, str) or not group_name.strip():
raise ValueError(f"Invalid parameter group name: {group_name}")
if not isinstance(new_value, str):
raise ValueError(
f"INCTYP value for group '{group_name}' must be a string."
)
clean_value = new_value.strip().lower()
if clean_value not in allowed_values:
raise ValueError(
f"INCTYP for group '{group_name}' must be one of: {sorted(allowed_values)}"
)
validated_updates[group_name.strip()] = clean_value
# Read PST file
with open(pst_path, 'r') as f:
lines = f.readlines()
# Find * parameter groups section
section_start_idx = None
section_end_idx = None
for i, line in enumerate(lines):
if line.strip().lower().startswith('* parameter groups'):
section_start_idx = i
j = i + 1
while j < len(lines) and not lines[j].strip().startswith('*'):
j += 1
section_end_idx = j
break
if section_start_idx is None:
raise ValueError(
"This file does not contain a '* parameter groups' section and is not a valid PEST control file."
)
# Process lines in the section
found_groups = set()
for i in range(section_start_idx + 1, section_end_idx):
current_line = lines[i]
# Skip empty lines
if not current_line.strip():
continue
values = current_line.split()
if len(values) < 2:
continue
group_name = values[0]
if group_name in validated_updates:
values[1] = validated_updates[group_name] # INCTYP is 2nd value
current_padding = len(current_line) - len(current_line.lstrip())
new_line = " " * current_padding + " ".join(values) + "\n"
lines[i] = new_line
found_groups.add(group_name)
# Check that all requested groups were found
missing_groups = set(validated_updates.keys()) - found_groups
if missing_groups:
raise ValueError(
"The following parameter groups were not found in the '* parameter groups' section: "
+ ", ".join(sorted(missing_groups))
)
# Write updated file
with open(pst_path, 'w') as f:
f.writelines(lines)
print(
f"INCTYP updated successfully for parameter groups: {', '.join(sorted(found_groups))}"
)
except FileNotFoundError as fe:
print(f"Error: {str(fe)}")
except ValueError as ve:
print(f"ValueError: {str(ve)}")
except Exception as e:
print(f"Unexpected error: {str(e)}")