Skip to content

Commit

Permalink
Use text, :ml:text and :samp:text consistently.
Browse files Browse the repository at this point in the history
Always use ``text``, unless:
- Matlab syntax highlighting is needed --> use :ml:`text`
- text contains value that should be highlighted as variables --> use :samp:`text with {var}` (braces can be escaped with *double* blackslash)
  • Loading branch information
rdzman committed Feb 19, 2024
1 parent 63908b7 commit 0382c45
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 81 deletions.
8 changes: 4 additions & 4 deletions docs/sphinx/source/dev-manual/architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ This architecture employs an explicit three-layer modeling structure designed to

|MATPOWER| Model Layers

The data model layer is further decoupled from any particular data format, such as the legacy |MATPOWER| case struct (:ml:`mpc`) and case file formats, by introducing a data conversion service (**data model converter**) to convert data between the data model and specific external data formats.
The data model layer is further decoupled from any particular data format, such as the legacy |MATPOWER| case struct (``mpc``) and case file formats, by introducing a data conversion service (**data model converter**) to convert data between the data model and specific external data formats.

Each modeling layer, plus the data conversion service, is organized around a collection of **element** objects, one for each **element type**, enclosed in a **container** object. An element type corresponds to a particular type of device (e.g. bus, generator, transmission line) or some other attribute or service (e.g. transmission interface, reserve requirement) in the system. This structure provides extraordinary flexibility by allowing the user to customize the environment by adding new, or modifying existing, element types independently from the rest.

Expand Down Expand Up @@ -71,7 +71,7 @@ The task then creates the data model converter object that corresponds to the da
Each of the four main objects created by the task consists of a container object holding a set of corresponding element objects. That is, the data model contains a set of data model elements, the network model, a set of network model elements, etc., one for each element type. Each element type is associated with a **name**, that is a valid struct field name used to identify the corresponding element in each container object. The list of element classes for a given container is defined by the container class, but can be modified after the container's construction and before calling its :meth:`build` method.

The build process of a given container object simply loops through its set of elements, building each one, possibly with access to the respective element of the other model layers. For example, when building the network model (:ml:`nm`), a network model element (:ml:`nme`) is constructed for each type of element, pulling its data from the corresponding data model element (:ml:`dme`). For example, the network model element for generators pulls its data from the data model element for generators.
The build process of a given container object simply loops through its set of elements, building each one, possibly with access to the respective element of the other model layers. For example, when building the network model (``nm``), a network model element (``nme``) is constructed for each type of element, pulling its data from the corresponding data model element (``dme``). For example, the network model element for generators pulls its data from the data model element for generators.

This process is described in more detail in Chapters :numref:`{number} <sec_data_model>`–:numref:`{number}<sec_math_model>`.

Expand Down Expand Up @@ -104,9 +104,9 @@ Two |MATPOWER| Frameworks

The first, which we call the **legacy** |*MATPOWER*| **framework**, wraps MP-Core objects inside the legacy user interface, with its inherent limitations, in order to provide backward compatibility for legacy user customization mechanisms. This allows MP-Core to be used internally to implement all of the legacy PF, CPF and OPF functionality and, even more importantly, to be validated by |MATPOWER|’s extensive legacy test suite.

The second approach, which we call the **flexible** |*MATPOWER*| **framework**, involves an object-oriented design with a new customization architecture, able to make the full scope of flexibility of MP-Core accessible to the end user. For example, this framework is required to take advantage of new modeling capabilities to add multiphase unbalanced and hybrid models. It provides its own version of the top-level user functions, namely :ml:`run_pf`, :ml:`run_cpf`, and :ml:`run_opf` *(note the underscores in the names)*.
The second approach, which we call the **flexible** |*MATPOWER*| **framework**, involves an object-oriented design with a new customization architecture, able to make the full scope of flexibility of MP-Core accessible to the end user. For example, this framework is required to take advantage of new modeling capabilities to add multiphase unbalanced and hybrid models. It provides its own version of the top-level user functions, namely :func:`run_pf`, :func:`run_cpf`, and :func:`run_opf` *(note the underscores in the names)*.

