Xmile Translation

PySD allows parsing a Xmile file and translates the result to an AbstractModel object that can be used to build the model.

Warning

Currently no Xmile users are working on the development of PySD. This is causing a gap between the Xmile and Vensim developments. Stella users are encouraged to take part in the development of PySD by including new test models and adding support for new functions and features.

The translation workflow

The following translation workflow allows splitting the Xmile file while parsing each part of it to build an AbstractModel type object. The workflow may be summarized as follows:

  1. Xmile file: Parses the file with etree library and creates a section for the model.

  2. Xmile section: Full set of variables and definitions that can be integrated. Allows splitting the model elements.

  3. Xmile element: A variable definition. It includes units and comments. Allows parsing the expressions it contains and saving them inside AbstractComponents, that are part of an AbstractElement.

Once the model is parsed and split following the previous steps. The AbstractModel can be returned.

Xmile file

The XmileFile class allows reading the original Xmile model file and parsing it into Section elements. The final result can be exported to an AbstractModel class in order to build a model in another programming language.

class pysd.translators.xmile.xmile_file.XmileFile(xmile_path: str | Path)[source]

The XmileFile class allows parsing an Xmile file. When the object is created, the model file is automatically opened and parsed with lxml.etree.

Parameters:

xmile_path (str or pathlib.Path) – Path to the Xmile model.

property verbose

Print model information to standard output.

parse(parse_all: bool = True) None[source]

Create a XmileSection object from the model content and parse it. As macros are currently not supported, all models will have a single section. This function should split the macros in independent sections in the future.

Parameters:

parse_all (bool (optional)) – If True, the created XmileSection objects will be automatically parsed. Otherwise, these objects will only be added to self.sections but not parsed. Default is True.

get_abstract_model() AbstractModel[source]

Get Abstract Model used for building. This, method should be called after parsing the model (self.parse). This automatically calls the get_abstract_section method from the model sections.

Returns:

AbstractModel – Abstract Model object that can be used for building the model in another language.

Return type:

AbstractModel

Xmile section

The Section class allows parsing a model section into Elements. The final result can be exported to an AbstractSection class in order to build a model in other language. A section could be either the main model (without the macros), or a macro definition (not supported yet for Xmile).

class pysd.translators.xmile.xmile_section.Section(name: str, path: Path, section_type: str, params: List[str], returns: List[str], content_root: _Element, namespace: str, split: bool, views_dict: dict | None)[source]

Section object allows parsing the elements of that section.

Parameters:
  • name (str) – Section name. ‘__main__’ for the main section or the macro name.

  • path (pathlib.Path) – Section path. It should be the model name for main section and the clean macro name for a macro.

  • section_type (str ('main' or 'macro')) – The section type.

  • params (list) – List of params that takes the section. In the case of main section it will be an empty list.

  • returns (list) – List of variables that returns the section. In the case of main section it will be an empty list.

  • content_root (etree._Element) – Section parsed tree content.

  • namespace (str) – The namespace of the section given after parsing its content with etree.

  • split (bool) – If split is True the created section will split the variables depending on the views_dict.

  • views_dict (dict) – The dictionary of the views. Giving the variables classified at any level in order to split them by files.

property verbose

Print section information to standard output.

parse(parse_all: bool = True) None[source]

Parse section object. The subscripts of the section will be added to self subscripts. The variables defined as Flows, Auxiliary, Gf, and Stock will be converted in XmileElements. The control variables, if the section is __main__, will be converted to a ControlElement.

Parameters:

parse_all (bool (optional)) – If True then the created VensimElement objects will be automatically parsed. Otherwise, this objects will only be added to self.elements but not parser. Default is True.

get_abstract_section() AbstractSection[source]

Get Abstract Section used for building. This, method should be called after parsing the section (self.parse). This method is automatically called by Model’s get_abstract_model and automatically generates the AbstractSubscript ranges and merge the components in elements calling also the get_abstract_components method from each model component.

