XML class structure

Data Representation and XML Dialect

Mien is built around an object-oriented model of data and protocol concepts. This data model is jointly represented as a hierarchy of classes (implemented in the Python language), and as a dialect of XML. There is an approximately one-to-one relationship between XML tags and Python classes. All classes are derived from a parent XML class that implements serialization to and de-serialization from XML. The dialect is flexible enough to express not only the declarative description of a model, but the procedural protocols for performing experiments or evaluations on the model. An advantage of this sort of representation is that any experiment or collection of experiments can be serialized to XML for persistent storage, or for communication across a network. The XML dialect used by MIEN is called the neural model and protocol markup language (nmpml). In addition to providing tag definitions and rules for tag relationships, the dialect has the overall requirement that every tag defines a Name attribute, and that Name is sibling-unique, meaning that no other element with the same parent and the same tag may also have the same name. This requirement is used to provide unique path (upath) identification, described below.

The mien XML specification is not as restrictive as a formal XML DTD. Instead, the mien runtime supports a set of XML dialects, which consist of collections of classes associated to particular tags. When those tags are encountered in an XML document, the associated class is initialized, using the data in the XML tag. This process performs a flavor of document validation. Each class can define a set of attributes, cdata, and child or parent tags that are required (or allowed) for correct function. If one of these classes is passed XML initialization information that doesn't match the classes contract, an exception is raised. The behavior of MIEN in response to these exceptions is configurable, and can range from refusing to open the document, to silently using the generic XML tag class to represent the tag. Similarly, if a tag is encountered that is not listed in the dialect, MIEN can fail, warn, or simply use the generic XML class. The default behavior is to use the generic class. This class supports many features, including xpath and unique path searches, attribute and cdata access, and editing in the GUIs. This behavior can be much more useful during prototyping than a simple fail-to-validate error. For example, the GUI editor can be used to fix a tag that was damaged by an experimental user function. A new tag can be invented that provides parameters to a user function, and this tag/function system can be deployed, tested, and even used in complete experiments before the user needs to add an extension to the XML dialect. Finally, data in generic XML, or in an unsupported dialect, can be reviewed, searched, edited, and often used in experiments without the need to explicitly add support for the new dialect to MIEN.

Addition of new tag/class pairs, or entire new dialect definitions, is only required when particular tags need to provide "special abilities" beyond the basic XML functions of storing, searching, and retrieving information. For example, a cell or cable section has concepts of physical length, parent and child sections, and perhaps location. All this can be expressed in purely declarative XML, and doesn't technically require a specialized tag (although it may be convenient to provide one for semantic clarity). It also has concepts like its branching depth, and its electrotonic length relative to a particular input waveform. These are not inherently declarative ideas. Implicitly, there is an algorithm used to calculate them when they are requested. In the former case, it is technically possible to calculate the value when the model is built, and store it in a pure XML attribute. In the later case, however, this strategy is somewhat ridiculous, since the number of possible input waveforms is very large. In an informatics context, it might be prudent to cache the declarative values associated to the most common input parameters to this type of quarry, but somewhere in the system there must be a representation of the algorithm used to calculate the function. This is where custom tag/class pairs become important. When a tag is associated to a sort of object that has particular algorithms naturally associated to it, then an associated class is provided that indicates how to compute these algorithms, in addition to inheriting the basic declarative XML object interface.

Figure: The Object inheritance hierarchy used by the Python implementation of the nmpml class structure

Special cases

The majority of classes behave as described. They initialize using the information contained in an XML tag, provide XML data retrieval methods, and optionally provide spatial algorithms appropriate to the sort of object their associated tag is used to represent. There are, however, some exceptional cases, where this basic behavior is not sufficient. These exceptions crop up because XML is not a perfect tool. It is a generally good framework, but there are several tasks common in modeling that it is bad at, and somewhat extensive infrastructure is needed to circumvent the limitations. Reasonable effort has been made to keep the number of these exceptions as small as possible. In the current MIEN implementation, there are four exceptional tags (or rather, three exceptional tags and one exceptional lack of tag). I don't foresee the need to add any others. The exceptions are listed individually below.

Class ElementReference

