Smart Tools Appendix: Point-based Tools

     Point-based Arguments
     Reserved Methods
     Exercise Point-based-1 -- Creating a Tool
     Exercise Point-based-2 -- Modifying a Tool
     Exercise Point-based-3 -- Using VariableLists
     Working With  Point-based Weather
     Exercise Point-based SmartScript-1 -- Accessing Grids Directly
     Exercise Point-based SmartScript-2 -- Accessing Variable Grids Directly
     Exercise Point-based SmartScript-3 -- Making and Accessing Soundings
     Answers to Point-based Exercises


Appendix -- Point-based Tools

Prior to the introduction of Numeric Python, Smart Tools were Point-based i.e. the "execute" method of the tool was called for each point of the grid. Point-based tools are much slower than their Numeric counterparts. However, for backward compatibility, Point-based tools are still supported. In some cases, they are easier to write since if-then-else logic can be used for assigning values instead of "where" statements. This section discusses the differences between Point-based and Numeric Smart Tools and contains exercises to illustrate how to write Point-based tools.

Point-based Arguments

The arguments to point-based tools differ slightly from those to numeric tools. The differences are listed below:

Reserved Methods

Some methods have reserved names and meanings. To understand the framework, recall that a Point-based Smart Tool may operate over a time range which may include multiple grids. The mandatory "execute" method is called for each grid to be modified. Sometimes, you may wish to set up information before or after this point-by-point processing occurs. If so, you may use the following methods: Of course, these methods will be called only if you supply them in your tool. They are included as comments in the Smart Tool template that appears when you create a new tool and are documented there. The possible arguments to these methods will vary according to the logic of when they are called.

Exercise Point-based-1 -- Creating a new tool

Create a Smart Tool to yield a SnowAmt equal to the current QPF value multiplied by 10.
  1. Select GFE -> Define SmartTools. The Localization perspective will open with the SmartTools folder selected. Select MB3 and click New. The New Tool Dialog appears into which you will enter:
  1. Press OK and a Python Editor will appear with a template Python module for your Tool.
  • There are lines to specify that this is a "numeric" type tool and to import the Numeric library.
  • Another line specifies the WeatherElementEdited. This may be changed if you ever wish to modify the element edited by the tool.
  • Notice that the Python module has a class named "Tool" and several methods. The "execute" method is mandatory and the one with which we will be concerned. The "execute" method may have weather element arguments plus various special arguments which will be supplied by the system when it is called.
  • You will notice a funny argument, "self". This refers to this Tool class instance. You don't need to understand much about this now. All you need to do is make sure you leave it as the first argument to your "execute" method.
  • If desired, a VariableList can define run-time variables that will be solicited from the user when the Tool is executed. These variables will be passed to the method.
  • We'll explore the various arguments and VariableList later, but for this tool, you need only one argument (in addition to "self"): QPF.
  1. Remove the sample arguments from the "execute" definition, leave the "self" argument, and enter the argument, QPF in the parentheses. When the tool executes, this argument will contain a Numeric Array representing the Fcst QPF grid.
  2. Type in a description of your tool below the "execute" definition. This description will appear when you click Button-3 --> Info over your new tool.
  3. Insert a line to multiply the QPF values by 10:
  4.     SnowAmt = QPF * 10
    This line produces a Numeric Array named "SnowAmt" which has values 10 times the corresponding QPF values.
  5. Save the Python module. Select File-->Save.
  6. Execute the new tool to see that it works. If you encounter errors when executing your tool, a Dialog will appear to help you locate the problem. After successfully executing the tool, the QPF grid appears. Examine the data by sampling the QPF values and the SnowAmt values.  If your results seem confusing, check to see
  7. Close the Python Editor. Select File-->Close.

Exercise Point-based-2 -- Modifying a Tool

Modify your SnowAmt_LearningTool to base its new value based on temperature values. Use the following table:

T
Multiply QPF by
< 20
18
between 20 and 25
14
over 25
10
  1. Select Modify... on the Button-3 popup over the SnowAmt_LearningTool. A dialog appears and you can change the Weather Element on which it operates. You are not allowed to change the name of the tool. Do not change anything for this example.
  2. Select OK. This opens the Python Editor in which you can make changes. You will need the corresponding T grid, so add this as an argument to your method. Modify the Python code with if-elif-else statements to implement the Temperature-based table.
  3. Save the file. You can try your Tool without closing the editor or restarting the GFE. The changes are effective as soon as you Save. Verify that the tool worked by Sampling the SnowAmt and QPF grid values.

Exercise Point-based-3 -- Using VariableLists

Modify your SnowAmt_LearningTool to adjust the QPF only in areas above a user-given elevation. To perform this exercise, we will need to define a variable for the user to input at execution time. Remember to include "varDict" in your argument list to get the value for the user's variable. You will also need to access the variable, Topo.
Click here for Answer to Exercise Point-based-3.