Returns:

AbstractSection – Abstract Section object that can be used for building the model in another language.

Return type:

AbstractSection

Xmile element

The Element class child classes alow parsing the expressions of a given model element. There are four tipes of elements:

  • Auxiliars (Aux class): Auxiliary elements, defined with <aux>.

  • Flows (Flow class): Flow elements, defined with <flow>.

  • Gfs (Gf class): Lookup elements, defined with <gf>.

  • Stocks (Stock class): Data component, defined with <stock>

Moreover, a fith type element is defined ControlElement, which allows parsing the values of the model control variables (time step, initialtime, final time).

The final result from a parsed element can be exported to an AbstractElement object in order to build a model in other language.

class pysd.translators.xmile.xmile_element.Element(node: _Element, ns: dict, subscripts)[source]

Element class. This class provides the shared methods for its children: Aux, Flow, Gf, Stock, and ControlElement.

Parameters:
  • node (etree._Element) – The element node content.

  • ns (dict) – The namespace of the section.

  • subscripts (dict) – The subscript dictionary of the section, necessary to parse some subscripted elements.

property verbose

Print element information to standard output.

parse(behaviors: dict) None[source]

Parse all the components of an element

Parameters:

behaviors (dict) – Dictionary with keys ‘non_negative_flow’ and ‘non_negative_stock’ and boolean values defining the global behavior for the stocks and flows.

Return type:

None

class pysd.translators.xmile.xmile_element.Aux(node, ns, subscripts)[source]

Auxiliary variable defined by <aux> in Xmile.

Parameters:
  • node (etree._Element) – The element node content.

  • ns (dict) – The namespace of the section.

  • subscripts (dict) – The subscript dictionary of the section, necessary to parse some subscripted elements.

get_abstract_element() AbstractElement[source]

Get Abstract Element used for building. This method is automatically called by Sections’s get_abstract_section.

Returns:

AbstractElement – Abstract Element object that can be used for building the model in another language. It contains a list of AbstractComponents with the Abstract Syntax Tree of each of the expressions.

Return type:

AbstractElement

class pysd.translators.xmile.xmile_element.Flow(node, ns, subscripts)[source]

Flow defined by <flow> in Xmile.

Parameters:
  • node (etree._Element) – The element node content.

  • ns (dict) – The namespace of the section.

  • subscripts (dict) – The subscript dictionary of the section, necessary to parse some subscripted elements.

class pysd.translators.xmile.xmile_element.Gf(node, ns, subscripts)[source]

Gf variable (lookup) defined by <gf> in Xmile.

Parameters:
  • node (etree._Element) – The element node content.

  • ns (dict) – The namespace of the section.

  • subscripts (dict) – The subscript dictionary of the section, necessary to parse some subscripted elements.

get_limits() Tuple[None | str, None | str][source]

Get the limits of the Gf element

get_abstract_element() AbstractElement[source]

Get Abstract Element used for building. This method is automatically called by Sections’s get_abstract_section.

Returns:

AbstractElement – Abstract Element object that can be used for building the model in another language. It contains a list of AbstractComponents with the Abstract Syntax Tree of each of the expressions.

Return type:

AbstractElement

class pysd.translators.xmile.xmile_element.Stock(node, ns, subscripts)[source]

Stock variable defined by <stock> in Xmile.

Parameters:
  • node (etree._Element) – The element node content.

  • ns (dict) – The namespace of the section.

  • subscripts (dict) – The subscript dictionary of the section, necessary to parse some subscripted elements.

get_abstract_element() AbstractElement[source]

Get Abstract Element used for building. This method is automatically called by Sections’s get_abstract_section.

Returns:

AbstractElement – Abstract Element object that can be used for building the model in another language. It contains a list of AbstractComponents with the Abstract Syntax Tree of each of the expressions.

Return type:

AbstractElement

