Metadata-Version: 2.1
Name: DSSATTools
Version: 2.0.0
Summary: A DSSAT's Python implementation
Home-page: https://github.com/daquinterop/Py_DSSATTools
Author: Diego Quintero
Author-email: daquinterop@gmail.com
License: MIT
Project-URL: Bug Tracker, https://github.com/daquinterop/Py_DSSATTools/issues
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE

# DSSATTools package
## Installation:
You can install the library using Python pip. I'll show you one way, but if you don't like that way you can google "pip install from git" [(or just click here).](https://www.google.com/search?client=firefox-b-1-d&q=pip+install+from+git). So to install it first clone or download the repository, then just install:
```
git clone https://github.com/daquinterop/Py_DSSATTools
cd Py_DSSATTools
pip install .
```
## Documentation
[https://py-dssattools.readthedocs.io/en/latest/index.html](https://py-dssattools.readthedocs.io/en/latest/index.html)
## Example Notebooks
You'll find example notebooks in this repo:[https://github.com/daquinterop/DSSATTools_notebooks](https://github.com/daquinterop/DSSATTools_notebooks). I'll keep uploading examples as some new feature is introduced.
## Module contents

DSSAT library is a collection of classes that allows the user to create low-code scripts to run simulations with DSSAT model. The library structure allows to execute DSSAT model based on four input classes: Crop, SoilProfile, WeatherStation and Management.

The simulation environment is represented by the DSSAT Class. There are three stages for the simulation to be excecuted: 1. Initialize a DSSAT instance; 2. setup the simulation environment by using the DSSAT.setup method; 3. run the simulation using the DSSAT.run method.

During the environment setup (DSSAT.setup) a directory is created and all the static files required to run DSSAT are copied in that directory. This directory will be removed when the DSSAT.close method is called. After the environment has been set up, the DSSAT.run method can be called as many times as you want.

All of the parameters and attributes of the four basic clases have the same name you find in the DSSAT files (Take a look at the .CDE files in [https://github.com/DSSAT/dssat-csm-os/tree/develop/Data](https://github.com/DSSAT/dssat-csm-os/tree/develop/Data)).

**At the moment Only the next crops and models are implemented:**
| Crop         | Model               |
|--------------|---------------------|
| Maize        | CERES               |
| Millet       | CERES               |
| Rice         | CERES               |
| Sugarbeet    | CERES               |
| Sorghum      | CERES               |
| Sweetcorn    | CERES               |
| Alfalfa      | FORAGE-Alfalfa      |
| Bermudagrass | FORAGE-Bermudagrass |

More crops and models will be added later.

If you're interested in contributing to this project, don't hesitate in sending me an email (daquinterop@gmail.com). Of course, if you want to contribute then I'll have to create a Developer's guide to the project.

All the Classes can be imported as:
```python
from DSSATTools import (
    Crop, SoilProfile, WeatherData, WeatherStation,
    Management, DSSAT
)
```
or 
```python
from DSSATTools import *
```
## DSSATTools.crop module

Basic crop class. It initializes a crop instances based on the crop name and
crop file if provided.

Crop class is the only needed class to initialize a Crop instance. You need
to specify the crop name (Those can be checked at DSSATTools.crop.CROPS_MODULES
object), and you can also specify a .SPE file to initialize the instance. If no
.SPE file is passed as argument, then default .SPE, .ECO and .CUL are used.

Please, take into account that if you initialize the instance with a custom
Species file the three files (.SPE, .ECO, .CUL) must be in the same directory 
as the passed Species file.

The only method implemented is set_parameter, that of course is used to set
the value of any crop parameter. Crop class inherits from the BaseCrop class
of the specified crop. BaseCrop is composed by sections, each of the included
in the Species file, and one section for Cultivar and Ecotype respectively.

The usage of the Crop class is explaied by this example. In here we initialize
a Crop instance, modify a parameter and write the cropfile (All of them).

```python
>>> crop = Crop('maize')
>>> crop.set_parameter(
        par_name = 'TBASE',
        par_value = 30.,
        row_loc = 'IB0002'
    )
>>> crop.write('crop_test')
```


### _class_ DSSATTools.crop.Crop(crop_name: str = 'Maize', spe_file: Optional[str] = None)
Initializes a crop instance based on the default DSSAT Crop files, or 
on a custom crop file provided as a cultivar.

##### Arguments
```
crop: str
    Crop name, available at the moment:  Maize, Millet, Sugarbeet, Rice, Sorghum, Sweetcorn.

spe_file: str
    Optional. Path to the species file to initialize the instance.

```
#### set_parameter(par_name: str, par_value, row_loc=0)
Set the value of one parameter in the Crop class.
##### Arguments
```
par_name: str
    name of the parameter. Parameter’s names are in the Crop.parameters 
    attribute.

par_value: str, int, float
    Value of the parameter to set.

row_loc: int, str
    id for the element to modify. This applies to parameters defined in 
    cols, such as cultivar or ecotype parameters. For example:

    @ECO#  ECONAME………  TBASE  TOPT ROPT   P20  
    IB0001 GENERIC MIDWEST1    8.0 34.0  34.0  12.5 
    IB0002 GENERIC MIDWEST2    8.0 34.0  34.0  12.5

    for this set of parameters (ecotype), the column ECO# is the id to
    be passed as row_loc argument.
```

## DSSATTools.management module

Management class includes all the information related to management. There are
multiple arguments to initialize a Management instance, however, the only 
mandatory arguments are cultivar (cultivar id, of course it has to be included
in the cultivars list of the Crop object you’ll be passing to DSSAT.run) and
planting_date. Simulation start is calculated as the day before the planting 
date, emergence_date is assumed to 5 days after planting, and the initial soil
water content is assumed to be 50% of the total available water 
(PWP + 0.5(FC-PWP))

Management class has one attribute per management section. Up to date not all
of the sections have been implemented and the next sections are available: 
fields, cultivars, initial conditions, planting details, irrigation, 
fertilizers, harvest details, simulation controls, automatic management. All of
the sections have dict object as base, so you can modify the parameters by
just reassigning the value as you would do it on a dict. Some of the sections
are defined as tables, so you can modify the values of those tabular sections
the same as you would modify a pandas.Dataframe.

In the next example a Management object is created, and two of its sections
are modified.

```python
>>> man = Management(
        cultivar='IB0001',
        planting_date=datetime(2020, 1, 1),
    )
>>> man.harvest_details['table'].loc[0, ['HDATE', 'HPC']] = \
        [datetime(2020, 7, 1).strftime('%y%j'), 100]
>>> man.simulation_controls['IRRIG'] = 'A'
```

### _class_ DSSATTools.management.Management(cultivar: str, planting_date: datetime, sim_start: Optional[datetime] = None, emergence_date: Optional[datetime] = None, initial_swc: float = 0.5, irrigation='R', fertilization='R', harvest='M')
Initializes a management instance.

##### Arguments
```
cultivar: str
    Code of the cultivar. That code must match one of the codes in the
    Crop instance used when runing the model.

planting_date: datetime
    Planting date.

sim_start: datetime
    Date for start of the simulation. If None, it’ll be calculated as
    the previous day to the planting date.

emergence_date: datetime
    Emergence date. If None, I’ll be calculated as 5 days after 
    planting.

initial_swc: int
    Fraction of the total available water (FC - PWP) at the start of the 
    simulation. .5(50%) is the default value.

irrigation: str
    Default ‘R’. Irrigation management option, options available are:

        A        Automatic when required
        N        Not irrigated
        F        Fixed amount automatic
        R        On reported dates
        D        Days after planting
        P        As reported through last day, then automatic to re-fill (A)
        W        As reported through last day, then automatic with fixed amount (F)

harvest: str
    Default ‘M’. Harvest management options. available options are:
        A        Automatic      
        M        At maturity
        R        On reported date(s)
        D        Days after planting

fertilization: str
    Default ‘R’. Fertilization management options. available options are:
        N        Not fertilized
        R        On reported dates
        D        Days after planting
```

## DSSATTools.run module

This module hosts the DSSAT class. That class is the simulation environment, so per each
Dscsm instance there’s a directory where all the necesary files to run the model
are allocated. To run the model there are 3 basic steps:

> 
> 1. Create a new Dscsm instance.


> 2. Initialize the environment by running the setup() method.


> 3. Run the model by running the run() method.

You can close the simulation environment by running the close() method.

The model outputs are storage in the outputs attribute. Up to date the only
model output parsed into outputs is ‘PlantGro’.

In the next example all the 4 required objects to run the DSSAT model are
created, an a simulation is run.

```python
>>> # Create random weather data
>>> df = pd.DataFrame(
    {
    'tn': np.random.gamma(10, 1, N),
    'rad': np.random.gamma(10, 1.5, N),
    'prec': np.round(np.random.gamma(.4, 10, N), 1),
    'rh': 100 * np.random.beta(1.5, 1.15, N),
    },
    index=DATES,
)
>>> df['TMAX'] = df.tn + np.random.gamma(5., .5, N)
>>> # Create a WeatherData instance
>>> WTH_DATA = WeatherData(
    df,
    variables={
        'tn': 'TMIN', 'TMAX': 'TMAX',
        'prec': 'RAIN', 'rad': 'SRAD',
        'rh': 'RHUM'
    }
)
>>> # Create a WheaterStation instance
>>> wth = WeatherStation(
    WTH_DATA, 
    {'ELEV': 33, 'LAT': 0, 'LON': 0, 'INSI': 'dpoes'}
)
>>> # Initialize soil, crop and management instances.
>>> soil = SoilProfile(default_class='SIL')
>>> crop = Crop('maize')
>>> man = Management(
    cultivar='IB0001',
    planting_date=DATES[10],
)
>>> man.harvest_details['table'].loc[0, ['HDATE', 'HPC']] =         [DATES[190].strftime('%y%j'), 100]
>>> # Initialize Dscsm instance and run.
>>> dssat = Dscsm()
>>> dssat.setup(cwd='/tmp/dssattest')
>>> dssat.run(
    soil=soil, weather=wth, crop=crop, management=man,
)
>>> # Get output
>>> PlantGro = dssat.outputs['PlantGro']
>>> dssat.close() # Terminate the simulation environment
```


### _class_ DSSATTools.run.DSSAT()

Class that represents the simulation environment. When initializing and 
seting up the environment, a new folder is created (usually in the tmp 
folder), and all of the necesary files to run the model are copied into it.

#### close()
Removes the simulation environment (tmp folder and files).


#### run(soil: SoilProfile, weather: WeatherStation, crop: Crop, management: Management)
Start the simulation and runs until the end or failure.
##### Arguments
```
soil: DSSATTools.soil.Soil
    SoilProfile instance

weather: DSSATTools.weather.WeatherStation
    WeatherStation instance

crop: DSSATTools.crop.Crop
    Crop instance

managment: DSSATTools.management.Management
    Management instance
```

#### setup(cwd=None)
Setup a simulation environment.
Creates a tmp folder to run the simulations and move all the required
files to run the model. Some rguments are optional, if those aren’t provided,
then standard files location will be used.
##### Arguments
```
cwd: str
    Working directory. All the model files would be moved to that directory.
    If None, then a tmp directory will be created.
```

## DSSATTools.soil module

soil module includes the basic soil class SoilProfile. This class contains
all the soil information necessary to run the DSSAT model. Each of the layers
of the soil profile is a SoilLayer instance. After a SoilProfile instance
is created, a new layer can added by calling the SoilProfile.add_layer method
passing a SoilLayer object as argument. You can also use the 
SoilProfile.drop_layer to drop the layer at the specified depth.

SoilLayer class represents each layer in the soil profile. The layer is 
initialized by passing the layer base depth and a dict with the parameteters as 
argument. Clay fraction (SLCL) and Silt fraction (SLSI) are the only mandatory
parameters when creating a layer, the rest of the parameters are estimated.

There are three basic ways of creating a SoilProfile object:

1. Specify a .SOL file and Soil id. Of course, the soil id must match one 
of the profiles in the .SOL file.

```python
>>> soilprofile = SoilProfile(
    file='SOIL.SOL',
    profile='IBBN910030'
)
```

2. Passing a string code of one the available default soils.

```python
>>> soilprofile = SoilProfile(
    default_class='SCL', # Silty Clay Loam
)
```

3. Pasing a dict with the profile parameters (different from the layer 
pars). DSSAT.soil.list_profile_parameters function prints a detailed list 
of the layer parameters. And empty dict can be pased as none of the 
parameters is mandatory.

```python
>>> soilprofile = SoilProfile(
    pars={
        'SALB': 0.25, # Albedo
        'SLU1': 6, # Stage 1 Evaporation (mm)
        'SLPF': 0.8 # Soil fertility factor
    }
)
>>> layers = [
    soil.SoilLayer(20, {'SLCL': 50, 'SLSI': 45}),
    soil.SoilLayer(50, {'SLCL': 30, 'SLSI': 30}),
    soil.SoilLayer(100, {'SLCL': 30, 'SLSI': 35}),
    soil.SoilLayer(180, {'SLCL': 20, 'SLSI': 30})
]
>>> for layer in layers: soilprofile.add_layer(layer)
```

That layer must be initialized with the texture information (‘SLCL’ and ‘SLSI’ 
parameters), or the hydraulic soil parameters (‘SLLL’, ‘SDUL’, ‘SSAT’, ‘SRGF’, 
‘SSKS’, ‘SBDM’, ‘SLOC’). If a soil hydraulic parameter is not defined, then it’s
estimated from soil texture using Pedo-transfer Functions. The previous
parameters are the mandatory ones, but all the available parameters can be 
includedin the pars dict.

If you want to save your soil profile in .SOL a file, you can use the 
SoilProfile.write method. The only argument of this method is the filename.

For both classes any of the parameters can be modified after the initialization
as each parameter is also an attribute of the instance.

```python
>>> soilprofile = SoilProfile(
    pars={
        'SALB': 0.25, # Albedo
        'SLU1': 6, # Stage 1 Evaporation (mm)
        'SLPF': 0.8 # Soil fertility factor
    }
>>> # Modify the albedo of the created instance
>>> soilprofile.SALB = 0.36
```


### _class_ DSSATTools.soil.SoilLayer(base_depth: int, pars: dict)

Initialize a soil layer instance.
##### Arguments
```
base_depth: int
    Depth to the bottom of that layer (cm)

pars: dict
    Dict including the parameter values to initialize the instance. Layer
    parameters include: 
    ‘SLMH’,  ‘SLLL’,  ‘SDUL’,  ‘SSAT’,  ‘SRGF’,  ‘SSKS’,  ‘SBDM’,  ‘SLOC’,
    ‘SLCL’,  ‘SLSI’,  ‘SLCF’,  ‘SLNI’,  ‘SLHW’,  ‘SLHB’,  ‘SCEC’,  ‘SADC’
    ‘SLPX’,  ‘SLPT’,  ‘SLPO’, ‘CACO3’,  ‘SLAL’,  ‘SLFE’,  ‘SLMN’,  ‘SLBS’,
    ‘SLPA’,  ‘SLPB’,  ‘SLKE’,  ‘SLMG’,  ‘SLNA’,  ‘SLSU’,  ‘SLEC’,  ‘SLCA’
    Only mandatory parameters are ‘SLCL’ and ‘SLSI’. The rest of the basic
    parameters can be calculated from the texture.

    SCOM is optional, and it can be passed as an string referencing the color,
    or a tupple with CIELAB coordinates (L, a, b). The string can be one of
    these:

    > BLK: Black (10YR 2/1)
    > YBR: Yellowish Brown (7.5YR 5/6)
    > RBR: Redish Brown (10R 4/8)
    > DBR: Dark Brown (2.5YR 3/4) 
    > GRE: Grey (10YR 6/1)
    > YLW: Yellow (10YR 7/8)

```

### _class_ DSSATTools.soil.SoilProfile(file: Optional[str] = None, profile: Optional[str] = None, default_class: Optional[str] = None, pars: dict = {})

Soil Profile class. It can be initialized from an existing file. It also can 
be initialized from scratch.  If a file is provided, then the soil is 
initialized as the soil profile with the matching profile id in the file.
##### Arguments
```
file: str
    Optional. Path to the soil file.

profile: str
    Optional. Must be passed if file argument is passed. It’s the 
    id of the profile within the file.

pars: dict
    Dict with the non-layer soil parameters.

default_class: str
    Optional. It’s a string defining a DSSAT default soil class. If not 
    None, then the SoilClass instance is initialized with the paremeters 
    of the specified default_class.
    default_class must match any of the next codes:
    > Sand            |  S 
    > Loamy Sand      |  LS  
    > Sandy Loam      |  SL 
    > Loam            |  L 
    > Silty Loam      |  SIL 
    > Silt            |  SI 
    > Sandy Clay Loam |  SCL 
    > Clay Loam       |  CL 
    > Silty Clay Loam |  SICL 
    > Sandy Clay      |  SC 
    > Silty Clay      |  SIC 
    > Clay            |  C

```

#### add_layer(layer: SoilLayer)
Add a new layer to the Soil.
##### Arguments
```
layer: DSSATTools.soil.SoilLayer
    Soil Layer object
```

#### drop_layer(layer: int)
Drop the layer at the specified depth


#### set_parameter(parameter, value)
Set the value of a soil parameter.
##### Arguments
```
parameter: str
    Parameter name. You can use the DSSATTools.soil.list_parameters 
    function
    to have a list of the parameters and their description.

value: int, float, str
    Value for that parameter
```

#### write(filename: str = 'SOIL.SOL')
It’s called by the DSSATTools.run.Dscsm.run() method to write the file.
##### Arguments
```
filename: str
    Path to the file to write
```

### DSSATTools.soil.list_layer_parameters()
Print a list of the soil parameters


### DSSATTools.soil.list_profile_parameters()
Print a list of the soil parameters


## DSSATTools.weather module

This module includes two basic classes to create a weather station. The 
WeatherStation class is the one that storages all the station info and the 
weather data. The WeatherData class inherits all the methods of a 
pandas.DataFrame, and it’s the one that includes the weather data.

In the next example we’ll create synthetic data and we’ll create a
WeatherStation object.

```python
>>> DATES = pd.date_range('2000-01-01', '2010-12-31')
>>> df = pd.DataFrame(
        {
        'tn': np.random.gamma(10, 1, N),
        'rad': np.random.gamma(10, 1.5, N),
        'prec': np.round(np.random.gamma(.4, 10, N), 1),
        'rh': 100 * np.random.beta(1.5, 1.15, N),
        },
        index=DATES,
    )
>>> df['TMAX'] = df.tn + np.random.gamma(5., .5, N)
>>> # Create a WeatherData instance
>>> WTH_DATA = WeatherData(
        df,
        variables={
            'tn': 'TMIN', 'TMAX': 'TMAX',
            'prec': 'RAIN', 'rad': 'SRAD',
            'rh': 'RHUM'
        }
    )
>>> Create a WheaterStation instance
>>> wth = WeatherStation(
        WTH_DATA, 
        {'ELEV': 33, 'LAT': 0, 'LON': 0, 'INSI': 'dpoes'}
    )
>>> wth.data.head() # To check the data first 5 records
```


### _class_ DSSATTools.weather.WeatherData(data: DataFrame, variables: dict = {})

WeatherData class.
Creates a WeatherData instance. That instance is the one that contains
the records for the Weather Station.
##### Arguments
```
data: pd.Dataframe
    A DataFrame containg the the weather data.

variables: dict
    A dict to map the columns of the dataframe, to the DSSAT Weather 
    variables. Use list_weather_parameters function to have a detailed
    description of the DSSAT weather variables.
```

### _class_ DSSATTools.weather.WeatherStation(wthdata: WeatherData, pars: dict, description='Weather Station')

WeatherStation Class.
Initialize a Weather station instance.

##### Arguments
```
pars: dict
    dict with the Weather station parameters. list_station_parameters
    provides a list with the parameters and their description. Only LAT,
    LON and ELEV parameters are mandatory.

description: str
    An string with the description of the weather station
```

### DSSATTools.weather.list_station_parameters()
Print a list of the weather station parameters


### DSSATTools.weather.list_weather_parameters()
Print a list of the weather data parameters
