Plugin How-To – Adding Solver Attributes

Manipulating the Pointwise Grid Model from within a CAE plugin can be a little confusing. This leads to customers contacting our Support Team with a plugin development question that starts with the phrase “How do I…?” As always, our Support Team is happy to help you with anything Pointwise, including your plugin development questions!

Many of these plugin development inquiries can be simply answered by pointing the customer to the appropriate pages in the Pointwise CAE Plugin SDK documentation. However, the solutions to some inquiries are more complex and require a more in-depth explanation with code examples.

I plan to periodically post these interesting inquiries along with their answers. These posts should provide valuable insight into writing a plugin and using the Pointwise Grid Model.

This installment of Plugin How-To deals with Adding solver attributes to your plugin.

Q: How do I add a solver attribute to my plugin?

The Pointwise CAE plugin SDK provides an interface that allows a plugin to publish one or more plugin-specific attributes. During export, the plugin can query the grid model to obtain the value assigned to each attribute. An attribute’s value can be set by the user from within the Pointwise application through the CAE/Set Solver Attributes… menu or through a Glyph script using the pw::Application setCAESolverAttribute action. In addition, Glyph scripts can discover all published attributes using the pw::Application getCAESolverAttributeNames and pw::Application getCAESolverAttributeDefinition actions.

From a plugin’s perspective, a solver attribute represents a special, global value that is only meaningful to the plugin itself or the solver to which the plugin is exporting. A plugin can write an attribute’s value to the exported data (e.g. FreeStreamVelocity), or use it to control the plugin’s export behavior (e.g. CellExport in the OpenFOAM plugin).

Pointwise and Glyph use attribute information to control runtime behavior. As a result, a plugin must publish all of its attributes when it is first loaded into memory. A plugin using the C API publishes its attribute definitions from within the runtimeCreate() function using the caeuPublishValueDefinition() function. A plugin using the C++ API publishes its attribute definitions from within its override of the CaePlugin::create() virtual class method using one of the CaePlugin::publishTypeValueDef() base class methods.

Components of an Attribute

An attribute is defined by several components:

  • Name
  • Type
  • Default value
  • Description
  • Access Control
  • Range (optional)

An attribute’s name can be any alpha numeric text string that is unique within a given plugin. The name is displayed by Pointwise and is used in Glyph scripts. Although not required, to be consistent with other CAE attributes, it is suggested that attribute names should use upper camel case. That is, a name should start with a capital letter, not use spaces, and each sub-word within the name should be capitalized. For instance, MachNumber, Pressure and FreeStreamVelocity are upper camel case names.

An attribute’s type is enforced by Pointwise and Glyph at runtime. An attribute can only accept values that are compatible with its type. The following attribute types are supported:

  • UInt (Unsigned Integer)
  • Int (Signed Integer)
  • Real
  • Bool (Boolean)
  • String
  • Enum

The default value is used to initialize an attribute when a solver is first activated. This occurs when the user changes solvers using the CAE/Select Solver… menu. This also happens in Glyph scripts using pw::Application setCAESolver. When a Pointwise file is loaded, the solver saved with the file is activated with attributes set to their respective defaults. However, any changes to these attributes that were saved in the file are then applied.

The attribute description is used for documentation and user interface purposes. A description can be any text value.

The access control settings control if an attribute is readable (R), writable (W) or both (RW). Unless changed, attributes published by plugins default to readable and writable (RW).

An attribute’s range controls which values are valid. Setting a range is optional. If a range is not specified, all valid values are allowed. As shown in the image, the description and range information is displayed in Pointwise as an input field tooltip.

Example of a numeric range tooltip in Pointwise

Example of a numeric range tooltip in Pointwise

How a range is specified depends on the attribute’s type. The range settings for each attribute type are detailed below.

The range for integer or real types is specified as a min and max value (inclusive). If appropriate, a typical range can also be specified where, min <= minTypical < maxTypical <= max. Only the min and max range is enforced at runtime. Values entered by the user that are outside the min/max range are rejected. In Glyph, setting a value outside the min/max range is an error.

The range for boolean types defines the tokens that represent boolean true and false values. By default the tokens true and yes map to boolean true values. The tokens false and no map to boolean false values.

The range for string types is a pattern and an optional min and max length. The pattern can be a regular expression or a glob expression. The pattern is used to validate string values. A regex pattern is delimited with slash characters (/regexPattern/). A glob pattern is delimited with colon characters (:globPattern:).

The range for enum types specifies a list of valid token strings and (optionally) each token’s associated integer value. Enumerated types are used for attributes that have a finite set of allowed values. For example, a Units attribute may only allow the values (tokens) Inches, Feet, Meters, and Millimeters. If a token is not given an explicit integer value, it assumes the value of the previous token in the list plus one. If there is no previous token, its value is zero. Each token must be unique within an enum definition. However, the associated integer values may be repeated.

