Previous Next Table of Contents

## 11. Extended Objects

GENESIS provides an extensive set of objects for building simulations. The extended object facilities may be used to create additional objects at the script level. New objects may also be added to GENESIS by compiling new object libraries written in C. (See Customizing GENESIS.)

A GENESIS object is characterized by its object name, fields, message definitions, actions and classes. An extended object is created by adding new fields, message definitions, actions or classes to an element of a preexisting GENESIS object. The new object defined through extending the element may be added as a named GENESIS object using the addobject command, or the element (and copies of it) may be used directly without using addobject.

Although extended objects may be used for any purpose they are usually used for one of three reasons: specialization, composition or creating completely new objects. Specialization customizes a given GENESIS object to describe a specific component in the model; the sodium channel of a squid giant axon for example. Composition takes a potentially complex combination of elements using them together to implement a new function and then presents the composition as a single object. A new object with a completely new function may be implemented by extending a neutral element.

An extended object is said to be derived from or based on the object from which it was extended. This derivation gives rise to an isa relationship between the extended object and its base object (or objects). The isa command and ISA wildcard path option allow testing and selection of elements based on generic object names. For example, if there were a number of specialized channels derived from the hh_channel object, the wildcard path

            /##[ISA=hh_channel]

would select all elements of all the specialized objects while

            /##[OBJECT=hh_channel]

would select only those element created directly from hh_channel.

If the class of the extended object needs to belong to an additional class besides that of the base object, another one may be added with the addclass command. This will be necessary when the simulation schedule for the new extended object needs to be different from that of the base object, as when the base object is a neutral object. (See Simulation Schedules.)

## 11.1 Extending Fields

New fields are added to an element using the addfield command. A new field may be used in every respect just as any field built in to the element. The `-indirect` option of addfield adds fields which refer to other fields of the element (field aliases) or to fields of other elements in the element hierarchy (useful for making fields of elements within a composition available). Fields added with addfield may later be removed with the deletefield command.

Fields may also be extended by changing the accessibility of the field with setfieldprot . A field may be one of readwrite, readonly or hidden. The accessibility of a field determines what a script executing outside the scope of the element may do with the field. A readwrite field is completely accessible, readonly fields may not be set and hidden fields may not be examined or set, though their presence in the element may be determined by the exists and showobject commands. A field's accessibility may never be made more permisive than the accessibility defined by the base object being extended (i.e. the computed field of an element which is readonly may not be made readwrite by extending the element), unless the `-debug` option of setfieldprotect is used.

Examples:

        create compartment mycompt
        addfield mycompt RM -description "Specific membrane resistance"
        setfieldprot mycompt -readonly Rm // Rm is now computed
        setfieldprot mycompt -readwrite Vm // Error Vm was readonly

        create xcell acell
        addfield acell fatmin -indirect . diamin \
            -description "XODUS 1 name for diamin"

## 11.2 Extending Actions

New actions may be added to an element by defining a script function implementing the action and using the addaction command to add this function as an action function for the element. Once added, all calls on the added action will result in a call to the script function. The first argument to the action function is always the name of the action followed by additional action-specific arguments.

An extended object may also override an action already defined for the base object. A few of the built in actions provide a chaining of calls to action functions in which all action functions defined for the object and its base objects are called in a specific order.

Current chained actions include CREATE, COPY, SET and DELETE. CREATE and COPY actions are called in base object to subobject order while SET and DELETE are called in subobject to base object order. The chaining of SET actions and subsequent direct setting of the element field are aborted if any SET action function returns a non-zero value. Manual chaining of other actions can be implemented using the call command's ```-parent`'' option within an action function. For example, to perform the PROCESS action of the base object, as well as some new ones which are defined for the extended object, add

            call . PROCESS -parent

to the beginning of the script function which defines the PROCESS action for the extended object.

When executing an action function, the working element is set to the element the action is called on and the effective accessibility of the element fields change. Within an action function any fields added with addfield are effectively readwrite and fields of the base object revert to the accessibility defined by the base object.

Example:

        // Here's a SET action function to calculate the actual membrane
        // resistance when the specific resistance, length or diameter
        // changes

        function __mycomptSET__(action, field, value)
            float   len, dia, RM

            // don't have to name the element since mycompt is cwe

            len = {getfield len}
            dia = {getfield dia}
            RM = {getfield RM}

            if (field == "RM")
                RM = value
            elif (field == "len")
                len = value
            elif (field == "dia")
                dia = value
            else
                return 0
            end

            // Rm is readwrite within the action function

            setfield Rm {RM * PI * dia * len}

            return 0
            end

        addaction mycompt SET __mycomptSET__

## 11.3 Extending Message Definitions

New messages types can be defined for an element with the addmsgdef command. A new message type can then be used by the addmsg command to add messages of the new type. Adding a new message definition typically means overriding the PROCESS action to obtain and use the new message data.

