  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'' (Customizing.txt).)

  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'' (Schedules.txt).)

  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
  ______________________________________________________________________