One of the primary differences between the two frameworks is that the legacy framework converts the |MATPOWER| case data to internal format, removing offline equipment and renumbering buses consecutively using the legacy :ml:`ext2int()` function, *before* creating the task object and running it. After solving, it converts the case back to the external format using :ml:`int2ext()` before returning the result. This conversion is required for the legacy user callback mechanisms, but is not necessary for MP-Core itself, so it is not included in the flexible framework.
One of the primary differences between the two frameworks is that the legacy framework converts the |MATPOWER| case data to internal format, removing offline equipment and renumbering buses consecutively using the legacy :func:`ext2int` function, *before* creating the task object and running it. After solving, it converts the case back to the external format using :func:`int2ext` before returning the result. This conversion is required for the legacy user callback mechanisms, but is not necessary for MP-Core itself, so it is not included in the flexible framework.


|MATPOWER| Customization
Expand Down
38 changes: 19 additions & 19 deletions docs/sphinx/source/dev-manual/customizing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ In order to customize the behavior it is important to understand how |MATPOWER|
Task Class
^^^^^^^^^^

First of all, at the top level, the **task class** is specified directly by the user through the function used to invoke the run. In fact, :func:`run_pf`, :func:`run_cpf`, and :func:`run_opf` are simple one-line wrappers around the :func:`run_mp` function. The only difference between the three is the value of the :ml:`task_class` argument, a handle to the corresponding task constructor, passed into :func:`run_mp`.
First of all, at the top level, the **task class** is specified directly by the user through the function used to invoke the run. In fact, :func:`run_pf`, :func:`run_cpf`, and :func:`run_opf` are simple one-line wrappers around the :func:`run_mp` function. The only difference between the three is the value of the ``task_class`` argument, a handle to the corresponding task constructor, passed into :func:`run_mp`.

This means that a new task class can be used simply by invoking :func:`run_mp`, either directly or via a new wrapper, with the task constructor as the :ml:`task_class` argument.
This means that a new task class can be used simply by invoking :func:`run_mp`, either directly or via a new wrapper, with the task constructor as the ``task_class`` argument.


Model and Data Converter Classes
Expand Down Expand Up @@ -84,22 +84,22 @@ This is done using **element class modifiers**, specified either by |MATPOWER| e
- Value
- Description
* - **add**
- :ml:`@new_class`
- Appends :ml:`@new_class` to the end of the list.
- ``@new_class``
- Appends ``@new_class`` to the end of the list.
* - **delete**
- :ml:`'old_class'`
- For each element :ml:`E` in the list, if :ml:`isa(E(), 'old_class')` is true, element :ml:`E` is deleted from the list.
- ``'old_class'``
- For each element ``E`` in the list, if :ml:`isa(E(), 'old_class')` is true, element ``E`` is deleted from the list.
* - **replace**
- :ml:`{@new_class, 'old_class'}`
- For each element :ml:`E` in the list, if :ml:`isa(E(), 'old_class')` is true, element :ml:`E` is replaced with :ml:`@new_class`.
- ``{@new_class, 'old_class'}``
- For each element ``E`` in the list, if :ml:`isa(E(), 'old_class')` is true, element ``E`` is replaced with ``@new_class``.

Typically, multiple element class modifiers can be provided in a cell array and they are processed sequentially to modify the existing list by the :meth:`modify_element_classes() <mp.element_container.modify_element_classes>` from :class:`mp.element_container`.


Customization via |MATPOWER| Options
------------------------------------

In addition to the |MATPOWER| options previously available that affect the formulation of the problem (e.g. polar vs. cartesian voltage representation, or current vs. power balance), there are several experimental options that can be used to directly modify the classes coming from the default class selection process outlined above. These options, summarized in :numref:`tab_custom_class_options`, are specified by assigning them directly to an existing |MATPOWER| options struct :ml:`mpopt` as optional fields in :ml:`mpopt.exp`. They must be assigned directly, since :func:`mpoption` does not recognize them.
In addition to the |MATPOWER| options previously available that affect the formulation of the problem (e.g. polar vs. cartesian voltage representation, or current vs. power balance), there are several experimental options that can be used to directly modify the classes coming from the default class selection process outlined above. These options, summarized in :numref:`tab_custom_class_options`, are specified by assigning them directly to an existing |MATPOWER| options struct ``mpopt`` as optional fields in ``mpopt.exp``. They must be assigned directly, since :func:`mpoption` does not recognize them.

.. _tab_custom_class_options:
.. list-table:: Class Customization Options
Expand All @@ -109,23 +109,23 @@ In addition to the |MATPOWER| options previously available that affect the formu