Here is a simple example which creates an extended object that uses its PROCESS action to receive an INPUT message and compute the sine of its input. As there is no similar pre-defined object available to use as the base object, it is based on the most primitive object, the neutral object. As neutral elements are not scheduled for processing, we will want to use the addclass command to assign the new object to a class which is scheduled for the PROCESS action.

        create neutral /sine

        // Create fields called input and output
        addfield /sine input
        addfield /sine output

        // Create a message definition for the INPUT message, define a PROCESS
        // action to process the INPUT message and make the sine object a device
        // class object
        addmsgdef /sine INPUT value
        addaction /sine PROCESS __sinePROCESS__
        addclass /sine device

        // PROCESS action script function
        function __sinePROCESS__(action)

            // check for an INPUT message: since its the only message type
            // sine will accept, just make sure at least one message is there
            // and use the first message's value

            if ({getmsg . -incoming -count} > 0)
                // Have an INPUT message: compute output and set input field
                // based on INPUT message value
                float input = {getmsg . -incoming -slot 0 0}
                setfield input {input} output {sin {input}}
            else
                // no INPUT message: compute output based on input field value
                setfield output {sin {getfield input}}
            end

            return 1
        end

        // create the sine object
        addobject sine /sine -author "J. R. Hacker" \
            -description "Computes sine of input"
        resched

Note the use of resched after the sine element is turned into the sine object. This command (or a reset) is needed so that the new object will be included in the current simulation schedule.

The situation is a little more complicated when we want to construct a composite element, and the message is intended to be forwarded to a child element. In a composition, child elements are not directly accessible to the user once the addobject command is used. In order to allow message data to be passed to a child element, a message added on the parent may be forwarded to the child from the parent's ADDMSGIN action using the addforwmsg command. In this case the message data is handled directly by the child element. The forwarded message must be deleted explicitly by calling the deleteforwmsg command in the parent's DELETEMSGIN action. Addforwmsg requires that the destination element accept messages with the same name and number of data slots as the message being forwarded.

Example:

        // This is part of a compositition which would normally include
        // an axis scaling menu and perhaps some additional buttons or
        // labels

        create xform /form
        create xgraph /form/graph

        addmsgdef /form PLOT data plotname color
        addaction /form ADDMSGIN __compgraphMSGIN__
        addaction /form DELETEMSGIN __compgraphMSGIN__

        // __compgraphMSGIN__ is used for both the ADDMSGIN and
        // DELETEMSGIN actions, the action argument is checked to
        // determine which action is being called

        function __compgraphMSGIN__(action, msgnum)
            str msgtype

            msgtype = {getmsg . -incoming -type {msgnum}}

            if (msgtype == "PLOT")
                if (action == "ADDMSGIN")
                    addforwmsg . {msgnum} graph
                else  // DELETEMSGIN
                    deleteforwmsg . {msgnum} graph
                end
            end
        end

## 11.4 Extending Classes

Additional class names can be associated with an element using the addclass command. Class names added with addclass can be used in wildcard path specifications for selecting groups of elements.

Example:

            addclass mycompt specificmemb

            setfield /##[CLASS=specificmemb] RM 1234

## 11.5 Using Extended Objects for Specialization

Specialization entails setting certain fields of an existing element to represent a more specialized component of a model. The fields which define the specialized element should not be changed once set or the element would no longer represent the specialized component. This can be enforced by setting the field accessibility to readonly or hidden.

In the following example we define a Hodgkin-Huxley squid giant axon potassium channel as a specialization of the hh_channel object. This is a scaled down version of Scripts/tutorials/hhchan_K.g which provides the same specialization, but also adds a gdens field to model channel density within a compartment and automates message setup between the channel and its compartment.

        // constants for form of rate constant equations

        int EXPONENTIAL = 1
        int SIGMOID     = 2
        int LINOID      = 3

        // H-H squid parameters

        float EREST_ACT = -0.070
        float EK        = -0.082

        // Now create the hh_channel and set fields for our channel.

        create hh_channel K_squid_hh
        setfield K_squid_hh \
                Ek              {EK} \                          // V
                Gbar            0.0  \
                Xpower          4.0 \
                Ypower          0.0 \
                X_alpha_FORM    {LINOID} \
                X_alpha_A       -10.0e3 \                       // 1/V-sec
                X_alpha_B       -10.0e-3 \                      // V
                X_alpha_V0      {10.0e-3+EREST_ACT} \           // V
                X_beta_FORM     {EXPONENTIAL} \
                X_beta_A        125.0 \                         // 1/sec
                X_beta_B        -80.0e-3 \                      // V
                X_beta_V0       {0.0+EREST_ACT}                 // V

        // Hide the hh_channel fields which define the rate equations.
        // We could have just made them readonly, but hiding them reduces
        // the number of fields the user must consider.

        setfieldprot K_squid_hh -hidden  Xpower Ypower X_alpha_FORM \
            X_alpha_A X_alpha_B X_alpha_V0 X_beta_FORM X_beta_A \
            X_beta_B X_beta_V0 Y_alpha_FORM Y_alpha_A Y_alpha_B \
            Y_alpha_V0 Y_beta_FORM Y_beta_A Y_beta_B Y_beta_V0

        // Now add this specialization as a new object.

        addobject K_squid_hh K_squid_hh -author "J. R. Hacker" \
            -description "Hodgkin-Huxley Active K Squid Channel - SI units"