This tag is not particularly exceptional in implementation, but it is used to encapsulate horizontal reference, which is, in XML, an exceptional behavior. Horizontal reference means providing a pointer to some particular element of the document, regardless of its position relative to the referring object. In general, XML attributes can refer to their parent element and their children. With some recursion, the element can refer to its xpath, which is constructed using the names of all the containing tags. Most xml libraries implement searching for elements based on xpath. However, in the general XML specification, a particular xpath isn't guaranteed to refer to a particular unique tag, and so it can't be used for reliable horizontal reference.

Efficient modeling very often requires horizontal references. For example, suppose we would like to describe an experiment E. Perhaps we want to inject Stimulus S into Section 10 of Cell 4. Then we want to observe the results with Recording Device R. R itself is defined by recoding Variable V in Section 14 of Cell 4 with some particular sampling rate, gain, etc. It is impractical to define concepts like Cell 4 using hierarchal XML syntax. Cell 4 is not semantically a child element of E. We may also want to describe an experiment E2 that injects stimulus S2 into Section 1 of Cell 4. Indeed, we often want to define protocols that perform hundreds of experiments that perform permutations of stimulus, model, recording site, and other variables. We clearly don't want to define the models anew for each such experiment, so we need to implement some sort of pointer (aka symbolic link or horizontal reference) to refer to the components.

Unique Paths

The idea of a pointer is in fact a declarative concept, but generic XML happens not to be very good at it. Several solutions to this problem have been proposed.

One is to require xpaths to be unique. This is possible, but can be cumbersome. Clearly we can want a given Experiment line to contain many Recordings. Since the recordings would all have the same xpath, we would need to relabel them something like <Recording_1>, <Recording_2>. We would then need extra logic to determine that all these are semantically equivalent to <Recording> and should be implemented with the same class.

Another solution is to use the order in which the tags are listed in the file. The XML spec is not clear on how handlers should respond to this order. If it is maintained, then each Recording is uniquely identified by the index at which it occurs in the element list. The only flaw in this system is that some parsing libraries may not maintain the order. Because of this concern, MIEN does not use this strategy. Also, some ordered elements in nmpml require an "index" parameter to specify their intended order. The behavior of class AbstractModel, however, now does exploit element order. Using this property streamlines both the python code and the XML. In future releases, it is probable that MIEN will require the order of elements to be maintained during parse/write cycles, and will use this order for increasingly many functions. The Name attribute system is already in place, and works, however, and there is no plan to change the implementation of unique paths described below.

The MIEN implementation of unique identification is to require a sibling-unique Name attribute as described above, and to define a upath (unique path), analogaus to the xpath but guaranteed unique. The upath is constructed using the string Tag:Name in place of the string Tag in a xpath. For example, a Section element contained in a Cell might have an xpath /Cell/Section (the same as all the other sections in the cell), but a particular Section could have the upath /Cell:TenThree/Section:s0, and its neighbor might be /Cell:TenThree/Section:s1.

The ElementReference tag includes an attribute Target, which contains the upath of the referenced element. For example:

<ElementReference Name="cell" Target="/Cell:TenThree/"/>

This is a strait-forward XML tag with simple attributes. In principal, it would be possible to add this sort of Target attribute to any tag, but MIEN discourages this. The reason the the ElementReference is considered an exceptional tag, and is the sole implementation of horizontal reference has to do with the special behaviors and book-keeping required to make horizontal references work smoothly.

The first main issue is that references may need to be dereferenced by methods, so an ElementReference tag needs to be able to behave like its target when appropriate, and like a link when that is appropriate. It also needs to handle exceptions that occur if the target is missing.

The second, more severe, issue, is that MIEN allows many sorts of functions, including interactive GUI events and user written scripts, to rearrange the xml document structure. Moving or renaming a high level element changes the upath of it and all its children, and potentially breaks any horizontal reference in the document. By keeping all these references encapsulated in the special ElementReference tag, MIEN is able to keep them updated with reasonable efficiency. A MIEN document object keeps a cache of all the ElementReference objects, and can check this cache efficiently to determine which, if any, references are effected by move, delete, and rename methods. Consequently, if all the references are handled by this tag, and all the document editing is done via MIEN instance methods (or MIEN GUI or CLI actions, which use these methods), then the references remain up to date.

Class PointContainer