class pysd.translators.xmile.xmile_element.SubscriptRange(name: str, definition: List[str], mapping: List[str] = [])[source]

Subscript range definition.

property verbose

Print subscript range information to standard output.

get_abstract_subscript_range() AbstractSubscriptRange[source]

Get Abstract Subscript Range used for building. This method is automatically called by Sections’s get_abstract_section.

Returns:

AbstractSubscriptRange – Abstract Subscript Range object that can be used for building the model in another language.

Return type:

AbstractSubscriptRange

Supported Functions and Features

Ongoing development of the translator will support the full set of Xmile functionality. The current release supports the following operators, functions and features:

Warning

Not all the supported functions and features are properly tested. Any new test model to cover the missing functions test will be welcome.

Operators

All the basic operators are supported, this includes the ones shown in the tables below.:

Supported unary operators

Xmile

Xmile example

Abstract Syntax

-

-A

LogicStructure([‘negative’], (A,))

+

+A

A

not

not A

LogicStructure([‘:NOT:’], (A,))

Supported binary operators

Xmile

Xmile example

Abstract Syntax

^

A ^ B

ArithmeticStructure([‘^’], (A, B))

*

A * B

ArithmeticStructure([‘*’], (A, B))

/

A / B

ArithmeticStructure([‘/’], (A, B))

mod

A mod B

CallStructure(‘modulo’, (A, B))

+

A + B

ArithmeticStructure([‘+’], (A, B))

-

A - B

ArithmeticStructure([‘-‘], (A, B))

=

A = B

LogicStructure([‘=’], (A, B))

<>

A <> B

LogicStructure([‘<>’], (A, B))

<

A < B

LogicStructure([‘<’], (A, B))

>

A > B

LogicStructure([‘>’], (A, B))

>=

A >= B

LogicStructure([‘>=’], (A, B))

<=

A <= B

LogicStructure([‘<=’], (A, B))

and

A and B

LogicStructure([‘:AND:’], (A, B))

or

A or B

LogicStructure([‘:OR:’], (A, B))

Functions

Not all the Xmile functions are included yet. The list of supported functions is shown below:

Supported basic functions

Xmile

Xmile example

Abstract Syntax

Xmile comments

abs

abs(A)

CallStructure(‘abs’, (A,))

min

min(A, B)

CallStructure(‘min’, (A, B))

max

max(A, B)

CallStructure(‘max’, (A, B))

min

min(A)

CallStructure(‘vmin_xmile’, (A,))

max

max(A)

CallStructure(‘vmax_xmile’, (A,))

sqrt

sqrt(A)

CallStructure(‘sqrt’, (A,))

exp

exp(A)

CallStructure(‘exp’, (A,))

ln

ln(A)

CallStructure(‘ln’, (A,))

pi

pi()

CallStructure(‘pi’, (,))

sin

sin(A)

CallStructure(‘sin’, (A,))

cos

cos(A)

CallStructure(‘cos’, (A,))

tan

tan(A)

CallStructure(‘tan’, (A,))

arcsin

arcsin(A)

CallStructure(‘arcsin’, (A,))

arccos

arccos(A)

CallStructure(‘arccos’, (A,))

arctan

arctan(A)

CallStructure(‘arctan’, (A,))

int

int(A)

CallStructure(‘int’, (A,))

if_then_else

if_then_else(A, B, C)

CallStructure(‘if_then_else’, (A, B))

IF condition THEN value_true ELSE value_false

IF A THEN B ELSE C

CallStructure(‘if_then_else’, (A, B))

safediv

safediv(A, B, X)

CallStructure(‘xidz’, (A, B, X))

safediv

safediv(A, B)

CallStructure(‘zidz’, (A, B))

pulse

pulse(magnitude, start)

CallStructure(‘Xpulse’, (start, magnitude))

Not tested for Xmile!

pulse

pulse(magnitude, start, interval)

