Creating Virtual Procedures

With Virtual Procedures you are able to use other procedures data (real or virtual) and manipulate data to get a different result.

_images/virtual_proc.png

Warning

When working with VP it’s easy to make some mistakes while coding.. So while testing your VP look at the apache error log to read about errors:

tail -f /var/log/apache2/error.log

If something goes wrong or you do some modification on your code, you should also restart the apache server.

sudo service apache2 restart

When you have filled up istSOS automatically you have create a couple of virtual procedures:

V_LUGANO: it gets data from a sensor measuring temperature in Celsius degree (T_LUGANO) and transforms it to Fahrenheit degree, here is the code:

from istsoslib.responders.GOresponse import VirtualProcess
class istvp(VirtualProcess):
    procedures = {
        "T_LUGANO": "urn:ogc:def:parameter:x-istsos:1.0:meteo:air:temperature"
    }
    def execute(self):
        data = self.getData("T_LUGANO")
        out=[]
        for idx in range(len(data)):
            rec = data[idx]
            if self.filter.qualityIndex == True:
                out.append([rec[0], self.convert(rec[1]), rec[2]])
            else:
                out.append([rec[0], self.convert(rec[1])])
        return out
    def convert(self, celsius):
        if celsius is None:
            return -999.9
        return (float(celsius) *1.8 + 32)

Test the virtual procedure executing a getObservation request here

V_GNOSCA: transforms river water levels in river discharge appling a rating curve defined with different parameters for different periods.

Here is the code, which instantiate a special istSOS virtual procedure class (VirtualProcessHQ):

from istsoslib.responders.GOresponse import VirtualProcessHQ
class istvp(VirtualProcessHQ):
    procedures = {
        "RH_GNOSCA": "urn:ogc:def:parameter:x-istsos:1.0:river:water:height"
    }

Select the “Rating curve” tap panel to see the rating curves values:

_images/rating_curve.png

Test the virtual procedure executing a getObservation request here

Creating a reference evapotranspiration virtual procedure manually

Evapotranspiration is an important parameter that takes part in the water balance assessment, and therefore in any attempt to calculate and predict plant water needs and optimized irrigation. ENORASIS use evapotranspiration as one of the component to feed the innovative advanced algorithms and optimization processes leading to irrigation optimized scheduling.

Note

A possible approach it to assess water needs by using a daily water balance calculation considering rainfall and irrigations as the water inputs and crop evapotranspiration (ETc ) as the loss. The water balance for a particular irrigation block, in millimetres, can then be calculated using the formula:

Where:

  • WB = water balance (mm)
  • R = rainfall depth (mm)
  • I = irrigation volumes (mm/area)
  • ET c = crop evapotranspiration (mm/area)

In this approach, the water balance does not include water stored in the soil profile. This is a simplification but it avoids the difficulty of trying to build a complex system reliant on accurate soil moisture accounting, that in many circumstances adds little benefit as the other agronomic or cultural preferences are unknown. In contrast to ENORASIS, a system operating in this mode does therefore not tell irrigators when and how much to irrigate, but provides an indication on how much water the crop has used since last irrigation. The decision when to irrigate is up to the grower based upon all the agronomic, economic and social/cultural considerations.

Create a virtual procedure named ETP_GRABOW observing Evapotranspiration

_images/etp_vp.png

Copy the FAO56 python function in the virtual procedure folder of ETP_GRABOW

If installed from source

sudo cp ~/Desktop/Tutorial/vp/FAO56.py /usr/local/istsos/services/demo/virtual/ETP_GRABOW

If installed from debian package

sudo cp ~/Desktop/Tutorial/vp/FAO56.py /usr/share/istsos/services/demo/virtual/ETP_GRABOW

Open the file to check the function ET0 which calculate evapotranspiration from a number of inputs:

'''
=======================================================================
Potential evaporation functions using Penman-Montheit with hourly data
=======================================================================
'''

def ET0(isodate,T,RH,u2,Rs,lat,lon,z,P=None,verbose=False):

    """
    Input:
        isodate: (str) iso datetime in UTC
        T: (float) hourly air temperature at 2m [Celsius]
        RH: (float) hourly relative air humidity [Pa]
        u2: (float) hourly wind speed at 2 m [m/s]
        Rs: (float) hourly incoming solar radiation [J/m2/hour]
        lat: (float) latitude of the measurement point [decimal degree]
        lon: (float) longitude of the measurement point [decimal degree]
        z: (float) altitude above sea level of the measurement point [m]
        P: (float) hourly air pressure [Pa] (Opzional)

    Output:
        - ET0: (float) hourly reference evapotranspiration [mm/h]

    Examples::
        >>> import FAO56
        >>> FAO56.ET0(isodate="2015-10-01T02:00Z",T=28,RH=90,u2=1.9,
                         Rs=0,lat=16.21,lon=-16.26,z=8)
        >>>
        >>> FAO56.ET0(isodate="2015-10-01T14:00Z",T=38,RH=52,u2=3.3,
                         Rs=2.450,lat=16.21,lon=-16.26,z=8)
        >>> 0.626874880652

    References:
        http://www.fao.org/docrep/X0490E/x0490e00.htm#Contents

    """

Code the evapotranspiration virtual procedure

# -*- coding: utf-8 -*-
# import
from istsoslib.responders.GOresponse import VirtualProcess

import FAO56

class istvp(VirtualProcess):

    procedures = {
        "GRABOW": [
            "urn:ogc:def:parameter:x-istsos:1.0:meteo:air:temperature",
            "urn:ogc:def:parameter:x-istsos:1.0:meteo:air:humidity:relative",
            "urn:ogc:def:parameter:x-istsos:1.0:meteo:air:wind:velocity",
            "urn:ogc:def:parameter:x-istsos:1.0:meteo:solar:radiation"
        ]
    }

    def execute(self):

        data = self.getData("GRABOW")
        data_out = []
        for rec in data:
            if self.filter.qualityIndex == True:
                # rec is a list:
                # [0]=time, [1]=T,[2]=Tqi, [3]=RH,[4]=RHqi,
                # [5]=u2,[6]=u2qi, [7]=Rs,[8]=Rsqi
                etp = FAO56.ET0(isodate = str(rec[0]),
                      T=float(rec[1]),
                      RH=float(rec[3]),
                      u2=float(rec[5]),
                      Rs=float(rec[7])*0.0036, # W/m2 to MJ/(m2*h)
                      lat=22.67,
                      lon=51.25,
                      z=177)
                data_out.append([rec[0], etp, min([rec[2],rec[4],rec[6],rec[8]])])
            else:
                # rec is a list: [0]=time,[1]=T,[2]=RH,[3]=u2,[4]=Rs
                etp = FAO56.ET0(isodate = str(rec[0]),
                      T=float(rec[1]),
                      RH=float(rec[2]),
                      u2=float(rec[3]),
                      Rs=float(rec[4])*0.0036,
                      lat=22.67,
                      lon=51.25,
                      z=177)
                data_out.append([rec[0], etp])
        return data_out

Test the virtual procedure with the “Data Viewer”