The PointContainer class does not correspond to an nmpml tag. Instead, it is used as the superclass for some tags, currently Section and Fiducial, that can contain 3D anatomical point data. Classes sub-classed from PointContainer have special handling during initialization if their tag contains child tags of type Point.

The tag Point is used in the XML files to represent anatomical point data. These tags can contain x, y, and z coordinates, and optional diameter and label information. Using an individual tag for each point in XML increases clarity and simplicity of the XML file. Points do not make sense when considered by themselves, however. Each point is contained in some other object, like a cable section, line contour, cloud or distribution of points, etc. The parent object encodes the meaning of the points, their units, and any special methods that can be done with the points. This is required because a point that is part of a fiducial line doesn't have the same set of useful methods as a point that is part of a collection of presynaptic varicosities, so it doesn't make sense to bind either set of these methods explicitly to tag Point.

Also, points are uniquely numerous. Large models may have a few thousand components, but a single highly detailed anatomical model may have a hundred thousand points. Because there is some overhead associated to generation of new objects, maintaining a one-to-one tag-to-object relationship for points is quite computationally expensive, as well as having limited utility for the reason presented above.

Consequently, MIEN uses an XML tag for a point, but doesn't use a corresponding class. Instead, points can only be defined as children of tags with associated classes that are some type of PointContainer. When these classes are initialized, they collect all the contained points into a single efficient array object. When the container is serialized, it uses its point array to write appropriate xml point tags.

PointContainer also implements methods for spatial scaling and alignment, which are useful for any sort of structure that uses 3D spatial points, but don't make sense for other structures.

Note that class Cell is not implemented as a PointContainer. Instead, Cells are made up of Sections, and the Sections contain points. This set of semantics is similar to the one used by the Neuron simulation environment. It is, however, easy enough to convert from this representation to others, used by, for example, GENESIS, NeuroML and Neurolucida. Class Cell contains methods for facilitating this conversion. Since, in some circumstances, it is appropriate to think of a cell as a point container, but in other situations it is a section container, the Cell class implements a number of methods which allow it to emulate a point container when appropriate. Cell also contains methods to assist the visualization and data recording classes, and a large amount of book-keeping logic to maintain appropriate relationships among the contained points, sections, channels and other components if the cell is scaled, edited, or otherwise transformed. All told, Cell is one of the most complex classes in MIEN (probably the second most complex, behind class Data). It is not, however, an exceptional class, in that its initialization, contents, and serialization follow the same model as the majority of other MIEN classes.

Class Data

The Data class is used to represent large collections of numbers. These can include images, time-series data of the sort generated by electrophysiology recordings, stimuli such as audio or video sequences, or the results of a model or analysis. All these objects have in common that they are fundamentally made of numbers, often they are not easy for a human observer to understand by direct inspection, and often they are extremely large.

The size of numerical data is the primary reason for defining an exceptional class. Although points are numerous, it is still quite possible to write 100000 XML point tags into a file and read them out quickly. It is not generally possible, to say nothing of quick or efficient, to write a 2GB physiology recording into an XML file (as, for example, BinHEX encoded cdata). Further, even once this huge file is read from somewhere, the class that handles the data will need substantially more performance optimization, memory management, and error handling than classes responsible for handling "mere" 300KB text files.

In addition to being hard to handle, numerical data is very common. A large number of tasks in a computational neuroscience lab operate exclusively on some form of numerical data. Common problems, including spike sorting, stimulus generation, predictive modeling, and physiological data analysis rely on high speed handling of large volumes of numerical data.

The Data class is designed to address these special requirements. In particular, it provides the following features:

The Data tag is capable of nesting other Data tags, and can therefore be used to represent an entire hierarchal framework of data, markup, and analysis results. Each separate, nested, collection of Data tags is referred to as a dataset. Datasets can be used as independent documents by various tools that handle only numerical data. A single dataset provides the core of the toolchains used by abstract models, and by data extensions like the spike sorting interface.

The Data class is exceptional because it does not always initialize from information contained directly in the XML Data tag it is created from. It is technically possible to store a whole data set within the xml tag. In this case the header information (for example the sampling rate and data type) are stored as attributes, and the numerical values are stored in cdata, as a BinHEX encoded string. This mode of storage may be appropriate for small data sets, but is not commonly used. More commonly, the Data tag contains some form of pointer to the location of the numerical data.

