Skip to content

fsm python Tute 2 Build Paddock

Kipling edited this page May 26, 2021 · 12 revisions

Building the Paddocks

In this tutorial, we will focus on building our paddock. The Paddock object is a core part of using the farm soil mapping tools as it will contain all the information to perform the various types of analysis. As shown below, the paddock is made up of 3 components. A boundary, grids and point data.

Lesson one - GridInput

Before creating your paddocks, you will need to prepare your datasets using the GridInput object. This can be done with any type of measurements such as elevation or gamma radiometric readings. When using the GridInput object the fsm-tools will align the gird to a pre-defined specification (lat/lon spacings and point of origin). This ensures that all the paddock layers are aligned and for processing.

To start, let's get the directory that has all of our sample data:

input_dir = "/path/to/your/fsm_sample_data"

Now we can prepare the GridInput for the elevation layer. This is the dem.tif file.

import os
from fsm.models.paddock import GridInput, Paddock, inputFileTypes

ELEVATION = "Elevation"
ele_tif = "dem.tif"
ele_file = os.path.join(input_dir, ele_tif)
ele_gird_input = GridInput(uid=ELEVATION, measurementType="elevation", inputFile=ele_file)

Note that we have also supplied:

  • uid a unique identifier
  • measurementType a helpful note about the type of measurement
  • inputFile the location of the tif file
  • inputFileType only inputFileTypes.TIFF is supported at this point

Lets add a few more paddock layers using GridInput:

NIR = "nir"
nir_tif = "nir.tif"
nir_file = os.path.join(input_dir, nir_tif)
nir_gird_input = GridInput(uid=NIR, measurementType="ndvi", inputFile=nir_file)

RED = "red"
red_tif = "red.tif"
red_file = os.path.join(input_dir, red_tif)
red_gird_input = GridInput(uid=RED, measurementType="ndvi", inputFile=red_file)

Next we need to create a boundary. We can do this directly by using the Boundary object:

from fsm.models.boundary import Boundary
# Boundary([[lon,lat],[lon,lat],[lon,lat],[lon,lat],[lon,lat]], bbox)

Or we can use a helper.

from fsm.helpers.shp_converter import shpToBoundaries

shpFileName = "paddock_b.shp"
sFile = os.path.join(input_dir, shpFileName)
boundaries = shpToBoundaries(sFile)

For .geojson files:

from fsm.helpers.geojson_converter import geojsonToBoundaries

fileName = "paddocks.json"
gFile = os.path.join(input_dir, fileName)
boundaries = geojsonToBoundaries(file = gFile)

Finally, we can create our paddock:

paddock =  Paddock(inputData=[ele_gird_input, nir_gird_input, red_gird_input], id="myPaddock", bounds=boundary, persistDir=persist_dir)

Note: persistDir will persist the processed data for faster access in future tasks.

If you run into memory problems, set lightning=False.

If you have paddock information in your geojson file, you may want to consider:

from fsm.helpers.geojson_converter import geojsonToPaddocks

paddocks = geojsonToPaddocks(file = gFile, inputData=[nir_gird_input, red_gird_input, ele_gird_input])

The id input will help with identifying the output files.

Be sure to check that the boundaries have been loaded properly with the helpers.

Making NDVI form red and nir

Often, we may want to mix the data from the layers that we have to create new layers. This is the case for creating ndvi from red and nir. In the python version, we can achieve this using the mixProcessor, one of the fsm processors.

NDVI = "ndvi"
mix_config = MixConfig(
                primary_layer=NIR,
                secondary_layer=RED,
                new_layer=NDVI,
                func= lambda a, b: (a-b)/(a+b))
mixProcessor([paddock], mix_config)

Note the lambda function. That's how you calculate the ndvi from red and nir. See here

By calling the paddockLayersDict, we can see all out added paddock layers, including the ndvi.

print(paddock.paddockLayersDict)

Lesson three - Point Data

PointAttribute

Note: this will be used in a later lesson

The first step in adding point data to your paddock is creating PointAttribute for each PointDataset. A point attribute represents a measured attribute from a soil sample.

attribute: str - The attribute name. eg "clay" value: Union[float, str] - the numerical value. eg 21 units: Optional[str] - measurement unite. eg % notes: Optional[str] - any notes. eg "indirectly measured"

Usage:

pa = PointAttribute("clay", 20, "%")

PointDataset

Once you have put all of your attributes into a list, you may create your PointDataset. This represents a soil sample that was taken at a date, depthRange (in cm), and location (lat, lon).

Usage:

from datetime import datetime
pd = PointDataset(id=3, attributes=[pa1, pa2, pa3, pa4, pa5], location=(-23.6757, 133.8915), depthRange=(0, 10), date=datetime(2021,01,12))

Full example

from fsm.models.paddock import Paddock, PointAttribute, PointDataset
from datetime import datetime

attributes5 = [PointAttribute("clay",20), PointAttribute("sand",40), PointAttribute("silt",40)]
pd5 = PointDataset(id=3, attributes=attributes5, location=location, depthRange=depths, date=date)

persist_dir = "/path/to/persist_dir"

Paddock(
    inputData=PaddockInputList, 
    id=paddock_id, 
    soilPointDataArray=[pd1,pd2,pd3,pd4,pd5],
    persistDir=persist_dir
)

Note: the persistDir input will allow you to persist grid aligned data. This can be helpful for future processing as aligning data to the grid can take a long time or use a lot of memory.

For this tute, you can easily import your samples to PointDatasets like

from fsm.sampleLocation import SampleLocationRecommender

sample_file = "samples.json"
sample_path = os.path.join(input_dir, sample_file)

point_datasets = geojsonToPointDatasets(sample_path)

Clone this wiki locally