Example Code

The image below shows the Set Solver Attributes… dialog box generated in Pointwise by the following code samples.

The CAE/Set Solver Attributes Dialog Box

The CAE/Set Solver Attributes Dialog Box

// Publish the solver attributes
PWP_BOOL runtimeCreate(CAEP_RTITEM * /*pRti*/)
{
    return caeuPublishValueDefinition("Iterations",
            PWP_VALTYPE_UINT, "5", "RW", "Number of iterations",
            "0 2000") &&
        caeuPublishValueDefinition("Magnitude", PWP_VALTYPE_INT,
            "-5", "RW", "Signed int magnitude", "-100 100") &&
        caeuPublishValueDefinition("Mach", PWP_VALTYPE_REAL,
            "0.3", "RW", "Incoming flow velocity",
            "0 100 0.0 50.0") &&
        caeuPublishValueDefinition("Temp", PWP_VALTYPE_REAL,
            "77.5", "RW", "Ambient temperature",
            "-1000 5000 -100 3000") &&
        caeuPublishValueDefinition("TempUnits",
            PWP_VALTYPE_ENUM, "Fahrenheit", "RW",
            "Temperature units", "Celsius|Fahrenheit|Kelvin") &&
        caeuPublishValueDefinition("Units", PWP_VALTYPE_ENUM,
            "Inches", "RW", "Grid dimensional units",
            "Feet=1|Inches=2|Meters=10|Millimeters=11") &&
        caeuPublishValueDefinition("Description",
            PWP_VALTYPE_STRING, "", "RW", "Grid description",
            "") &&
        caeuPublishValueDefinition("Linear", PWP_VALTYPE_BOOL,
            "Reject", "RW", "Grid is linear", "Reject|Accept");
}

// Query the attribute values at export
PWP_BOOL runtimeWrite(CAEP_RTITEM *pRti,
    PWGM_HGRIDMODEL model,
    const CAEP_WRITEINFO *pWriteInfo)
{
    PWP_BOOL ret = PWP_FALSE;
    PWP_UINT32 iters;
    PWP_INT32 mag;
    PWP_REAL mach;
    PWP_REAL temp;
    const char* tempUnits; // will get enum token value
    PWP_UINT32 units;      // will get enum id value
    const char* desc;
    PWP_BOOL linear;
    if (PwModGetAttributeUINT32(model, "Iterations", &iters) &&
        PwModGetAttributeINT32(model, "Magnitude", &mag) &&
        PwModGetAttributeREAL(model, "Mach", &mach) &&
        PwModGetAttributeREAL(model, "Temp", &temp) &&
        PwModGetAttributeEnum(model, "TempUnits", &tempUnits) &&
        PwModGetAttributeUINT32(model, "Units", &units) &&
        PwModGetAttributeString(model, "Description", &desc) &&
        PwModGetAttributeBOOL(model, "Linear", &linear)) {
        // export data...
    }
    return ret;
}
// Publish the solver attributes
bool CaeUnsCPP::create(CAEP_RTITEM &rti)
{
    return publishUIntValueDef(rti, "Iterations", 5,
            "Number of iterations", 0, 2000) &&
        publishIntValueDef(rti, "Magnitude", -5,
            "Signed int magnitude", -100, 100) &&
        publishRealValueDef(rti, "Mach", 0.3,
            "Incoming flow velocity", 0, 100, 0, 50) &&
        publishRealValueDef(rti, "Temp", 77.5,
            "Ambient temperature", -1000, 5000, -100, 3000) &&
        publishEnumValueDef(rti, "TempUnits", "Fahrenheit",
            "Temperature units", "Celsius|Fahrenheit|Kelvin") &&
        publishEnumValueDef(rti, "Units", "Inches",
            "Grid dimensional units",
            "Feet=1|Inches=2|Meters=10|Millimeters=11") &&
        publishStringValueDef(rti, "Description", "",
            "Grid description", "") &&
        publishBoolValueDef(rti, "Linear", "Reject",
            "Grid is linear", "Reject|Accept");
}

// Query the attribute values at export
bool CaeUnsCPP::beginExport()
{
    PWP_UINT32 iterations;
    PWP_INT32 magnitude;
    PWP_REAL mach;
    PWP_REAL temp;
    const char* tempUnits; // will get enum token string value
    PWP_UINT32 units;      // will get enum token id value
    const char* description;
    bool linear;
    return model_.getAttribute("Iterations", iterations, 3) &&
        model_.getAttribute("Magnitude", magnitude, 1) &&
        model_.getAttribute("Mach", mach, 1.0) &&
        model_.getAttribute("Temp", temp, 34.7) &&
        model_.getAttributeEnum("TempUnits", tempUnits,
            "Kelvin") &&
        model_.getAttribute("Units", units, 11) &&
        model_.getAttribute("Description", description, "") &&
        model_.getAttribute("Linear", linear, false);
}
package require PWI_Glyph 2.17