The data pointers can be uri or file name strings, or the names of several automatic retrieval methods. When a Data class is initialized, it looks for a helper class called a data server, and instantiates one if there is not already one associated to the document object. The data server handles the task of returning the actual numerical data when polled with the pointer string. It is possible to configure this behavior to uses lazy evaluation, so that if the data is on a network, or is very large, it will not be loaded unless a method actually needs to use it. By default, however, the data is loaded on class initialization.

The data server insulates the data class from the implementation of finding the data. In general, data stored in a network uri or a local file sholud look the same to the user, and to the Data tag.

The most common methods of storing data in MIEN currently use local files. MIEN's internal file format stares models in two parts. The first part is compressed xml, containing the model. The second part is a binary hash, containing binary objects associated with string keys. The keys are the upaths of Data tags in the xml. These tags specify their retrieval pointers as "auto", which is interpreted by the data server as get the data from the attached archive, using this tag's upath as the key. This method is efficient, and prevents inconvenient file accounting, where one file codes the uri of another file, and the other file therefore can't be moved without damaging the first.

Another common case is that the data are stored in a strictly numerical format like DataMAX or csv. This is common if the data were generated by a recording device, or by a separate mathematical model in C or Matlab. In this case, there is no associated XML. When MIEN opens a file of this type, it creates a single dataset, based on the numerical data in the file, and generates a (trivial) xml document object to contain this element.

Using local files is convenient for data exploration and algorithm development. The disadvantage of using local files appears when a relatively finalized model is evaluated under many conditions. This may use hundreds of stimulus inputs, or generate hundreds of recording outputs. If these are stored in a single file, it may be intractably large. If each is stored in a separate file, then keeping track of these files is time consuming and error prone. MIEN was designed to support requesting and submitting files from a database server. Currently, this feature is supported, but not tested. We would like to collaborate with users of an appropriate database in order to tune this functionality to work with the database, and test it in day-to-day use.

Class MienBlock

Abstract or mathematical models are inherently algorithms. These are procedural, or functional, rather than declarative concepts. As in the case of unique paths, there are several reasonable solutions. In some situations, MIEN can use more than one such solution, but the most practical and efficient method (arguably also the least elegant), requires an exceptional class to implement.

Perhaps the most elegant solution to the core problem of expressing an algorithm in a declarative context is to use a symbolic language, for example MathML, that can reduce the algorithm to semantically tagged declarative elements. It is the intention of MIEN to eventually support this sort of algorithm embedding, however, it is difficult, and not always practical in the context of rapid development. It is usually faster to code up an algorithm in perl, python, or matlab, than to figure out how to represent it analytically, and then translate the resulting symbolic expressions to MathML.

Indeed, computer languages themselves have solved the problem of expressing algorithms in declarative structures (source code files). Although it requires escaping some sensitive characters, it is not difficult to embed source code in an XML tag, with attributes indicating the required interpreter or compiler, and input/output data structures. Practically, however, this still poses some problems. First, it is more complex to xml-wrap your code than simply to write it, so the cycle of rapid prototyping is slowed down. More concerning, in order to use the stored algorithms, an interpreting computer will be asked to, for example, eval or exec an arbitrary string of code, which it may have received over the network in an XML file. Few servers would allow this, for reasons of security, and, even on a trusted subnetwork, of wishing to prevent poorly written code from crashing or locking up a server. MIEN occasionally uses "wrapped" code snippets despite this, but almost exclusively uses them to represent static data structures, not to execute arbitrary algorithms.

The MienBlock class addresses this issue by providing a pointer to a piece of pre-written code which is part of MIEN or of an extension block. Consequently, the tag is only meaningful if the "function" attribute it specifies is defined, and more importantly, is pointing to the correct function. Similar to the ElementReference tag, the MienBlock tag encapsulates this required correspondence between the contents of an XML tag and a source code tree, so that MIEN methods can handle it as effectively as possible.

