<jupyter_start><jupyter_text>Introduction to PyGSFLOWSimulating integrated hydrological systems requires working with a large set of input parameters and output variables that are saved in several files. Thus, changing input parameters and reading output can be laborious task. This is particularly true in  model calibration and sensitivity and uncertainty analysis. [pyGSFLOW](https://github.com/usgs-pygsflow/pygsflow) allows modeler to focus on the hydrologic aspect of the problem as it simplifies most of modeling operations such as modifying model input files, running the model, and reading and processing the model. PyGSFLOW uses [FloPy](https://github.com/modflowpy/flopy) (Bakker and others, 2021) to work with MODFLOW files.   This notebook illustrates some of the basic elements of pyGSFLOW.<jupyter_code>try:
    import gsflow
except ImportError:
    import os, sys
    import subprocess
    python_exe = sys.executable
    current_dir = os.getcwd()
    package_location = ".."
    os.chdir(package_location)
    cmd = python_exe + " setup.py install"
    result = subprocess.check_output(cmd, shell=True)
    os.chdir(current_dir)
    print(result)
from gsflow import GsflowModel
import os, sys
import numpy as np
import matplotlib.pyplot as plt
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()<jupyter_output><empty_output><jupyter_text>pyGSFLOW in a nutshellpyGSFLOW consists of three main components (See Figures below). These components are:    (1) A Control class,      (2) a PRMS class,      (3) the Flopy package, with some GSFLOW specific overrides.The Control class handles operations and information related the control file. The PRMS object wraps a number of other classes such as:        (1) the Parameters Class that handles all PRMS parameters that can be saved in one (or more) files,    (2) the Data class that handles climate station data information.    (3) The Day class that handles climate by hru files    (4) Output modules that handle some of the PRMS output.          The [FloPy](https://github.com/modflowpy/flopy) package (called from the `mf` attribute in pyGSFLOW) is used to handle data and operations related to MODFLOW.   Accessing Data in pyGSFLOW -- The Big PictureTo access any piece information within the GSFLOW model the user can use an object oriented approach starting from the main class Gsflow. The following figure illustrates how this can be accomplished       __Note__: PyGSLFOW is still under development and updates are occuring regularly. Some of the features that are not supported includes:    (1) Reading and processing animation files and PRMS budget files,    (2) Tools to check for user errors in input files. Some of the tools that are currently in development:        (1) builder classes to rapidly go from raster data to model    (2) additional output readers    (3) improved methods to handle prms discretization    Features that are included, but in their alpha version:        (1) prms dynamic parameters    (2) prms day file (climate by hru) support  Example (1) Loading an existing GSFLOW model Let's start by loading an existing GSFLOW model. To do so we need to pass the control file to the `GsflowModel` class that will load information stored in the model input files.To do this the method `GsflowModel.load_from_file()` is used. This method has a few parameters including:   - `control_file`: gsflow control file name   - `gsflow_exe`: optional, gsflow executable file path   - `modflow_only`: bool, if True only modflow files will be loaded, default is False   - `prms_only`: bool, if True only prms files will be loaded, default is False   - `mf_load_only`: optional, list of Modflow package names to load   - `forgive`: bool, if True pyGSFLOW will continue loading packages even if one does not load properly, default is False   - `model_ws`: optional, base directory path of the GSFLOW model<jupyter_code>control_file = os.path.join(".", "data", "sagehen", "prms", "windows", "sagehen.control")
gsf = GsflowModel.load_from_file(control_file=control_file)<jupyter_output>Control file is loaded
Working on loading PRMS model ...
Prms model loading ...
------------------------------------
Reading parameter file : calibration_parameters.param
------------------------------------
Warning: ncascade data type will be infered from data supplied
Warning: ncascdgw data type will be infered from data supplied
Warning: ndays data type will be infered from data supplied
Warning: ndepl data type will be infered from data supplied
Warning: ndeplval data type will be infered from data supplied
Warning: nevap data type will be infered from data supplied
Warning: ngw data type will be infered from data supplied
Warning: ngwcell data type will be infered from data supplied
Warning: nhru data type will be infered from data supplied
Warning: nhrucell data type will be infered from data supplied
Warning: nlake data type will be infered from data supplied
Warning: nlake_hrus data type will be infered from data supplied
Warning: nmonths data type will be infered from data sup[...]<jupyter_text>(2) Accessing data in GSFLOW inputsThe `gsf` variable in the previous cell is a name for the `GsflowModel` object that holds information about the two components of GSFLOW : PRMS and MODFLOW. This example uses that variable to access data. (2.a) Control Class Common methods and attributes the user can use to access control information include:   - `record_names`: list of all control file record names   - `get_record`: method that allows the user to get control file record object   - `get_values`: method that allows the user to get data from an existing control file record   - `set_values`: method that allows the user to update existing control file record data   - `add_record`: method that allows the user to add a new record to the control file   - `remove_record`: method that allows the user to remove a record from the control file  Get a list of record names from the control file<jupyter_code>control_names = gsf.control.record_names
print(control_names[0:5])<jupyter_output>['mapoutvar_names', 'nmapoutvars', 'mapouton_off', 'parameter_check_flag', 'prms_warmup']<jupyter_text>Get a control record and inspect itNote: printing a record will generate a GSFLOW control file entry<jupyter_code># Assuming that we are interested in looking closer into ET Module 
et_module = gsf.control.get_record('et_module')
print(et_module)<jupyter_output>####
et_module
1
4
potet_jh
####<jupyter_text>_Note_ : when the output is large, pygsflow only prints the first 4 records to save space<jupyter_code>start_date = gsf.control.get_record('start_time')
print(start_date)<jupyter_output>####
start_time
6
1
1982
8
1
0.
.
.
####<jupyter_text>Get the values from a control recordValues in any record can be accessed using the `get_values()` method.<jupyter_code>start_time = gsf.control.get_values("start_time")
start_time<jupyter_output><empty_output><jupyter_text>Update the values of an existing recordThe `set_values()` method can be used to update record values<jupyter_code>gsf.control.set_values(name='start_time', values=[1990,1,1,0,0,0])

print(gsf.control.get_record("start_time"))<jupyter_output>####
start_time
6
1
1990
1
1
0.
.
.
####<jupyter_text>Adding a new record to the Control fileThe `add_record()` method allows the user to add a new record to the control file. This method has two parameters.   - `name` : the parameter name   - `values` : a list or numpy array of values   - `after`: optional, existing parameter name to insert record after, default is None   Note: pyGSFLOW does not check if the parameter name is valid<jupyter_code>gsf.control.add_record("xyz", [1, 2])

print(gsf.control.get_record('xyz'))<jupyter_output>Warning: xyz data type will be infered from data supplied

####
xyz
2
1
1
2
####<jupyter_text>The user is also able to insert a new record into a specific location within the control file using the `after=` keyword argument<jupyter_code>gsf.control.add_record(name="hummingbird_2", values=['a', 'b'], after='save_vars_to_file')
gsf.control.record_names[-25: -17]<jupyter_output>Warning: hummingbird_2 data type will be infered from data supplied<jupyter_text>Removing records from the control filepyGSFLOW allows the user to remove records with the `remove_record()` method. If a record does not exist, pyGSFLOW will warn the user.<jupyter_code>gsf.control.remove_record("xyz") 
gsf.control.remove_record("hummingbird_2")

# try to get the non-exitent record
gsf.control.get_record("hummingbird_2")<jupyter_output>param_base.py:72: UserWarning: The record does not exist...<jupyter_text>(2.b) PRMS Parameters informationPrms parameters are stored in the `PrmsParameters` class which can be accessed via the following example<jupyter_code>parameters = gsf.prms.parameters<jupyter_output><empty_output><jupyter_text>Accessing a list of PRMS parameter namesA list of the model's PRMS parameter names can be aquired using the `record_names` attribute<jupyter_code>parameter_names = parameters.record_names
print(len(parameter_names))

# print first 5 parameter names in list
print(parameter_names[0:5])<jupyter_output>133
['ncascade', 'ncascdgw', 'ndays', 'ndepl', 'ndeplval']<jupyter_text>Getting parameter values from `prms.parameters`The `get_values()` method allows the user to get a numpy array of parameter values for any of the prms parameters.<jupyter_code># check the temperature station for each hru
hru_tsta = parameters.get_values('hru_tsta')
hru_tsta<jupyter_output><empty_output><jupyter_text>Updating parameter values from `prms.parameters`parameter values can be changed using the `set_values()` method.<jupyter_code>hru_tsta = parameters.get_values('hru_tsta')
hru_tsta[0] = 2
parameters.set_values('hru_tsta', hru_tsta)

parameters.get_values('hru_tsta')<jupyter_output><empty_output><jupyter_text>(2.c) Data Class (Climate Data)Climate data is stored in the `PrmsData` object and can be accessed as follows.<jupyter_code>data = gsf.prms.data

data.data_df.head(10)<jupyter_output><empty_output><jupyter_text>No data values are stored as a default value of -999. in the `PrmsData` dataframe. If we plot all of the data without filtering the no data values will mask the climate trends, as we see in the example below.<jupyter_code>climate_data = data.data_df
plt.plot(climate_data['Date'], climate_data['tmax_0']);<jupyter_output><empty_output><jupyter_text>We can mask out the no data values by either filtering the pandas dataframe or setting no data values to NaN values. This allows us to visualize the climite trends over the simulation period.<jupyter_code># filtering data 
df_to_plot = climate_data[climate_data['tmax_0']>-100]
plt.plot(df_to_plot['Date'], df_to_plot['tmax_0'])
plt.title('filtering by value')
plt.show()

# replacing -999 with np.nan
df_to_plot = climate_data.copy()
df_to_plot[df_to_plot.tmax_0 == -999] = np.nan
plt.plot(df_to_plot['Date'], df_to_plot['tmax_0'])
plt.title('replacing filler value with NaN');<jupyter_output><empty_output><jupyter_text>Adding a climate station to the `prms.data` objectThe prms data object stores data as a pandas dataframe. Adding a station to the DataFrame is as simple as adding a new column and setting data to it.<jupyter_code>## add a station
climate_data['precip_2'] = 10
climate_data.head(10)<jupyter_output><empty_output><jupyter_text>Removing station information from the dataframe<jupyter_code>gsf.prms.data.data_df.drop(columns=["precip_2"], inplace=True)
gsf.prms.data.data_df<jupyter_output><empty_output><jupyter_text>(2.d) Access MODFLOW data in pyGSFLOW All data related to MODFLOW can be accessed and assigned using `.mf` object. This object is pyGSFLOW `Modflow` instance that interacts with the python package Flopy; all operations in Flopy can be used here. MODFLOW is covered in notebook `pygsflow_assemble_GSFLOW_model.ipynb`<jupyter_code># !jupyter nbconvert --to script pygsflow_intro.ipynb<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08044730034215138, 'fraction_numerical': 0.008762413419010264, 'mean_word_length': 5.337387625594923, 'pattern_counts': {'":': 0, '<': 72, '<?xml version=': 0, '>': 73, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '20', 'dir': 'jupyter-structured-clean-dedup', 'id': '602354', 'license': 'Unlicense', 'n_tokens_mistral': 3611, 'n_tokens_neox': 3494, 'n_words': 1405, 'path': 'examples/pygsflow_introduction.ipynb', 'repo_name': 'usgs-pygsflow/pygsflow', 'size': '11983'}