Working with Point-based Weather

The Wx parameter is passed to Tools in a string format affectionately called the "ugly string." We will examine examples of ugly strings and how to manipulate them. The WxMethods utility provides some "prettier", more convenient methods for working with Weather strings. Using these methods will make your tool run slower than one that works directly with the "ugly" string. However, you may want to develop your tool using the WxMethods and revert to "ugly" string manipulation after your algorithm is established if you find the performance to be unacceptable. As processing speed improves, this may become less of an issue. There are many examples of Wx-based Smart Tools in the examples/smartTools directory.

"Ugly" Weather Strings

The "ugly string" format is:
    Coverage:Type:Intensity:Visibility:Attributes
Examples:
    Iso:RW:-:<NoVis>:
    Wide:T:+:1SM:DmgW,HvyRain
     
Weather strings can be concatenated with the ^.
    Iso:RW:--:<NoVis>:^Iso:T:--:<NoVis>:
To create a Wx string simply assign a variable to the string value. For example:
    Wx = "Iso:RW:--:<NoVis>:^Iso:T:--:<NoVis>:"
    Wx = "Wide:S:+:<NoVis>:"
     
To examine the Wx string, you may use Python "string" commands. Here's an example in which we are looking for a particular pattern:

        import string
        import SmartScript

        class Tool (SmartScript.SmartScript):
            def __init__(self, dbss):
                SmartScript.SmartScript.__init__(self, dbss)
            def execute(self, Wx, varDict):
                "Tool to calculate LAL from Wx"

                if string.find(Wx, "Iso:T")>=0:
                    LAL = 2
                elif string.find(Wx, "Sct:T")>=0:
                    LAL = 3
                elif string.find(Wx, "Num:T")>=0:
                    LAL = 4
                elif string.find(Wx, "Wide:T")>=0:
                    LAL = 5
                else
                    LAL = 1
                return LAL

To look for a particular Coverage or Type in a Wx string you could use the string command as follows:

                if string.find(Wx, ":R:")>=0:

Note that we need to include the colons so that the test distinguishes between "R" and "RW". A similar confusion can arise when looking for Coverages such as "Sct" and "WSct" or "Chc" and "SChc". If you are looking for a particular Coverage, you may want to use the simple (and fast) WxMethod, WxParts, to separate the string into a list of parts and then test for inclusion. At the beginning of your tool, be sure to "import" the WxMethods utility as shown:

        from WxMethods import *
        import SmartScript

        class Tool (SmartScript.SmartScript):
            def __init__(self, dbss):
                SmartScript.SmartScript.__init__(self, dbss)
            def execute(self, Wx, varDict):
                "Tool to calculate PoP from Wx"

                parts = WxParts(Wx)
                if "Def" in parts:
                    PoP = 100
                elif "Wide" in parts:
                    PoP = 90
                elif "Ocnl" in parts:
                    PoP = 80
                elif "Lkly" in parts:
                    PoP = 70
                elif "Chc" in parts:
                    PoP = 40
                elif "SChc" in parts:
                    PoP = 20
                elif "Iso" in parts:
                    PoP = 10
                return PoP

"Prettier" Weather Methods

Let's look at other WxMethods available and how they are used.
  1. In Localization Perspective, drill down to the SITE or USER level of the PoP_SmartTool and select Button-3-->Open over the PoP_SmartTool.
  2. Examine the code to see the WxContains method in use.
  3. In the EditAction Dialog, Select Windows --> Windows --> Utilities. Select Button-3-->Modify over WxMethods.
  4. Look at the documentation for the WxContains method.
  5. In Localization Perspective, drill down to the SITE or USER level of the Wx_SmartTool and select Button-3-->Open over the Wx_SmartTool.py and examine the code to see the WxString method in use.
  6. Look at the documentation for the WxString method in WxMethods.
  7. Finally, read the documentation for the WxModify.
  8. Close the Python Editor windows.

Exercise Point-based SmartScript-1 -- Accessing Grids Directly

In this exercise, we will access grid values directly from the Smart Tool instead of from the argument list.
  1. In Localization Perspective, select Utilities. Drill down to BASE level and select MB-3-->Open over SmartScript.
  2. Find the method, "getValue" and read the documentation.
  3. Return to the Smart Tools Window and create a new smart tool which edits QPF. Access both the current QPF value and the most recent D2D NAM12 tp (total precipitation) value directly using the "getValue" method. If the current QPF value is zero, assign the tp value to it. Otherwise, return it as is.
  4. Run and test your tool to make sure it works.
Click here for Answer to Exercise Point-based SmartScript-1.

Exercise Point-based SmartScript-2 -- Accessing Variable Grids Directly