Because Python provides extensive introspection capabilities, most of the behavior of the MienBlock tag can be implemented automatically. Interfaces for creating blocks will prompt for only the list of specified functions. Once a function is chosen, the block tag will be automatically outfitted with a set of child Parameter tags appropriate to the number and type of parameters needed by the referenced function. If the value of a block needs to be computed by a remote server, the client and server will verify that the block corresponds to the same function in both environments. Currently this is done by comparing the MD5 hash of the actual code snippet used to implement the block.

Although new code has to be added to MIEN to allow the use of new "function" attributes in MienBlock tags, the extension block framework makes this process very fast. In practice, a user simply needs to write out a short Python function inside an appropriate module, and a new MienBlock function, argument request interface, and MD5 hash are all generated automatically. The user doesn't need to interact with this complexity. In fact, she doesn't even need to restart MIEN. All the interfaces that use blocks provide a reload method, that applies any changes to the block architecture to all running MIEN components immediately.

Of corse, this system is not flawless. If a user writes some extension blocks, writes models that use them, saves the models to disk, and deletes the source code, emails the models to a colleague without the associated code, or requests distributed evaluation from a network server that hasn't adopted the new extensions, then the MienBlock tags can not be executed. Fortunately, however, they are extremely unlikely to execute, but implement the wrong algorithm.

Class structure

Currently active tags

These tags provide the data types used in the arguments to MienBlock functions.

Number implements all scalar numeric types, including int and float types by providing a precision argument, which may take any value, and emulates floats when set to float_epsilon and ints when set to 1.0.

String and Boolean are self explanatory.

PyCode contains strings that can eval to simple Python data types including tuples and dictionaries. It does not allow python statements (or anything that would need to be processed by exec rather than eval)

Parameters stores collections of basic parameters in a structure like a python dictionary. The arguments to any MienBlock function are always a Data instance and a single Parameters instance, although the Parameters instance appears to the function as though it is an arbitrary number of keyword arguments (the calling syntax looks like p=par.getValue('dict');f(d,**p) )

Described in detail above

This tag indicates that the system should use distributed computation when needed, and provides the port ID for the resulting server. Most of the actual mechanics of distribution are implemented in mien.tools.remoteeval and mien.nmpml.abstract.

These tags implement stimuli for compartmental cell models. IClamp injects current, and SynapticEvents activates synapses. Stimulus is a container class. It is somewhat useful for human readability, but should perhaps be deprecated, or turned into a MetaClass rather than a tag. Really, you never instantiate the idea of a stimulus, only an actual particular type of stimulus. Experiment uses the Stimulus container in order to identify the semantic type of the

contained elements, but it would be easy to implement this instead by storing a list of stimulus type tags, or by using Stimulus as a meta class and using Python's isinstance to identify stimulus subclasses, so the only reason to keep this is for human readability. Grouping of stimuli can be accomplished by using several stimulus type ElementReferences inside an Experiment.