pw::Application setCAESolver {CaeUnsC} 3

# Set some attribute values
pw::Application setCAESolverAttribute Iterations 10
pw::Application setCAESolverAttribute Linear Accept
pw::Application setCAESolverAttribute Mach 1.5
pw::Application setCAESolverAttribute Magnitude 6
pw::Application setCAESolverAttribute Temp 112.5
pw::Application setCAESolverAttribute TempUnits Kelvin
pw::Application setCAESolverAttribute Units Meters

# Enumerate all published attributes
set attrNames [pw::Application getCAESolverAttributeNames]
foreach name $attrNames {
    set attrDef [pw::Application getCAESolverAttributeDefinition $name]
    puts "Attribute definition: \{$attrDef\}"
    lassign $attrDef aGroup aName aType aAccess aDesc aDefValue aRange
    puts "...Group  : $aGroup"
    puts "...Name   : $aName"
    puts "...Type   : $aType"
    puts "...Access : $aAccess"
    puts "...Desc   : $aDesc"
    puts "...Default: $aDefValue"
    puts "...Range  : $aRange"
    puts "...Value  : [pw::Application getCAESolverAttribute $name]"
}

# OUTPUT:
# Attribute definition: {CAE Iterations UInt RW {Number of iterations} 5 {0 2000}}
# ...Group  : CAE
# ...Name   : Iterations
# ...Type   : UInt
# ...Access : RW
# ...Desc   : Number of iterations
# ...Default: 5
# ...Range  : 0 2000
# ...Value  : 10
# Attribute definition: {CAE Magnitude Int RW {Signed int magnitude} -5 {-100 100}}
# ...Group  : CAE
# ...Name   : Magnitude
# ...Type   : Int
# ...Access : RW
# ...Desc   : Signed int magnitude
# ...Default: -5
# ...Range  : -100 100
# ...Value  : 6
# Attribute definition: {CAE Mach Real RW {Incoming flow velocity} 0.3 {0 100 0.0 50.0}}
# ...Group  : CAE
# ...Name   : Mach
# ...Type   : Real
# ...Access : RW
# ...Desc   : Incoming flow velocity
# ...Default: 0.3
# ...Range  : 0 100 0.0 50.0
# ...Value  : 1.5
# Attribute definition: {CAE Temp Real RW {Ambient temperature} 77.5 {-1000 5000 -100 3000}}
# ...Group  : CAE
# ...Name   : Temp
# ...Type   : Real
# ...Access : RW
# ...Desc   : Ambient temperature
# ...Default: 77.5
# ...Range  : -1000 5000 -100 3000
# ...Value  : 112.5
# Attribute definition: {CAE TempUnits Enum RW {Temperature units} Fahrenheit Celsius|Fahrenheit|Kelvin}
# ...Group  : CAE
# ...Name   : TempUnits
# ...Type   : Enum
# ...Access : RW
# ...Desc   : Temperature units
# ...Default: Fahrenheit
# ...Range  : Celsius|Fahrenheit|Kelvin
# ...Value  : Kelvin
# Attribute definition: {CAE Units Enum RW {Grid dimensional units} Inches Feet=1|Inches=2|Meters=10|Millimeters=11}
# ...Group  : CAE
# ...Name   : Units
# ...Type   : Enum
# ...Access : RW
# ...Desc   : Grid dimensional units
# ...Default: Inches
# ...Range  : Feet=1|Inches=2|Meters=10|Millimeters=11
# ...Value  : Meters
# Attribute definition: {CAE Description String RW {Grid description} {} {}}
# ...Group  : CAE
# ...Name   : Description
# ...Type   : String
# ...Access : RW
# ...Desc   : Grid description
# ...Default:
# ...Range  :
# ...Value  :
# Attribute definition: {CAE Linear Bool RW {Grid is linear} Reject Reject|Accept}
# ...Group  : CAE
# ...Name   : Linear
# ...Type   : Bool
# ...Access : RW
# ...Desc   : Grid is linear
# ...Default: Reject
# ...Range  : Reject|Accept
# ...Value  : 1

Your Suggestions Welcome

I hope this information is useful. If you have any other ideas for a future Plugin How-To post, please leave a comment below or contact our support staff.

Happy coding!

Find out more about the Pointwise Plugin SDK by clicking on the link below.

Learn more about the Pointwise CAE Plugin SDK

About David Garlisch

Illini by birth, Texan by choice.
This entry was posted in Applications, Software and tagged , , , , , , , , , , , . Bookmark the permalink.

2 Responses to Plugin How-To – Adding Solver Attributes

  1. jdrch says:

    Great post! That said, the unit Celsius is misspelled as “Celcius” in all 3 API examples.

  2. John Chawner says:

    Thanks, Judah. All fixed.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s