CallStructure(‘Xpulse_train’, (start, interval, magnitude))

Not tested for Xmile!

ramp

ramp(slope, start_time, end_time)

CallStructure(‘ramp’, (slope, start_time, end_time))

Not tested for Xmile!

ramp

ramp(slope, start_time)

CallStructure(‘ramp’, (slope, start_time))

Not tested for Xmile!

step

step(height, step_time)

CallStructure(‘step’, (height, step_time))

Not tested for Xmile!

init

init(value)

InitialStructure(value)

Supported delay functions

Xmile

Xmile example

Abstract Syntax

Xmile comments

delay1

delay1(input, delay_time, initial_value)

DelayStructure(input, delay_time, initial_value, 1)

Not tested for Xmile!

delay1

delay1(input, delay_time)

DelayStructure(input, delay_time, input, 1)

Not tested for Xmile!

delay3

delay3(input, delay_time, initial_value)

DelayStructure(input, delay_time, initial_value, 3)

Not tested for Xmile!

delay3

delay3(input, delay_time)

DelayStructure(input, delay_time, input, 3)

Not tested for Xmile!

delayn

delayn(input, delay_time, n, initial_value)

DelayNStructure(input, delay_time, initial_value, n)

Not tested for Xmile!

delayn

delayn(input, delay_time, n)

DelayNStructure(input, delay_time, input, n)

Not tested for Xmile!

delay

delay(input, delay_time, initial_value)

DelayFixed(input, delay_time, initial_value)

delay

delay(input, delay_time)

DelayFixed(input, delay_time, input)

smth1

smth1(input, smth_time, initial_value)

SmoothStructure(input, smth_time, initial_value, 1)

Not tested for Xmile!

smth1

smth1(input, smth_time)

SmoothStructure(input, smth_time, input, 1)

Not tested for Xmile!

smth3

smth3(input, smth_time, initial_value)

SmoothStructure(input, smth_time, initial_value, 3)

Not tested for Xmile!

smth3

smth3(input, smth_time)

SmoothStructure(input, smth_time, input, 3)

Not tested for Xmile!

smthn

smthn(input, smth_time, n, initial_value)

SmoothNStructure(input, smth_time, initial_value, n)

Not tested for Xmile!

smthn

smthn(input, smth_time, n)

SmoothNStructure(input, smth_time, input, n)

Not tested for Xmile!

forcst

forcst(input, average_time, horizon, initial_trend)

ForecastStructure(input, average_time, horizon, initial_trend)

Not tested for Xmile!

forcst

forcst(input, average_time, horizon)

ForecastStructure(input, average_time, horizon, 0)

Not tested for Xmile!

trend

trend(input, average_time, initial_trend)

TrendStructure(input, average_time, initial_trend)

Not tested for Xmile!

trend

trend(input, average_time)

TrendStructure(input, average_time, 0)

Not tested for Xmile!

Stocks

Stocks are supported with any number of inflows and outflows. Stocks are translated to the AST as IntegStructure(flows, initial_value, non_negative). Non-negative flag is parsed for both stocks and flows, this can be set element by element or using the behavior section. Flows with non-negative flags are read as flows with a maximum condition, while for stocks this information is saved in the pysd.translators.structures.abstract_expressions.IntegStructure object.

Subscripts

Several subscript related features are supported. These include:

  • Basic subscript operations with different ranges.

  • Subscript ranges and subranges definitions.

Graphical functions

Xmile graphical functions (gf), also known as lookups, are supported. They can be hardcoded or inlined.

Warning

Interpolation methods ‘extrapolate’ and ‘discrete’ are implemented but not tested. Full integration models with these methods are required.

Supported in Vensim but not in Xmile

Macro

Currently Xmile macros are not supported. In Vensim, macros are classified as an independent section of the model. If they are properly parsed in the XmileFile, adding support for Xmile should be easy.

Planed New Functions and Features

Nothing yet.