* - Option
- Description
* - :ml:`dm_converter_class`
* - ``dm_converter_class``
- function handle for data model converter constructor
* - :ml:`data_model_class`
* - ``data_model_class``
- function handle for data model constructor
* - :ml:`network_model_class`
* - ``network_model_class``
- function handle for network model constructor
* - :ml:`math_model_class`
* - ``math_model_class``
- function handle for math model constructor
* - :ml:`dmc_element_classes`
* - ``dmc_element_classes``
- element class modifier(s) [#]_ for data model converter elements
* - :ml:`dm_element_classes`
* - ``dm_element_classes``
- element class modifier(s) [1]_ for data model elements
* - :ml:`nm_element_classes`
* - ``nm_element_classes``
- element class modifier(s) [1]_ for network model elements
* - :ml:`mm_element_classes`
* - ``mm_element_classes``
- element class modifier(s) [1]_ for math model elements
* - :ml:`exclude_elements`
* - ``exclude_elements``
- cell array of names of elements to exclude from all four container objects, i.e. char arrays that match the :attr:`name` property of the element(s) to be excluded


Expand All @@ -136,7 +136,7 @@ In addition to the |MATPOWER| options previously available that affect the formu

The *flexible* |/MATPOWER/| *framework* summarized in :numref:`sec_two_frameworks` introduces a |*MATPOWER*| **extension** API as a way to bundle a set of class additions and modifications together into a single named package.

For example, the :class:`mp.xt_reserves` class and those it references, adds co-optimization of fixed zonal reserves to the standard OPF problem, as previously implemented by :ml:`toggle_reserves()` and :ml:`run_opf_w_res()` in |MATPOWER| 7.1 and earlier using its legacy OPF callback functions. To invoke an OPF with the :class:`mp.xt_reserves` extension, you simply pass the extension object as an optional argument into the :func:`run_opf` function.
For example, the :class:`mp.xt_reserves` class and those it references, adds co-optimization of fixed zonal reserves to the standard OPF problem, as previously implemented by :func:`toggle_reserves` and :func:`run_opf_w_res` in |MATPOWER| 7.1 and earlier using its legacy OPF callback functions. To invoke an OPF with the :class:`mp.xt_reserves` extension, you simply pass the extension object as an optional argument into the :func:`run_opf` function.

.. code-block::
Expand Down
57 changes: 19 additions & 38 deletions docs/sphinx/source/dev-manual/data-model-converter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ A data model converter object is primarily a container for data model converter

Data Model Converter Classes

By convention, data model converter variables are named :ml:`dmc` and data model converter class names begin with :ml:`mp.dm_converter`.
By convention, data model converter variables are named ``dmc`` and data model converter class names begin with ``mp.dm_converter``.

Building a Data Model Converter
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -67,7 +67,7 @@ Data Model Converter Elements

A data model converter element object implements the functionality needed to import and export a particular element type from and to a given data format. All data model converter element classes inherit from :class:`mp.dmc_element` and each element type typically implements its own subclass.

By convention, data model converter element variables are named :ml:`dmce` and data model converter element class names begin with :ml:`dmce`. :numref:`fig_dm_converter_classes` shows the inheritance relationships between a few example data model converter element classes. Here the PSS/E classes have not yet been implemented, but are shown here for illustration.
By convention, data model converter element variables are named ``dmce`` and data model converter element class names begin with ``mp.dmce``. :numref:`fig_dm_converter_classes` shows the inheritance relationships between a few example data model converter element classes. Here the PSS/E classes have not yet been implemented, but are shown here for illustration.

.. _fig_dm_converter_element_classes:
.. figure:: figures/dm-converter-element-classes.*
Expand All @@ -84,7 +84,7 @@ The default :meth:`import() <mp.dmc_element.import>` method for a data model con

The import specifications include things like where to find the data in the data source, the number of rows, number of columns, and possibly a row index vector for rows of interest, [#]_ and a map defining how to import each column of the main data table.

This map :samp:`vmap` is a struct returned by the :meth:`table_var_map() <mp.dmc_element.table_var_map>` method with fields matching the table column names for the corresponding data model element :samp:`dme`. For example, if :samp:`vn` contains a variable, that is column, name, then :samp:`vmap.(vn) = {<value>}` defines how that data table column will be imported or initialized, as summarized in :numref:`tab_var_map` for different types of values.
This map ``vmap`` is a struct returned by the :meth:`table_var_map() <mp.dmc_element.table_var_map>` method with fields matching the table column names for the corresponding data model element ``dme``. For example, if ``vn`` contains a variable, that is column, name, then :samp:`vmap.(vn) = {<value>}` defines how that data table column will be imported or initialized, as summarized in :numref:`tab_var_map` for different types of values.

.. _tab_var_map:
.. list-table:: Variable Map Values
Expand All @@ -94,44 +94,25 @@ This map :samp:`vmap` is a struct returned by the :meth:`table_var_map() <mp.dmc

* - :samp:`{<value>}`
- Description
* - :ml:`{'IDs'}`
* - ``{'IDs'}``
- Assign consecutive IDs starting at 1.
* - :ml:`{'col', c}` *or*
* - :samp:`\\{'col', {c}\\}` *or*

:ml:`{'col', c, sf}` *or*
:samp:`\\{'col', {c}, {sf}\\}` *or*

:ml:`{'col', c, sf_fcn}`
- Copy the data directly from column :ml:`c` of data source, optionally scaling it by a numerical scale factor :ml:`sf`, or by the value returned by the function handle :samp:`sf_fcn`, called as :samp:`sf_fcn(dmce, vn)`.
* - :ml:`{'cell', val}`
- Create a cell array with each element initialized with :ml:`val`.
* - :ml:`{'num', n}`
- Create a numeric vector with each element initialized with numeric scalar :ml:`n`.
* - :ml:`{'fcn', ifn}` *or*

:ml:`{'fcn', ifn, efn}`
- Assign the values returned by the import function handle in :samp:`ifn`, where the optional :samp:`efn` is the corresponding export function. The import and export functions are called as :samp:`ifn(dmce, d, spec, vn)` and :samp:`efn(dmce, dme, d, spec, vn, ridx)`, respectively, where :samp:`d` is the data source, :samp:`spec` is the import/export specification, and :samp:`ridx` is an optional vector of row indices.

The :meth:`table_var_map() <mp.dmc_element.table_var_map>` in :class:`mp.dmc_element` initializes each entry to :ml:`{'col', []}` by default, so subclasses only need to assign ``vmap.(vn){2}`` for columns that map directly from a column of the data source.

..
.. _tab_var_map2:
.. list-table:: Variable Map Values
:widths: 30 70
:header-rows: 1
:class: longtable
* - :samp:`{<value>}`
- Description
* - :ml:`{'IDs'}`
- consecutive IDs starting at 1
* - :ml:`{`:samp:`'col', {j}`:ml:`}`
- copy the data directly from column :samp:`{j}` of data source
* - :ml:`{`:samp:`'cell', {c}`:ml:`}`
- create a cell array with each element initialized with :samp:`{c}`
* - :ml:`{`:samp:`'num', {n}`:ml:`}`
- create a numeric vector with each element initialized with numeric scalar :samp:`{n}`
* - :ml:`{`:samp:`'fcn', {ifn}, {<efn>}`:ml:`}`
- assign the values returned by the import function handle in :samp:`{ifn}`, where the optional :samp:`{<efn>}` is the corresponding export function
:samp:`\\{'col', {c}, {sf_fcn}\\}`
- Copy the data directly from column :samp:`{c}` of data source, optionally scaling it by a numerical scale factor :samp:`{sf}`, or by the value returned by the function handle :samp:`{sf_fcn}`, called as :samp:`{sf_fcn(dmce, vn)}`.
* - :samp:`\\{'cell', {val}\\}`
- Create a cell array with each element initialized with :samp:`{val}`.
* - :samp:`\\{'num', {n}\\}`
- Create a numeric vector with each element initialized with numeric scalar :samp:`{n}`.
* - :samp:`\\{'fcn', {ifn}\\}` *or*

:samp:`\\{'fcn', {ifn}, {efn}\\}`
- Assign the values returned by the import function handle in :samp:`{ifn}`, where the optional :samp:`{efn}` is the corresponding export function. The import and export functions are called as :samp:`{ifn(dmce, d, spec, vn)}` and :samp:`{efn(dmce, dme, d, spec, vn, ridx)}`, respectively, where :samp:`{d}` is the data source, :samp:`{spec}` is the import/export specification, and :samp:`{ridx}` is an optional vector of row indices.

The :meth:`table_var_map() <mp.dmc_element.table_var_map>` in :class:`mp.dmc_element` initializes each entry to ``{'col', []}`` by default, so subclasses only need to assign ``vmap.(vn){2}`` for columns that map directly from a column of the data source.


Data Export Specifications
^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
Loading

0 comments on commit 0382c45

Please sign in to comment.