Often, you will want to choose the model you want to work with at run-time. You can use a variable list to get the model and then access the grids directly.
  1. Modify your tool from Exercise SmartScript-1 to have a variable D2D model from which to get the "tp" value.
  2. Run and test your tool to make sure it works.
Click here for Answer to Exercise Point-based SmartScript-2.

Exercise Point-based SmartScript-3 -- Making and Accessing Soundings

The Smart Script class has the capability to create a sounding and get a value from the sounding based on a given elevation. In this exercise, we will create a sounding from model data and Topo information to determine the surface temperature.
  1. In the SmartScript class, find the method, "getSoundingValue". Read the documentation to learn how to call this method.
  2. Find the Unit Conversion methods section and examine the methods available.
  3. Create a new smart tool which edits T. Allow the user to set the D2D model using a VariableList. Get the value from a sounding made from the D2D model grids using the Topo information. You will have to convert Topo from feet to meters and temperature from K to F.
  4. Run and test your tool to make sure it works.
Click here for Answer to Exercise Point-based SmartScript-3.


Answers to Point-based Exercises

Answer to Exercise Point-based-1

import SmartScript

class Tool (SmartScript.SmartScript):
   def __init__(self, dbss):
      SmartScript.SmartScript.__init__(self, dbss)

    def execute(self, QPF):
        "Tool to return QPF multiplied by 10"

        # Determine new value
        SnowAmt = QPF * 10

        # Return the new value
        return SnowAmt

Answer to Exercise Point-based-2

import SmartScript

class Tool (SmartScript.SmartScript):
   def __init__(self, dbss):
      SmartScript.SmartScript.__init__(self, dbss)

    def execute(self, QPF, T):
        "Tool to calculate SnowAmt"

       if T < 20:
           SnowRatio = 18
       elif T < 25:
           SnowRatio = 14
       else:
            SnowRatio = 10
        # Determine new value
        SnowAmt = QPF * SnowRatio

        # Return the new value
        return SnowAmt

Answer to Exercise Point-based-3

import SmartScript

class Tool (SmartScript.SmartScript):
   def __init__(self, dbss):
      SmartScript.SmartScript.__init__(self, dbss)

    def execute(self, QPF, T, Topo, varDict):
        "Tool to calculate SnowAmt"

        # Set up Variables from the varDict
        elevation = varDict["Enter elevation"]

        if T < 20:
            SnowRatio = 18
        elif T < 25:
            SnowRatio = 14
        else:
            SnowRatio = 10

        # Determine new value
        if Topo > elevation:
            SnowAmt = SnowRatio * QPF
        else:
            SnowAmt = 0

        # Return the new value
           return SnowAmt

VariableList = [
        ("Enter elevation" , 5000, "numeric"),
       ]
 

Answer to Exercise Point-based SmartScript-1

import SmartScript

class Tool (SmartScript.SmartScript):
   def __init__(self, dbss):
      SmartScript.SmartScript.__init__(self, dbss)

    def execute(self,  x,  y, GridTimeRange):
           "This tool accesses QPF and tp  grids directly"

                #  Get QPF and tp values
                qpf = self.getValue("Fcst", "QPF", "SFC", x, y, GridTimeRange)
                tp = self.getValue("BOU_D2D_NAM12", "tp","SFC", x, y, GridTimeRange)

                if qpf == 0:
                    return tp
                else:
                    return qpf

Answer to Exercise Point-based SmartScript-2

import SmartScript

VariableList = [("Model:" , "", "D2D_model")]
class Tool (SmartScript.SmartScript):
   def __init__(self, dbss):
      SmartScript.SmartScript.__init__(self, dbss)

    def execute(self,  x,  y, GridTimeRange, varDict):
           "This tool accesses QPF and tp  grids directly"

                model = varDict["Model:"]

                #  Get QPF and tp values
                qpf = self.getValue("Fcst", "QPF", "SFC", x, y, GridTimeRange)
                tp = self.getValue(model, "tp","SFC", x, y, GridTimeRange)

                if qpf == 0:
                    return tp
                else:
                    return qpf
 

Answer to Exercise Point-based SmartScript-3

import SmartScript

VariableList = [("Model:" , "", "D2D_model")]

class Tool (SmartScript.SmartScript):
    def __init__(self, dbss):
        SmartScript.SmartScript.__init__(self, dbss)

    def execute(self, Topo, x, y, GridTimeRange, varDict):
        "This tool initializes T based on model temperature soundings"
        model = varDict["Model:"]

        # Make a sounding for T at this point
        # Height will increase in the sounding
        levels = ["MB1000","MB950","MB900","MB850","MB800",
                        "MB750","MB700","MB650","MB600"]
        topo_M = self.convertFtToM(Topo)
        T_K = self.getSoundingValue(model, "t", levels, x, y, GridTimeRange, topo_M)

        T_F = self.convertKtoF(T_K)

        # Return the new value
        return T_F