This is the "business end" PointContainer that makes cell models work. Sections contain 3D anatomical data, Channels, Synapses, and RangeVars (and potentially Ions, but they aren't in use yet). They also provide connectivity information via their Parent attribute. Section methods provide tools for spatial measurement and editing. Their setName method is a great deal more complex than the basic method, since renaming a section might disrupt a whole chain of cell connectivity, and this method needs to prevent that.

These tags specify the location (for synapses) or density (for channels and RangeVars) of compartmental model elements. Currently they don't specify the mechanics of the associated model element, only its name. Since these things are simulated in Neuron, the models are specified in NMODL. Perhaps these should be considered exceptional classes similar to MienBlock. In the future, of course, they should actually nest MienBlocks that do specify the model mechanisms. In this case, these classes would not need to be exceptional.

These objects use their containing section to specify location, and therefore the location is always relative to the section. I believe this is correct, since it would make no sense at all to move a section and then have the synapses or channels that used to be on it hanging around in empty space.

Comments can be nested nearly anywhere. They simply contain strings, in cdata, that describe whatever seems appropriate to the user. Some methods, particularly the scaling and aligning methods, use comments to log their actions. More complex logging, of the sort done by the spike sorter, can't be handled by comments, and has to use a patch. Probably, an new Log class should be added to separate user/interactive comments from machine written (and therefore structured and machine readable) action logs. At that point the alignment methods should be changed to write Logs rather than Comments. That on the ToDo list.

This somewhat bloated class is concerned with organizing sections into branched trees. Actually, all the information describing the cell model is contained solely in the Sections, except, possibly, the values of the (initial) resting potential and the leak current reversal potential, which may optionally be specified as attributes of a Cell. The Cell class, however, implements many methods that operate on the data derived from the contained sections. There are three principal problems that Cell methods are designed to handle.

First, different modeling paradigms represent the conversion between 3D anatomical data and discrete isopotential compartments in different ways. The dominant choices are the "GENESIS way", where there is a one-to-one correspondence between point measurements and compartments, and the "Neuron way", where there is a concept of an anatomical section (an unbranched chunk of cable, of any length), and such a section may include some number of anatomical measurements, and may, independently, be represented as some other number of compartments. There could be considered to be a third way, used by MorphML and by reconstruction programs, where the value and connectivity of the anatomical measurements is the fundamental encoded value, and one doesn't really think about compartments and cable theory.

Because the fundamental point container in MIEN is a section, MIEN can be considered to follow the Neuron way. This makes sense in terms of computational efficiency, since MIEN currently evaluates compartmental models via Neuron. MIEN also needs to deal with anatomical reconstruction data from Neurolucida and from anatomical databases, however, and to read a wide range of anatomical file formats. It should also be as easy as possible to provide extension block support for other simulation engines, including GENESIS. Consequently, it is often required to convert between the section representation and the point set representation. Many methods of class Cell are devoted to doing this. Cell is not formally a PointContainer in MIEN, but it implements enough methods to act as a "pseudo" point container if needed. For example, a cell is able to return a (reasonably ordered) list of points, calculate the path lengths between two points, or scale, rotate, or translate itself. The user is insulated from the fact that the Cell is implemented as a group of Sections.

Second, Cells keep an up-to-date cache of certain information. Since sections specify a parent section, and only the (unique) root section has a parent value that evaluates as False, it is possible to construct the entire tree structure of a cell recursively from the section information. However, this process takes time. Many measurements and UI events rely on rapid traversal of a Cell's branching pattern. For example interactive selection tools in the CellViewer GUI, such as "Select Distal Points" rely on rapid retrieval of the branching structure. The Cell class consequently calculates and caches the branch pattern on initialization, and does the bookkeeping need to keep this cache up to date if sections are added, removed, or edited.

Third, many MIEN functions need to visualize cells, or represent them as various sorts of numerical arrays (for example to calculate their overlap with a spatial field). The process of drawing 30000 frusta is complex enough to occupy the classes that use these representations, so the task of constructing the representations is left to methods of class Cell.

Cell instances also act as containers for non-section elements associated to a given cell model, such as comments, parameters, and named regions.

This class acts as a container for references (or in some cases actual elements) that make up a modeling experiment. Usually, these experiments require the numerical evaluation of cable equations in a compartmental model. Although it is possible to construct a purely abstract experiment, such an experiment can be entirely performed by class AbstractModel, so no Experiment instance is needed.

An experiment consists of some number of stimuli, recordings, and cells. It is possible that the stimuli may also invoke abstract models. Often, the stimulus and cell contents are listed as references, and the recordings as actual elements, since other experiments may reuse some of the same stimuli and/or cells, but it is often desirable to separate the recordings so that they do not overwrite each other.

Aside from acting as a container, the main job of class Experiment is to generate instructions for the underlying simulator (currently Neuron). When the run method of an Experiment is called, it generates instructions suitable for implementing the experiment in the given simulator, calls the simulator in batch mode, loads and parses the output, and updates the associated Data structures. The Experiment may also handle remote or threaded evaluation.

In principal, additions to class Experiment would enable support for other evaluation backends, or even for control of real hardware experiments.

For consistency, it might be nice to allow abstract models, optimizers, and other non-compartmental components to be run from Experiment. This has absolutely no computational advantage (indeed no effect), but it would allow for a single unified set of UI behaviors for any situation in which you wanted to "run" something, rather than scattering the entry points over many tags.

These are simple point containers that specify fiducial contours, points, or other landmarks. They provide a spatial alignment interface and some plotting information, including the style (line, points, etc.) that should be used to visualize them. The points may optionally have attached labels.

Recordings contain a Data instance, some references (to points inside cells), and attributes specifying what variable to record and at what sampling rate. They are used when running Experiments to tell the underlying simulator what to record.

Recordings provide methods for accessing their data, and logic for auto-generating appropriate collections of records. For example, a recording reference can select a single relative location in a single section, but it can also point to an entire cell. In the latter case, the recording records data at every point in the cell (really every compartment, after translation into Neuron code and specification of the nseg parameter). This allows quick specification of the sort of recording required to generate, for example, a space/time animation of membrane voltage throughout a cell. The Recording instance also serves the resulting data to UI elements in an appropriate order, such that each point record corresponds to the correct spatial point, as these are ordered by class Cell.

As with experiments, they are currently not used to record values in abstract models. The component blocks of the

abstract model do this themselves by modifying their input Data instance, or by attaching sub-elements to it. Here also it might be nice to allow this behavior to be specified by a Recording tag for consistency, but it has no practical advantage. Also, although running an abstract model within an Experiment would be a trivial modification, specifying what to record in one using an external element is not easy. Often, the intermediate variables are generated by user written extension blocks that could contain almost any sort of code structure. Unless the code block records intermediate values into the dataset, these values probably don't exist yet when the block is called, and have already been garbage collected by the time the block exits. Specifying what and when to record is a hard problem.

This is a container for references to sections. They are used to store additional semantic information about sections, for example "these sections make up the axon". The CellViewer is able to display them, and to create and edit them via section selection tools. The ModelBuilder can use them in various model editing operations, for example, "set the density of Foo channel in Bar region to X", or "Randomly distribute 30 synapses, but only allow them within Foo region".

The implementation of NamedRegions is quite complete and satisfactory. Indeed the only issue with them is that their logic should perhaps be used on a higher level in the inheritance hierarchy to replace class Group as discussed here

This class is used to nest MienBlock objects. The result is a chain of procedures that operate on a Data element using a buch of Parameters, in order to do essentially any set of operations that can be coded in Python, and that has been accepted into the set of MIEN extension blocks.

Abstract model is sometimes used interchangeably with DSP (digital signal processing) in MIEN documentation, and the special purpose GUI for interacting with abstract models is called "DSP". This is a holdover from the origin of the class as a way to encode tasks like signal generation, digital filtering, de-trending, and similar signal processing jobs. Current abstract models can do more than this, including alter the morphology or physiology of cell models and talk to databases, but they are still sometimes called DSP chains for historical reasons.

Abstract models have many uses, including less-than-obvious uses like participating in model building by semi-stochastically distributing channels or synapses. They are often used to generate inputs or synaptic events, or to implement simplified mathematical models such as LNP cascade or ARX. They also serve as the core of the optimization tools. Every optimization problem in MIEN is represented as an abstract model that uses some set of parameters to calculate a scalar value, which is used as the cost or fitness function in optimization.

The code that is run inside an abstract model is associated to the contained blocks. The AbstractModel instance itself provides the interface to running the blocks in the appropriate order with the appropriate input Data instance. Also, the abstract instance handles threaded and/or remote computation if it is requested.

In addition to blocks, abstract models can contain other abstract models. A common use of this sort of nesting is to have one abstract model calculate a set of parameter permutations to feed to a nested abstract model. The nested model will then perform different operations for each of the inputs. These operations may be complex and time consuming. In this case, the nested model can be attached to a Distributer, and it will then evaluate its many input sets on many different networked computers, collecting the results and returning them to the containing model when the parallel computation is finished.

This isn't even really a class. It is, by convention, the top level tag in an nmpml document, but it is instantiated as a generic NMPMLObject, and it would still be if the value of the tag were different. The top level tag is essentially irrelevant. It needs to be instantiated as some sort of Nmpml object, and it can't be one of the strange ones, or one that won't init with generic child elements and no special attributes. Other than that, it can be anything. Recent documents use the tag "Nmpml" for clarity and ease of identifying the dialect type. Some older documents use XModeLObject. They end up working just the same. If someone happens to use "MyLeastFavoriteModel", that will still work, it will just look strange.

This class is a relatively simple container for a Data instance. It marks the contained data as being sampled from points in space. As a result, spatial methods such as alignment and 3D display, usually ignore raw numerical data, will correctly operate on the spatial data.

Defined tags that are not used

These are all current tags that we do use, but that aren't in any of the current models. They are used for parameter search and optimization. It would be good to make sure they are all working and build an example model that uses them.

I think we need this, though it is inelegant. It is very similar to Parameters, but designed for use by optimizers. Since none of the current models mount optimizers, it's not currently in use, but it works and can be used. The reason to have two tags that are so similar is that the requirements of interactive DSP tool chain design are very different from the requirements of numerical optimization. In the first case, the parameters can be anything - strings, arrays, code objects, etc. The range and precision of allowed values can be infinite. They are usually manipulated by a human, so it is nice to hash them by name. There are usually a reasonably small number of them. Retrieval speed isn't too important, as long as it is faster than screen refresh speed. In an optimizer, the values are all numerical, are tightly constrained, need to be quickly converted to and from structures like GA chromosomes (and therefore have to be stored in a consistently ordered array or list), may be unreasonably numerous, and an extra millisecond of access time is a really big deal. Consequently, I'm using two different classes.

Subclass of AbstractModel. The intent of this class is to provide support for complex (non-feed-forward) tool chains inside abstract models, for instance do-while loops, conditional execution, goto-step-N, etc. Since UIs and scripts might need to quickly recognize complex control structures, this tag was defined early on for "future proofing". So far, it has never been used, or even implemented. In r506 this subclass contains no code, so FlowControls are exactly identical to AbstractModels. We could remove them from the ontology, explain this sad story in a footnote, or ignore them. What do you think?

Trivial subclass of NmpmlObject. The intention of this class is to associate other elements to each other. For example, one could have a group of experiments. The concept of a Group doesn't really need to do much, other than act as a python iterator over its elements member (which is pretty much already implemented, since that member is a python list). This is a very old idea. I still think the idea of groups might be useful, but I don't think a group should nest a set of elements. Instead, it should contain a list of ElementReferences. The iterator behavior is then slightly less trivial, since one would like to iterate over the targets, not the references themselves. This is exactly how the currently used tag NamedRegion works. The elegant solution is to have NamedRegion be a kind (subclass) of Group. At that point I could move 90% of the functionality from NamedRegion up to Group, and have a useful and not-trivial group class without writing any new code. This is an obvious thing to do, it just hasn't been done yet.

This class is part of the fall-through system for determining membrane and reversal potentials. Channel objects need to know a reversal potential for their set of allowed ions in order to compute currents. Channels can specify the relevant RP using their Reversal attribute. If this is specified, then the get_rp method returns it. This is fast, easy, and is how all the existing models work. It isn't flexible, though. What if the concentrations of ions are not uniform in time? What if they are specified in terms of absolute spatial coordinates, rather than as a single constant, or as a function of cell or channel identity? Most models don't deal with this complexity, but on the theory that they should be able to, MIEN included an Ion class. If the reversal isn't specified as an attribute of a channel, it could, in principal, fall back to looking up the relevant Ion tags. These Ions could contain SpatialFields specifying concentration, and could compute RP. This is hugely complicated, and not yet implemented.

Back in the days when we did spatial alignment, I thought it would be slick if every spatial model carried around its own coordinate system with it. This way, when two models are put together, they could automatically co-register. These classes implement that behavior. As far as I know they work. In practice, defining a reference in the first place is exactly as hard as co-registering models, so what we ended up doing was just moving all the models to the same coordinate system, and not bothering with reference points. Within a single project, this idea works fine. Across projects, ReferencePoint wouldn't work anyway, and might be misleading. It's simply not semantically legitimate to "co-register" a mouse amacrine cell and a cricket cercal IN, and the machine shouldn't be given an excuse to try.

The only place these would really be useful is in something like a brain anatomy atlas. Here, two cells might be 100000 micros apart, but you might still care about their relative locations. It wouldn't be practical to put all the models on the same origin, since it would result in lots of models with stupidly large x,y,z coordinate values, which would be annoying to rotate, and which human users couldn't quickly recognize characteristic dimensions. Having ReferencePoints would allow these very distant structures to be efficiently rendered individually, while still allowing a larger scale image of their relative positions to be quickly computed.

Since we aren't doing anything like this at the moment, I'm contemplating deprecating these classes.

 

Last edit: 05/29/09

Index