## 11.6 Using Extended Objects for Composition

Composition uses a number of cooperating elements to create a reusable new component performing a complex task. The new component presents itself as a single element even though it is composed of a combination of other elements. In the following example a reusable graph scaling button is created from the basic built-in graphical elements. The component includes a popup dialog for setting graph axis ranges. The new object appears as an xbutton with a single additional field which is set to the name of the graph to control.

NOTE: XODUS callback scripts don't work particularly well for widgets inside a composite object, since you can't use the full widget path to refer to the widget. Here we use actions rather than script callbacks, since an action sets the affected widget as the current working element.

        // First we create the button which when clicked upon brings up
        // the scaling dialog.  All widgets must be created within a form

        create xform /form
        create xbutton /form/scale

        // Add a field which names the graph that scaling changes are to
        // apply to.  We set the default value of the graphpath to the
        // parent of the scale button.  This works nicely if we normally
        // create graphscales under the corresponding graph.

        addfield /form/scale graphpath -description "pathname to graph element"
        setfield /form/scale graphpath ..

        // Add actions for popup and hiding of graphscale dialog

        // __gs_B1DOWN: on a button press, copy the cuurent graph axis
        // settings from the graph named in the graphpath field to the
        // popup dialogs and show the dialog

        function __gs_B1DOWN(action)
            str graph = {getfield graphpath}
            if (!{isa xgraph {graph}})
                echo xgraphscale {el .} graphpath {graph} is not an xgraph
                return
            end

            // Initialize the value of each dialog from the corresponding
            // graph field.
            str field
            foreach field (xmin xmax ymin ymax)
                setfield popup/{field} value {getfield {graph} {field}}
            end
                xshow popup
        end

        // __gs_HIDE: hide the popup graph scale form

        function __gs_HIDE(action)
            xhide popup
        end

        // __gs_APPLY: apply a change to a graph scale dialog to the
        // appropriate graph field.

        function __gs_APPLY(action, field, value)
            str graph = {getfield graphpath}
            setfield {graph} {field} {value}
        end

        addaction /form/scale B1DOWN __gs_B1DOWN
        addaction /form/scale HIDE __gs_HIDE
        addaction /form/scale APPLY __gs_APPLY

        // Now create a new form under the scale button.  This form will
        // hold the popup dialog for setting the graph values.  In the
        // popup form we create the dialogs for setting the graph axis
        // ranges and a done button.

        create xform /form/scale/popup [300,0,400,300]
        create xdialog /form/scale/popup/xmin
            addaction ^ B1DOWN __gs_apply_one
        create xdialog /form/scale/popup/xmax
            addaction ^ B1DOWN __gs_apply_one
        create xdialog /form/scale/popup/ymin
            addaction ^ B1DOWN __gs_apply_one
        create xdialog /form/scale/popup/ymax
            addaction ^ B1DOWN __gs_apply_one
        create xbutton /form/scale/popup/done
            addaction ^ B1DOWN __gs_call_hide

        // Call the APPLY action on the graphscale to update
        // the graph field

        function __gs_apply_one(action)
            call ../.. APPLY {getfield name} {getfield value}
        end

        // Call the HIDE action on the graphscale to hide the
        // graph scale dialog

        function __gs_call_hide(action)
            call ../.. HIDE
        end

        // Now that we have all the pieces in place, add the new object.
        // We can also delete the form we used to create the new button.

        addobject xgraphscale /form/scale
        delete /form

Now adding a graph scaling button to a graph is as easy as creating an element. The following works even without setting the graphpath field since graphpath defaults to the parent of the xgraphscale.

        create xform /form
        create xgraph /form/graph
        create xgraphscale /form/graph/scale

## 11.7 Related Commands

The following routines are used for working with extended objects:

Routine | Description
addaction | Add an action to an element and a script function to
| implement the action
addclass | Add a class to the class list of an element
addfield | Add a field to an element
addforwmsg | Forward a copy of an existing message to another element
addmsgdef | Add a message definition to an element
addobject | Add the object described by a given element as a named
| GENESIS object
deleteaction | Delete an action previously added to an element
deleteclass | Delete a class previously added to an element
deletefield | Delete a field previously added to an element
deleteforwmsg | Delete a forwarded message to another element
deletemsgdef | Delete a message previously added to an element
setfieldprot | Set the accessibility for a field

Previous Next Table of Contents