Reference Guide: Structures
This document (along with "structures2definitions" and "structures3instances") describes the core data structures used to implement in Mimi 1.0.
Prior versions of Mimi supported only "flat" models, i.e., with one level of components. The current version supports mulitple layers of components, with some components being "final" or leaf components, and others being "composite" components which themselves contain other leaf or composite components. This approach allows for a cleaner organization of complex models, and allows the construction of building blocks that can be re-used in multiple models.
To the degree possible, composite components are designed to operate the same as leaf components, though there are necessarily differences:
Leaf components are defined using the macro
@defcomp
, while composites are defined using@defcomposite
. Each macro supports syntax and semantics specific to the type of component. See below for more details on these macros.Leaf composites support user-defined
run_timestep()
functions, whereas composites have a built-inrun_timestep()
function that iterates over its subcomponents and calls theirrun_timestep()
function. Theinit()
function is handled analogously.
Classes.jl
Most of the core data structures are defined using the Classes.jl
package, which was developed for Mimi, but separated out as a generally useful julia package. The main features of Classes
are:
Classes can subclass other classes, thereby inheriting the same list of fields as a starting point, which can then be extended with further fields.
A type hierarchy is defined automatically that allows classes and subclasses to be referenced with a single type. In short, if you define a class
Foo
, an abstract type calledAbstractFoo
is defined, along with the concrete classFoo
. If you subclassFoo
(say with the classBar
), thenAbstractBar
will be a subtype ofAbstractFoo
, allowing methods to be defined that operate on both the superclass and subclass. See the Classes.jl documentation for further details.
For example, in Mimi, ModelDef
is a subclass of CompositeComponentDef
, which in turn is a subclass of ComponentDef
. Thus, methods can be written with arguments typed x::ComponentDef
to operate on leaf components only, or x::AbstractCompositeComponentDef
to operate on composites and ModelDef
, or as x::AbstractComponentDef
to operate on all three concrete types.
Core types
Several core types are defined in types/core.jl
, including the two primary abstract types, MimiStruct
and MimiClass
.
All structs and classes in Mimi are derived from these abstract types, which allows us to identify Mimi-defined items when writing show()
methods. Important structs and classes include:
ComponentId
To identify components,
@defcomp
creates a variable with the name of the component whose value is an instance of this type. The definition is:julia struct ComponentId <: MimiStruct module_obj::Union{Nothing, Module} comp_name::Symbol end
ComponentPath
A
ComponentPath
identifies the path from one or more composites to any component, using anNTuple
of symbols. Since component names are unique at the composite level, the sequence of names through a component hierarchy uniquely identifies a component in that hierarchy.julia struct ComponentPath <: MimiStruct names::NTuple{N, Symbol} where N end