# apsimx: An R package for APSIM Next Generation (and Classic)

#### Fernando Miguez

#### 2020-07-09

    ## Will only write file to a temporary directory for these Examples
    tmp.dir <- tempdir()

# Introduction

Are you a user of APSIM-X (“Next Generation”)? Are you a frequent user of R? Are you hoping for APSIM-X and R to interact with each other? Then the answer is the apsimx package, which allows you to inspect, edit, run and read files created by APSIM-X – .apsim(x) files. New .apsimx files are based on the JSON (JavaScript Object Notation https://www.json.org/) format and it is used to communicate information to the APSIM-X engine. By using the ‘jsonlite’ R package apsimx can read and write (‘inspect’ and ‘edit’) files in this format. APSIM ‘Classic’ used an XML format and this type is now fully supported (‘inspect’, ‘edit’, ‘run’ and ‘read’). For ‘inspect’ and ‘edit’ in the APSIM ‘Classic’ version I use the ‘xml2’ package. To run simulations the apsimx function (apsim for ‘Classic’) is available and results from the simulation can be imported as an R object with a dedicated function (read_apsimx ‘NG’ and read_apsim for ‘Classic’). If you need to write scripts (regardless of whether you use the apsimx package or not) the vignette ‘writing scripts’ might be useful. The package is currently being developed and available at: https://github.com/femiguez/apsimx. If you have any questions write to: femiguez at iastate.edu.

In part this package is inspired by previous work by Bryan Stanfill on the ‘apsimr’ package (available from CRAN and github: https://github.com/stanfill/apsimr). That package made it possible to not only run APSIM from R, but also to perform sensitivity analysis and model emulation using ‘GAMS’. However, that package has not been maintained in the last five years and it does not work for the new APSIM-X framework. Another useful R package is ‘APSIM’, but as with ‘apsimr’ it has not been updated and it has somewhat of a different functionality. The ‘APSIM’ package is especially useful for creating weather (‘.met’) files for APSIM ‘Classic’ or ‘Next Generation’.

## Background information

To run the code in this vignette, you need to have APSIM ‘Next Generation’ installed. However, if you have not used APSIM it is recommended that you become familiar with it before hand.

See the following for details

APSIM

APSIM-X

Holzworth et al. (2018)

This package has been tested on:

Mac: ApsimX version (2020-06-05) 5260 (R 3.6.2)

Debian: ApsimX version (2020-01-29) 4007 (R 3.6.1)

Windows: ApsimX version 4236 (2020-06-05) 5260 (R 3.6.2)

## Installing APSIM-X

For most functions in this pacakge you need to have a version of APSIM-X installed (or APSIM ‘Classic’). For Mac and Linux, first you need to install mono (https://www.mono-project.com/download/stable/) and then download and install APSIM-X (https://www.apsim.info/download-apsim/downloads/). The apsimx package will try to detect both mono and APSIM-X.

Mac: For Mac it is also assumed that APSIM-X has been moved to ‘Applications’.

Windows: In Windows the default install location is in ‘Program Files’.

Linux (Debian): It assumed that APSIM-X is in ‘/usr/local/lib/apsim/’.

If you have your own flavor of APSIM, then you need to set the path manually using the function ‘apsim_options’ for Classic and ‘apsimx_options’ for Next Generation.

## R functions for APSIM-X

The main functions in the package are (for now):

- inspect_apsimx simple inspecting of an .apsimx file. (It does not replace the GUI.)
- edit_apsimx edit/modify an .apsimx file.
- apsimx run an .apsimx simulation.
- read_apsimx read files created by an .apsimx simulation run (.db files)
- read_apsimx_all read all files created by one or more .apsimx simulation runs in a directory (.db files)
- inspect_apsimx_replacement inspect a replacement component of an .apsimx file.
- apsimx_options set global options: path for executable, examples and warnings.

## R functions for APSIM ‘Classic’ (7.x) - Only for Windows

The main functions relevant for ‘Classic’ are:

- inspect_apsim allows for inspection of .apsim file.
- edit_apsim edit an .apsim file.
- apsim runs an .apsim file.
- read_apsim reads files (.out and .sim) generated by apsim into a data frame.
- apsim_example runs (only a few) of the built-in examples.
- apsim_options set global options: path for executable, examples and warnings.
- edit_apsim_xml edit an XML file such as Maize.xml or Soil.xml

# Using ‘apsimx’

## Running a built-in example with ‘apsimx_example’

To get started you can run one of the examples distributed with APSIM-X. This function does the following: it detects where the APSIM examples are located, it runs the example indicated and it returns the ‘report’ as a data.frame. After that you can do the usual manipulations, including visualization.

    maize <- apsimx_example("Maize")

After we run this example we can treat it as a standard data frame in R.

    summary(maize)

    ##   CheckpointID  SimulationID    Zone                 Clock.Today
    ##  Min.   :1     Min.   :1     Field:10   1991-05-28 12:00:00:1
    ##  1st Qu.:1     1st Qu.:1                1992-04-09 12:00:00:1
    ##  Median :1     Median :1                1993-03-16 12:00:00:1
    ##  Mean   :1     Mean   :1                1994-03-15 12:00:00:1
    ##  3rd Qu.:1     3rd Qu.:1                1995-04-04 12:00:00:1
    ##  Max.   :1     Max.   :1                1996-03-15 12:00:00:1
    ##                                         (Other)            :4
    ##  Maize.Phenology.CurrentStageName Maize.AboveGround.Wt Maize.AboveGround.N
    ##  HarvestRipe:10                   Min.   : 198.5       Min.   : 2.103
    ##                                   1st Qu.: 887.8       1st Qu.: 9.149
    ##                                   Median :1347.2       Median :13.543
    ##                                   Mean   :1261.5       Mean   :12.749
    ##                                   3rd Qu.:1620.2       3rd Qu.:17.056
    ##                                   Max.   :1995.9       Max.   :18.327
    ##
    ##  Maize.Grain.Wt   Maize.Grain.Size Maize.Grain.NumberFunction
    ##  Min.   : 70.35   Min.   :0.2205   Min.   : 232.3
    ##  1st Qu.:381.36   1st Qu.:0.2820   1st Qu.:1440.0
    ##  Median :636.27   Median :0.2926   Median :2220.7
    ##  Mean   :585.84   Mean   :0.2850   Mean   :2058.2
    ##  3rd Qu.:836.26   3rd Qu.:0.2988   3rd Qu.:2880.1
    ##  Max.   :885.18   Max.   :0.3028   Max.   :3058.4
    ##
    ##  Maize.Grain.N     Maize.Total.Wt           Date
    ##  Min.   : 0.9447   Min.   : 221.6   1991-05-28:1
    ##  1st Qu.: 5.2682   1st Qu.: 984.6   1992-04-09:1
    ##  Median : 8.4116   Median :1493.8   1993-03-16:1
    ##  Mean   : 7.7509   Mean   :1379.6   1994-03-15:1
    ##  3rd Qu.:11.0796   3rd Qu.:1757.4   1995-04-04:1
    ##  Max.   :11.3600   Max.   :2152.1   1996-03-15:1
    ##                                     (Other)   :4

    ## Simple data plotting
    ggplot(data = maize , aes(x = Date, y = Maize.AboveGround.Wt)) +
      geom_point()

## Inspecting a file with ‘inspect_apsimx’: Why?

Being able to inspect a file from within R is a functionality which was not considered in previous R packages. My first motivation for doing this was to be able to verify from within R that if I edited an APSIM(X) file, the editing worked as expected. The second use of ‘inspect’ is to be able to understand the structure of ‘apsim’ files better. A third useful aspect of ‘inspect’ is that it can be used to supply the path for a parameter that will be later edited. In addition, having this functionality within R allows to make these tasks repeatable. For complex inspections and manipulations of an .apsim(x) file the GUI is recommended. However, this package is designed to work with relatively simple .apsim(x) files.

## Inspecting and Editing the ‘Maize’ example

Here I’m using the ‘Maize’ example distributed with APSIM-X but stored in the package and the specific task is: we want to make sure that the intended component was edited as expected. Let’s look at the weather file used.

    extd.dir <- system.file("extdata", package = "apsimx")
    inspect_apsimx("Maize.apsimx", src.dir = extd.dir, node = "Weather")

    ## Met file: %root%\Examples\WeatherFiles\Dalby.met

Editing a file has the side effect of creating a new file with ‘-edited’ added to the name to avoid conflict or unintended consequences, but it is also possible to overwrite it. This follows the same style as in the ‘apsimr’ package. One difference is that it is possible to supply a different ‘edit.tag’. This code does not run an APSIM simulation, it only edits the file.

Let’s say we want to modify the values of ‘Organic Carbon’ in the soil in the ‘Maize.apsimx’ example. First we should inspect the current values.

    inspect_apsimx("Maize.apsimx", src.dir = extd.dir,
                   node = "Soil", soil.child = "Organic")

    ## Soil Type:  Clay
    ## Latitude:  -27.58184
    ## Longitude:  151.3202
    ## Soil children: Physical SoilWater Organic Chemical InitialWater InitialN CERESSoilTemperature Nutrient
    ##
    ##
    ## parm         value
    ## -----------  -----------------------------
    ## $type        Models.Soils.Organic, Models
    ## FOMCNRatio   40
    ##
    ##
    ## Depth     Thickness   Carbon   SoilCNRatio   FBiom   FInert   FOM
    ## --------  ----------  -------  ------------  ------  -------  -----------------
    ## 0-15      150         1.2      12            0.04    0.4      347.129032312756
    ## 15-30     150         0.96     12            0.02    0.6      270.344362191994
    ## 30-60     300         0.6      12            0.02    0.8      163.972144349901
    ## 60-90     300         0.3      12            0.02    1        99.4541328870406
    ## 90-120    300         0.18     12            0.01    1        60.3219808311247
    ## 120-150   300         0.12     12            0.01    1        36.5871308286749
    ## 150-180   300         0.12     12            0.01    1        22.1912165985086

The function ‘inspect_apsimx’, in this example, displays various information about the organic matter in the soil. (See the help page - ?inspect_apsimx - for more options). In the next step, we ‘edit’ the values.

    ocs <- c(1.5, 1.4, 1.3, 1.2, 1.1, 1.0, 0.9)
    edit_apsimx("Maize.apsimx",
                src.dir = extd.dir,
                wrt.dir = ".",
                node = "Soil",
                soil.child = "Organic",
                parm = "Carbon", value = ocs)

    ## Edited (node):  Soil
    ## Edited (child):  Organic
    ## Edited parameters:  Carbon
    ## New values:  1.5 1.4 1.3 1.2 1.1 1 0.9
    ## Created:  ./Maize-edited.apsimx

Let’s make sure that we have changed the values successfully.

    inspect_apsimx("Maize-edited.apsimx", src.dir = ".",
                   node = "Soil", soil.child = "Organic")

    ## Soil Type:  Clay
    ## Latitude:  -27.58184
    ## Longitude:  151.3202
    ## Soil children: Physical SoilWater Organic Chemical InitialWater InitialN CERESSoilTemperature Nutrient
    ##
    ##
    ## parm         value
    ## -----------  -----------------------------
    ## $type        Models.Soils.Organic, Models
    ## FOMCNRatio   40
    ##
    ##
    ## Depth     Thickness   Carbon   SoilCNRatio   FBiom   FInert   FOM
    ## --------  ----------  -------  ------------  ------  -------  -----------------
    ## 0-15      150         1.5      12            0.04    0.4      347.129032312756
    ## 15-30     150         1.4      12            0.02    0.6      270.344362191994
    ## 30-60     300         1.3      12            0.02    0.8      163.972144349901
    ## 60-90     300         1.2      12            0.02    1        99.4541328870406
    ## 90-120    300         1.1      12            0.01    1        60.3219808311247
    ## 120-150   300         1        12            0.01    1        36.5871308286749
    ## 150-180   300         0.9      12            0.01    1        22.1912165985086

# Proposed workflow

It is recommended that you start by creating an .apsim(x) file using the GUI. In following steps the goal could be, for example, to either perform sensitivity or uncertainty analysis using R. The functions included in this package are aimed at simplifying the process of running a simulation, changing the value of a variable/parameter and running the model again iteratively. Writing complex scripts requires a high level knowledge of both APSIM and R, but it is made possible with these tools. This is the proposed workflow:

1. Create a simulation using the APSIM GUI
2. Identify variables/parameters that you want to modify (they need to be exposed in the .apsimx (JSON) or .apsim (XML) file)
3. Edit the file using ‘edit_apsim(x)’
4. Run the simulation using ‘apsim(x)’
5. Repeat steps 3 and 4 as needed
6. Read in and/or manipulate the results, possibly using ‘read_apsim(x)’
7. Perform visual and statistical analysis

Another proposed more advanced workflow would involve calibrating or optimizing variables given observed data. This is considered for future development, but not a priority since this kind of task is very specific to a given project and they are unlikely to generalize well across a range of applications.

## Wheat Example (APSIM-X)

The ‘Wheat’ example is distributed with the ‘apsimx’ package.

    sim <- apsimx("Wheat.apsimx", src.dir = extd.dir, value = "report")

If you have APSIM-X installed you can also run it in this way.

    ex.dir <- auto_detect_apsimx_examples()
    ## Copy 'Wheat' file to a temporary directory
    ## (or change as needed)
    tmp.dir2 <- tempdir()
    file.copy(paste0(ex.dir, "/", "Wheat.apsimx"), tmp.dir2)
    sim <- apsimx("Wheat.apsimx", src.dir = tmp.dir2, value = "report")

    ## Calcualte summary statistics on all variables
    summary(sim)

    ##   CheckpointID  SimulationID    Zone                 Clock.Today
    ##  Min.   :1     Min.   :1     Field:79   1900-11-14 12:00:00: 1
    ##  1st Qu.:1     1st Qu.:1                1901-11-15 12:00:00: 1
    ##  Median :1     Median :1                1902-10-21 12:00:00: 1
    ##  Mean   :1     Mean   :1                1903-11-04 12:00:00: 1
    ##  3rd Qu.:1     3rd Qu.:1                1904-11-17 12:00:00: 1
    ##  Max.   :1     Max.   :1                1905-11-07 12:00:00: 1
    ##                                         (Other)            :73
    ##  Wheat.Phenology.Zadok.Stage Wheat.Phenology.CurrentStageName
    ##  Min.   :0                   HarvestRipe:79
    ##  1st Qu.:0
    ##  Median :0
    ##  Mean   :0
    ##  3rd Qu.:0
    ##  Max.   :0
    ##
    ##  Wheat.AboveGround.Wt Wheat.AboveGround.N     Yield
    ##  Min.   :  64.59      Min.   : 2.619      Min.   : 251.3
    ##  1st Qu.: 766.44      1st Qu.:22.448      1st Qu.:3155.3
    ##  Median :1061.98      Median :26.816      Median :4050.3
    ##  Mean   :1029.24      Mean   :25.734      Mean   :4126.6
    ##  3rd Qu.:1355.02      3rd Qu.:30.893      3rd Qu.:5347.4
    ##  Max.   :1654.14      Max.   :35.665      Max.   :7204.5
    ##
    ##  Wheat.Grain.Protein Wheat.Grain.Size  Wheat.Grain.Number
    ##  Min.   :10.78       Min.   :0.01992   Min.   : 1112
    ##  1st Qu.:15.12       1st Qu.:0.02196   1st Qu.:13475
    ##  Median :15.15       Median :0.02334   Median :17118
    ##  Mean   :15.08       Mean   :0.02492   Mean   :16240
    ##  3rd Qu.:15.20       3rd Qu.:0.02646   3rd Qu.:19980
    ##  Max.   :15.35       Max.   :0.04120   Max.   :24042
    ##
    ##  Wheat.Grain.Total.Wt Wheat.Grain.Total.N Wheat.Total.Wt
    ##  Min.   : 25.13       Min.   : 0.6662     Min.   :  79.04
    ##  1st Qu.:315.53       1st Qu.: 8.3994     1st Qu.: 889.73
    ##  Median :405.03       Median :10.6031     Median :1236.50
    ##  Mean   :412.66       Mean   :10.9070     Mean   :1193.27
    ##  3rd Qu.:534.74       3rd Qu.:14.1672     3rd Qu.:1563.53
    ##  Max.   :720.45       Max.   :19.2557     Max.   :1922.30
    ##
    ##          Date
    ##  1900-11-14: 1
    ##  1901-11-15: 1
    ##  1902-10-21: 1
    ##  1903-11-04: 1
    ##  1904-11-17: 1
    ##  1905-11-07: 1
    ##  (Other)   :73

    ## Plot data
    ggplot(data = sim, aes(x = Date, y = Yield)) + geom_point()

    ## Inspect the Wheat .apsimx file
    inspect_apsimx("Wheat.apsimx", src.dir = extd.dir, node = "Crop")

    ##
    ##
    ## parm           value
    ## -------------  -------
    ## StartDate      1-may
    ## EndDate        10-jul
    ## MinESW         100
    ## MinRain        25
    ## RainDays       7
    ## CultivarName   Hartog
    ## SowingDepth    30
    ## RowSpacing     250
    ## Population     120

    ## This only displays the available 'Manager' components
    inspect_apsimx("Wheat.apsimx", src.dir = extd.dir, node = "Manager")

    ## Management Scripts:  SowingFertiliser Harvest SowingRule1

    ## Looking more in-depth into 'SowingRule1'
    inspect_apsimx("Wheat.apsimx", src.dir = extd.dir,
                   node = "Manager", parm = list("SowingRule1", NA))

    ## Management Scripts:  SowingFertiliser Harvest SowingRule1
    ##
    ## Name:  SowingRule1
    ##
    ##
    ## parm           value
    ## -------------  -------
    ## StartDate      1-may
    ## EndDate        10-jul
    ## MinESW         100
    ## MinRain        25
    ## RainDays       7
    ## CultivarName   Hartog
    ## SowingDepth    30
    ## RowSpacing     250
    ## Population     120

If you only want to display the Wheat cultivar choose the sixth element in that table.

    inspect_apsimx("Wheat.apsimx", src.dir = extd.dir,
                   node = "Manager", parm = list("SowingRule1", 6))

    ## Management Scripts:  SowingFertiliser Harvest SowingRule1
    ##
    ## Name:  SowingRule1
    ## Key: CultivarName
    ##
    ##
    ## parm           value
    ## -------------  -------
    ## CultivarName   Hartog

    ## We can print and store the path to this parameter
    pp <- inspect_apsimx("Wheat.apsimx", src.dir = extd.dir,
                   node = "Manager", parm = list("SowingRule1", 6),
                   print.path = TRUE)

    ## Management Scripts:  SowingFertiliser Harvest SowingRule1
    ##
    ## Name:  SowingRule1
    ## Key: CultivarName
    ##
    ##
    ## parm           value
    ## -------------  -------
    ## CultivarName   Hartog
    ##
    ## Parm path: .Simulations.Simulation.Field.SowingRule1.CultivarName

## Millet example (APSIM ‘Classic’)

One of the difficulties with working with APSIM(X) in scripting efforts is that the names of the parameters that we might want to edit can be buried deep in the .apsim(x) file and that there might be multiple instances of those parameters. To overcome this (to some extent) the ‘inspect’ functions can provide the path to the parameter to edit. For example,

    inspect_apsim("Millet.apsim", src.dir = extd.dir, node  = "Manager")

    ## Crop Type:  millet
    ## Management Scripts:
    ## Sow on a fixed date
    ## Harvesting rule
    ## Tiller Aggregation

We can see that we have ‘Sow on a fixed date’ as one of the options. Let’s say that we want to edit the planting density

    inspect_apsim("Millet.apsim", src.dir = extd.dir, node  = "Manager",
                  parm = list("Sow on a fixed date", NA))

    ## Crop Type:  millet
    ## Management Scripts:
    ## Sow on a fixed date
    ## Harvesting rule
    ## Tiller Aggregation
    ##
    ##
    ## Selected manager:  Sow on a fixed date
    ##
    ##
    ## parm                                  value
    ## ------------------------------------  --------
    ## Sowing criteria
    ## Enter sowing date (dd-mmm) :          1-dec
    ## Sowing parameters
    ## Enter name of crop to sow :           millet
    ## Enter sowing density  (plants/m2) :   7.5
    ## Enter sowing depth  (mm) :            30
    ## Enter cultivar :                      wrajpop

Planting density is the fifth element in that table. We can obtain the full path by using the ‘print.path’ option. It makes sense to use this option once you have found the parameter you are looking for.

    inspect_apsim("Millet.apsim", src.dir = extd.dir, node  = "Manager",
                  parm = list("Sow on a fixed date",5), print.path = TRUE)

    ## Crop Type:  millet
    ## Management Scripts:
    ## Sow on a fixed date
    ## Harvesting rule
    ## Tiller Aggregation
    ##
    ##
    ## Selected manager:  Sow on a fixed date
    ##
    ##
    ##      parm                                  value
    ## ---  ------------------------------------  ------
    ## 5    Enter sowing density  (plants/m2) :   7.5
    ## Parm path: /folder/simulation/area/folder/manager[1]/ui/density

    ## Or store it in an object for later editing
    pp <- inspect_apsim("Millet.apsim", src.dir = extd.dir, node = "Manager",
                  parm = list("Sow on a fixed date",5), print.path = TRUE)

    ## Crop Type:  millet
    ## Management Scripts:
    ## Sow on a fixed date
    ## Harvesting rule
    ## Tiller Aggregation
    ##
    ##
    ## Selected manager:  Sow on a fixed date
    ##
    ##
    ##      parm                                  value
    ## ---  ------------------------------------  ------
    ## 5    Enter sowing density  (plants/m2) :   7.5
    ## Parm path: /folder/simulation/area/folder/manager[1]/ui/density

Once we have identified the parameter we want to edit, we can do so by using the ‘edit_apsim’ function. When using the ‘parm.path’ argument, node should be “Other”.

    edit_apsim("Millet.apsim", src.dir = extd.dir, wrt.dir = tmp.dir,
               node = "Other", parm.path = pp, value = 8,
               edit.tag = "-pp")

    ## Edited /folder/simulation/area/folder/manager[1]/ui/density
    ## Edited parameter
    ## New values  8
    ## Created  /var/folders/6j/xksd1tld70q91h73d5s0ln7c0000gn/T//RtmpeQZ4oX/Millet-pp.apsim

Verify that it was edited correctly.

    inspect_apsim("Millet-pp.apsim", src.dir = tmp.dir,
                  node = "Manager",
                  parm = list("Sow on a fixed date", NA))

    ## Crop Type:  millet
    ## Management Scripts:
    ## Sow on a fixed date
    ## Harvesting rule
    ## Tiller Aggregation
    ##
    ##
    ## Selected manager:  Sow on a fixed date
    ##
    ##
    ## parm                                  value
    ## ------------------------------------  --------
    ## Sowing criteria
    ## Enter sowing date (dd-mmm) :          1-dec
    ## Sowing parameters
    ## Enter name of crop to sow :           millet
    ## Enter sowing density  (plants/m2) :   8
    ## Enter sowing depth  (mm) :            30
    ## Enter cultivar :                      wrajpop

    ## [1] TRUE

# Advanced Examples

## Inspecting a ‘Replacement’ component

Many additional options in an APSIM-X simulation can be realized through the use of ‘Replacements’. For this, there is a function that allows inspection. For this, it is important to know the structure of the ‘replacement’ and explore the available components. For example, if we want to display the xy pair for the thermal time in the phenology component of the ‘Maize’ replacement we might go through the following steps:

State the node (“Maize”) and display available components:

    inspect_apsimx_replacement("MaizeSoybean.apsimx", src.dir = extd.dir,
                               node = "Maize", display.available = TRUE)

    ## Replacements:  Soybean Maize
    ## node: Maize
    ## CropType Maize
    ## Level: node
    ## list Name: Maize
    ## list length: 11
    ## list names: $type CropType IsAlive IsEnding DaysAfterEnding ResourceName Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 20
    ## Children Names: Arbitrator Phenology Structure Grain Root Leaf Husk Rachis Stem AboveGround BelowGround Total TotalLive TotalDead EarLive AboveGroundLive AboveGroundDead Future Development Needs CultivarFolder Spike
    ## missing node.child

Choose ‘Phenology’ as a ‘child’ of ‘Maize’:

    inspect_apsimx_replacement("MaizeSoybean.apsimx", src.dir = extd.dir,
                               node = "Maize", node.child = "Phenology",
                               display.available = TRUE)

    ## Replacements:  Soybean Maize
    ## node: Maize
    ## CropType Maize
    ## Level: node
    ## list Name: Maize
    ## list length: 11
    ## list names: $type CropType IsAlive IsEnding DaysAfterEnding ResourceName Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 20
    ## Children Names: Arbitrator Phenology Structure Grain Root Leaf Husk Rachis Stem AboveGround BelowGround Total TotalLive TotalDead EarLive AboveGroundLive AboveGroundDead Future Development Needs CultivarFolder Spike
    ## node child: Phenology
    ## list Name: Phenology
    ## list length: 6
    ## list names: $type Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 16
    ## Children Names: ThermalTime Germinating Emerging Juvenile Photosensitive LeafAppearance FlagLeafToFlowering FloweringToGrainFilling GrainFilling Maturing MaturityToHarvestRipe ReadyForHarvesting Photoperiod FloweringDAS MaturityDAS BBCH
    ## node subchild:
    ## missing node.subchild

Choose ‘ThermalTime’ as a ‘sub.child’ of ‘Phenology’:

    inspect_apsimx_replacement("MaizeSoybean.apsimx", src.dir = extd.dir,
                               node = "Maize", node.child = "Phenology",
                               node.subchild = "ThermalTime",
                               display.available = TRUE)

    ## Replacements:  Soybean Maize
    ## node: Maize
    ## CropType Maize
    ## Level: node
    ## list Name: Maize
    ## list length: 11
    ## list names: $type CropType IsAlive IsEnding DaysAfterEnding ResourceName Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 20
    ## Children Names: Arbitrator Phenology Structure Grain Root Leaf Husk Rachis Stem AboveGround BelowGround Total TotalLive TotalDead EarLive AboveGroundLive AboveGroundDead Future Development Needs CultivarFolder Spike
    ## node child: Phenology
    ## list Name: Phenology
    ## list length: 6
    ## list names: $type Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 16
    ## Children Names: ThermalTime Germinating Emerging Juvenile Photosensitive LeafAppearance FlagLeafToFlowering FloweringToGrainFilling GrainFilling Maturing MaturityToHarvestRipe ReadyForHarvesting Photoperiod FloweringDAS MaturityDAS BBCH
    ## node subchild: ThermalTime
    ## Subchild Name:  ThermalTime
    ## list Name: ThermalTime
    ## list length: 6
    ## list names: $type Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 1
    ## Children Names: BaseThermalTime
    ## missing node.subsubchild

Now we need to pick from within ‘ThermalTime’. There is a component named “BaseThermalTime”.

    inspect_apsimx_replacement("MaizeSoybean.apsimx", src.dir = extd.dir,
                               node = "Maize", node.child = "Phenology",
                               node.subchild = "ThermalTime",
                               node.subsubchild = "BaseThermalTime",
                               display.available = TRUE)

    ## Replacements:  Soybean Maize
    ## node: Maize
    ## CropType Maize
    ## Level: node
    ## list Name: Maize
    ## list length: 11
    ## list names: $type CropType IsAlive IsEnding DaysAfterEnding ResourceName Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 20
    ## Children Names: Arbitrator Phenology Structure Grain Root Leaf Husk Rachis Stem AboveGround BelowGround Total TotalLive TotalDead EarLive AboveGroundLive AboveGroundDead Future Development Needs CultivarFolder Spike
    ## node child: Phenology
    ## list Name: Phenology
    ## list length: 6
    ## list names: $type Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 16
    ## Children Names: ThermalTime Germinating Emerging Juvenile Photosensitive LeafAppearance FlagLeafToFlowering FloweringToGrainFilling GrainFilling Maturing MaturityToHarvestRipe ReadyForHarvesting Photoperiod FloweringDAS MaturityDAS BBCH
    ## node subchild: ThermalTime
    ## Subchild Name:  ThermalTime
    ## list Name: ThermalTime
    ## list length: 6
    ## list names: $type Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 1
    ## Children Names: BaseThermalTime
    ## Name sub-sub-child:  BaseThermalTime
    ## Available node children (unpack_node):
    ## $type : Models.Functions.XYPairs, Models
    ## X : 0 18 26 34 44
    ## Y : 0 10 18 26 0
    ## Name : TemperatureResponse
    ## Children :
    ## IncludeInDocumentation : TRUE
    ## Enabled : TRUE
    ## ReadOnly : FALSE
    ##
    ## $type : Models.Functions.ThreeHourSin, Models
    ## TempRangeFactors :
    ## Name : InterpolationMethod
    ## Children :
    ## IncludeInDocumentation : TRUE
    ## Enabled : TRUE
    ## ReadOnly : FALSE
    ##
    ## missing node.sub3child

‘BaseThermalTime’ is the only child inside ‘ThermalTime’, but within ‘BaseThermalTime’ there are two Children: ‘TemperatureResponse’ and ‘InterpolationMethod’. There is not much to edit for ‘InterpolationMethod’, so we choose ‘TemperatureResponse’.

    inspect_apsimx_replacement("MaizeSoybean.apsimx", src.dir = extd.dir,
                               node = "Maize", node.child = "Phenology",
                               node.subchild = "ThermalTime",
                               node.subsubchild = "BaseThermalTime",
                               node.sub3child = "TemperatureResponse")

    ## Replacements:  Soybean Maize
    ## node: Maize
    ## CropType Maize
    ## node child: Phenology
    ## node subchild: ThermalTime
    ## Subchild Name:  ThermalTime
    ## Name sub-sub-child:  BaseThermalTime
    ## Name sub-sub-sub-child:  TemperatureResponse
    ## $type : Models.Functions.XYPairs, Models
    ## X : 0 18 26 34 44
    ## Y : 0 10 18 26 0
    ## Name : TemperatureResponse
    ## Children :
    ## IncludeInDocumentation : TRUE
    ## Enabled : TRUE
    ## ReadOnly : FALSE

Choose the ‘X’ and ‘Y’ parameters within ‘TemperatureResponse’.

    inspect_apsimx_replacement("MaizeSoybean.apsimx", src.dir = extd.dir,
                               node = "Maize", node.child = "Phenology",
                               node.subchild = "ThermalTime",
                               node.subsubchild = "BaseThermalTime",
                               node.sub3child = "TemperatureResponse",
                               parm = c("Y", "X"))

    ## Replacements:  Soybean Maize
    ## node: Maize
    ## CropType Maize
    ## node child: Phenology
    ## node subchild: ThermalTime
    ## Subchild Name:  ThermalTime
    ## Name sub-sub-child:  BaseThermalTime
    ## Name sub-sub-sub-child:  TemperatureResponse
    ## $type : Models.Functions.XYPairs, Models
    ## X : 0 18 26 34 44
    ## Y : 0 10 18 26 0

The function shows the available replacements (“Maize” and “Soybean”), the ‘CropType’ if available, the subchild name and the ‘Y’ vector in this example. If parm is not specified all elements will be displayed.

Let’s say we want to inspect details of soybean cultivars in the same file:

    inspect_apsimx_replacement("MaizeSoybean.apsimx", src.dir = extd.dir,
                               node = "Soybean", display.available = TRUE)

    ## Replacements:  Soybean Maize
    ## node: Soybean
    ## CropType Soybean
    ## Level: node
    ## list Name: Soybean
    ## list length: 11
    ## list names: $type CropType IsAlive IsEnding DaysAfterEnding ResourceName Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 41
    ## Children Names: Arbitrator Phenology Structure Grain Root Nodule Shell Leaf Stem AboveGround BelowGround Total TotalLive TotalDead Pod Memo PioneerP932T16R_MG32 PioneerP22T69R_MG22 Trial_MG00 Lambert_MG0 IA1006_MG10 IA2008_MG20 Macon_MG30 Pioneer94B01_MG40 Hutcheson_MG50 NK622_MG60 Becks367NRR_MG37 AsgrowAG4403_MG40 HornbeckHBK4891_MG40 AsgrowAG5701_MG50 PioneerP9504_MG50 Pioneer92MGI_MG26 Becks321NRR_MG32 Hooper_MG40 Stephens_MG40 Davis PioneerP92Y75_MG27 PioneerP22T61_MG22 Buchanan Djakal PioneerP93M11_MG31
    ## missing node.child

In this case the cultivars are at the sub-node level.

    inspect_apsimx_replacement("MaizeSoybean.apsimx",
                               src.dir = extd.dir,
                               node = "Soybean",
                               node.child = "PioneerP22T61_MG22",
                               display.available = FALSE)

    ## Replacements:  Soybean Maize
    ## node: Soybean
    ## CropType Soybean
    ## node child: PioneerP22T61_MG22
    ## $type : Models.PMF.Cultivar, Models
    ##  : [Phenology].Vegetative.Target.FixedValue = 328
    ##  : [Phenology].EarlyFlowering.Target.FixedValue = 106
    ##  : [Phenology].EarlyGrainFilling.Target.FractionofGrainfilling.FixedValue = 0.3
    ##  : [Phenology].LateGrainFilling.Target.EntireGrainfillPeriod.FixedValue = 499
    ##  : [Phenology].PhotoperiodModifier.XYPairs.X = 13.59, 17.6
    ## Command
    ## Name : PioneerP22T61_MG22
    ## IncludeInDocumentation : TRUE
    ## Enabled : TRUE
    ## ReadOnly : FALSE
    ## no node sub-children available or parm not equal to null

The function inspect_apsimx_replacement can also be used to inspect more complex file structures such as the ‘Factorial’ example distributed with APSIM-X. See ‘?inspect_apsimx_replacement’.

## Editing a ‘Replacement’

After using the ‘inspect’ version of the file, editing should be much more straight forward.

    edit_apsimx_replacement("MaizeSoybean.apsimx",
                            src.dir = extd.dir, wrt.dir = tmp.dir,
                            node = "Maize", node.child = "Phenology",
                            node.subchild = "ThermalTime",
                            node.subsubchild = "BaseThermalTime",
                            node.sub3child = "TemperatureResponse",
                            parm = "Y", value = c(0, 12, 20, 28, 0))

    ## Replacements:  Soybean Maize
    ## CropType Maize
    ## Available node children:  Arbitrator Phenology Structure Grain Root Leaf Husk Rachis Stem AboveGround BelowGround Total TotalLive TotalDead EarLive AboveGroundLive AboveGroundDead Future Development Needs CultivarFolder Spike
    ## Subchild Name:  ThermalTime
    ## Subsubchild Name:  BaseThermalTime
    ## Sub-sub-subchild Name:  TemperatureResponse
    ## Edited (node):  Maize
    ## Edited (node.child):  Phenology
    ## Edited (node.subchild):  ThermalTime
    ## Edited (node.subsubchild):  BaseThermalTime
    ## Edited (node.sub3child):  TemperatureResponse
    ## Edit (level):  6
    ## Edited parameter:  Y
    ## New values:  0 12 20 28 0
    ## Created:  /var/folders/6j/xksd1tld70q91h73d5s0ln7c0000gn/T//RtmpeQZ4oX/MaizeSoybean-edited.apsimx

Let’s inspect the edited file

    inspect_apsimx_replacement("MaizeSoybean-edited.apsimx",
                               src.dir = tmp.dir,
                               node = "Maize",
                               node.child = "Phenology",
                               node.subchild = "ThermalTime",
                               node.subsubchild = "BaseThermalTime",
                               node.sub3child = "TemperatureResponse",
                               parm = "Y")

    ## Replacements:  Soybean Maize
    ## node: Maize
    ## CropType Maize
    ## node child: Phenology
    ## node subchild: ThermalTime
    ## Subchild Name:  ThermalTime
    ## Name sub-sub-child:  BaseThermalTime
    ## Name sub-sub-sub-child:  TemperatureResponse
    ## $type : Models.Functions.XYPairs, Models
    ## Y : 0 12 20 28 0

## Inspecting and editing a Factorial

The complexity of APSIM-X files can be mind-boggling and it makes it difficult to write robust functions across all tasks that APSIM is able to accomplish. I wrote the ‘inspect_apsimx_replacement’ and ‘edit_apsimx_replacement’ specifically to edit replacements but these functions have much more flexibility than ‘inspect_apsimx’ and ‘edit_apsimx’. The function ‘apsimx_example’ is limited in the number of examples that it is allowed to run, but this does not mean that you cannot run the other examples which are distributed with APSIM-X. Let’s take the ‘Factorial’ example:

If we want to inspect and edit this file, we need the ‘inspect_apsimx_replacement’ function.

    ## There are multiple 'Experiments' so we need to pick one
    inspect_apsimx_replacement("Factorial", src.dir = extd.dir,
                               root = list("Experiment", NA))
    ##These positions matched  Experiment   1 2 3 4 5
    ##Error in inspect_apsimx_replacement("Factorial", src.dir = ex.dir, root = ##list("Experiment", : Multiple root nodes found. Please provide a position

    ## There are multiple 'Experiments' so we need to pick one
    inspect_apsimx_replacement("Factorial", src.dir = extd.dir,
                               root = list("Experiment", 1))

    ## Replacements:  Factors Base
    ## Please provide a node

    ## We need to provide a node
    inspect_apsimx_replacement("Factorial", src.dir = extd.dir,
                               root = list("Experiment", 1),
                               node = "Base", display.available = TRUE)

    ## Replacements:  Factors Base
    ## node: Base
    ## Level: node
    ## list Name: Base
    ## list length: 7
    ## list names: $type Descriptors Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 4
    ## Children Names: Weather Clock Summary Field
    ## missing node.child

    ## We need to provide a node child
    inspect_apsimx_replacement("Factorial", src.dir = extd.dir,
                               root = list("Experiment", 1),
                               node = "Base", node.child = "Clock",
                               display.available = TRUE)

    ## Replacements:  Factors Base
    ## node: Base
    ## Level: node
    ## list Name: Base
    ## list length: 7
    ## list names: $type Descriptors Name Children IncludeInDocumentation Enabled ReadOnly
    ## Children: Yes
    ## Children length: 4
    ## Children Names: Weather Clock Summary Field
    ## node child: Clock
    ## Available node children (unpack_node):  $type StartDate EndDate Name Children IncludeInDocumentation Enabled ReadOnly
    ## $type : Models.Clock, Models
    ## StartDate : 2003-10-20T00:00:00
    ## EndDate : 2004-05-23T00:00:00
    ## Name : Clock
    ## IncludeInDocumentation : TRUE
    ## Enabled : TRUE
    ## ReadOnly : FALSE
    ## no node sub-children available or parm not equal to null

Here we stop at this level but it is possible to dig deeper using ‘node.subchild’ and ‘node.subsubchild’. It is not possible at this point to dig deeper than ‘node.subsubchild’ in the hierarchy level.

The inspect_apsimx function can also handle factorials.

    inspect_apsimx("Factorial.apsimx", src.dir = extd.dir)
    ## Simulation structure:
    ## list Name: Simulations
    # list length: 8
    # list names: $type ExplorerWidth Version Name Children IncludeInDocumentation Enabled ReadOnly
    # Children: Yes
    # Children length: 6
    # Children Names: Experiment RangeExperiment OperationsExpt Compound ManagerExpt DataStore
    # Error in inspect_apsimx("Factorial", src.dir = ex.dir) :
    #   more than one simulation found and no root node label has been specified
    #  select one of the children names above

We need to pick one out of the possible factorials. If you check this file with the APSIM GUI, you’ll see that within ‘RangeExperiment’ there is ‘Factors’ and ‘Base2’, but the core simulation is within ‘Base2’. The ‘root’ argument provides the specific factorial and the node ‘Base2’ within that factorial.

    inspect_apsimx("Factorial.apsimx", src.dir = extd.dir,
                   root = c("RangeExperiment", "Base2"),
                   node = "Weather")

    ## Met file: WeatherFiles\lincoln.met

Following this structure, if we want to edit the path to the weather file we can use the following example.

    edit_apsimx("Factorial.apsimx",
                src.dir = extd.dir, wrt.dir = tmp.dir,
                root = c("RangeExperiment", "Base2"),
                node = "Weather",
                value = "Ames.met")

    ## Edited (node):  Weather
    ## Edited (child):  none
    ## Edited parameters:
    ## New values:  Ames.met
    ## Created:  /var/folders/6j/xksd1tld70q91h73d5s0ln7c0000gn/T//RtmpeQZ4oX/Factorial-edited.apsimx

I won’t be running the ‘Factorial’ example here, but if you are interested this is done in the folder ‘tests’ in the pacakge source.

# APSIM-X Inputs: Weather and Soil

## Obtaining weather data

One of the easiest ways of generating weather data (“.met” files) is by using the ‘nasapower’ (https://github.com/ropensci/nasapower) or ‘FedData’ (https://github.com/ropensci/FedData) packages. See function ‘nasapower::create_met’. In addition in this package the following utilities are provided:

- read_apsim_met: read an APSIM met file into R with S3 class ‘met’.
- write_apsim_met: write an APSIM met file from an object of class ‘met’.
- check_apsim_met: check for reasonable values for met variables.
- impute_apsim_met: impute missing values using linear interpolation, splines or the mean.
- get_power_apsim_met: (requires the ‘nasapower’ package). Fetch data and create a ‘met’ R object and (optionally) write a met file to disk.
- get_daymet_apsim_met: (requires the ‘FedData’ package). Fetch data and create a ‘met’ R object and (optionally) write a met file to disk.
- get_iem_apsim_met: Fetch data from Iowa Environmental Mesonet
- get_iemre_apsim_met: Fetch data from Iowa Environmental Mesonet Reanalysis

Note that similar utilities are available in the ‘APSIM’ package (loadMet, prepareMet, checkMet, writeMetFile) for reading, preparing, checking and writing a met file, but not for imputing.

## Obtaining soil data

In the USA, soil data can be obtained through the ‘FedData’ R package (https://github.com/ropensci/FedData) by using the function ‘get_ssurgo’. I have developed helper functions ‘ssurgo2sp’ for conversion from ‘SSURGO’ files to a soil profile and ‘apsimx_soil_profile’ for generating a soil profile that can be used in APSIM-X. Finally, the function ‘edit_apsimx_replace_soil_profile’ will batch replace the soil profile created by ‘apsimx_soil_profile’ in a designated ‘.apsimx’ file. Similarly, ‘edit_apsim_replace_soil_profile’ will batch replace the soil profile in a designated ‘.apsim’ (Classic) file. I will be working on a more concrete tutorial soon.

# File Type (or File Format) Details

APSIM has traditionally generated files that produce simulations using an XML schema. This has been used with APSIM versions of 7.x, ‘Classic’. With APSIM-X a new format based on JSON files has been implemented and apparently both formats will be supported for the forseeable future. JSON files are less verbose and they are gaining widespread adoption. All distributed APSIM-X examples are ‘JSON’ now.

The apsimx package supports inspection and editing of both file types, but XML is for ‘Classic’ only and JSON is for APSIM-X. In most instances the parameters that are likely to need inspection and editing are supported, but more features will be added in the future as needed.

# Additional functions

apsim_version: displays which version(s) of APSIM(X) are available. For example,

    ava <- apsim_version()
    aiu <- apsim_version(which = "inuse")

edit_apsimx_batch: Uses APSIM-X built-in functionality to edit parameters. In testing, it is slower than the other ’edit_apsimx*’ functions.

# To-Do

- inspect_apsimx_replacement challenge this function with more complex examples. It has problems with ‘manager’ when replacements are present.

- Add more tests using the ‘CoverCrop example’ (APSIM ‘Classic’). This would be the motivation for writing a function for ‘factorials’. ‘edit_apsim_factorial’.

- Include parameter estimation example

# Appendix

Files in ‘inst/extdata’ and how they are used (ordered alphabetically):

- ames-10-19.met: not sure if it is used, if it is not, I’ll delete it.
- Ames.met: used to run the Soybean.apsimx.
- Factorial.apsimx: This file IS needed for the vignette.
- ISUAG (folder): SSURGO files to test the ssurgo2sp function.
- Maize_old.apsimx: Old-style ‘xml’ file used by APSIM-X.
- maize-factorial.apsim (file that I might use to test the ability to inspect and edit factorial .apsim files). TODO: low priority
- maize-manager-folder.apsimx: file I will use to test whether I need to modify inspect and edit functions when the management is inside a folder.
- maize-soybean-rotation.apsim: example file with a maize and soybean rotation used in testing and in the ‘inspect_apsim’ file.
- maize-swim.apsim: example file with the SWIM module for testing (test_apsim_swim.R).
- Maize.apsimx: This file is needed for the vignette.
- Maize.db: This file is needed for the vignette.
- Maize.out: This file is needed for the ‘read_apsim’ example.
- MaizeSoybean.apsimx: This file is needed for the vignette and for testing in ‘test_replacements.R’
- Millet.apsim: Millet example from APSIM ‘Classic’ for testing ‘inspect_apsim’ and used in the vignette.
- Millet.out/sum: result from the Millet simulation. Used in the ‘read_apsim’ example.
- Soybean.apsimx: Soybean example for APSIM-X. Used in ‘test_replacements.R’.
- Wheat.apsimx: This file is used in the vignette.
- Wheat.db: This file is used in the vignette.
- WheatRye.apsimx: This file is used in ‘test_replacements.R’.