Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • kit/virtmat-tools/vre-language
1 result
Show changes
Commits on Source (849)
Showing with 1030 additions and 136 deletions
[report]
precision = 2
omit =
*/language/kernel/*
__pycache__ __pycache__
*.dot *.dot
*.pdf *.pdf
*.log
*.traj
launcher_* launcher_*
*.egg-info *.egg-info
FW.json FW.json
_build
...@@ -2,43 +2,55 @@ default: ...@@ -2,43 +2,55 @@ default:
image: registry.gitlab.com#ikondov/vre-ci-docker/ci-docker image: registry.gitlab.com#ikondov/vre-ci-docker/ci-docker
before_script: before_script:
- pip install --upgrade pip - pip install --upgrade pip
- pip install -r requirements.txt - pip install -r requirements_test.txt
stages: stages:
- Static Analysis - Static Analysis
- test - Regression Tests
- Build Docs
pylint: pylint:
stage: Static Analysis stage: Static Analysis
tags: tags:
- docker - docker
script: script:
- mkdir ./pylint_log - pip install .
- pylint --output-format=text **/*.py | tee ./pylint_log/pylint.log || pylint-exit $? - mkdir ./pylint_log
- PYLINT_SCORE=$(sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' ./pylint_log/pylint.log) - pylint --output-format=text **/*.py | tee ./pylint_log/pylint.log || pylint-exit $?
- anybadge --label=Pylint --file=pylint_log/pylint.svg --value=$PYLINT_SCORE 2=red 4=orange 8=yellow 10=green - PYLINT_SCORE=$(sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' ./pylint_log/pylint.log)
- echo "Pylint score is $PYLINT_SCORE" - anybadge --label=Pylint --file=pylint_log/pylint.svg --value=$PYLINT_SCORE 2=red 4=orange 8=yellow 10=green
- echo "Pylint score is $PYLINT_SCORE"
artifacts: artifacts:
paths: paths:
- ./pylint_log/ - ./pylint_log/
flake8: flake8:
stage: Static Analysis stage: Static Analysis
tags: tags:
- docker - docker
script: script:
- flake8 . - flake8 .
tests: pytest:
stage: test stage: Regression Tests
tags: tags:
- docker - docker
before_script: before_script:
- mongod --fork --syslog - mongod --fork --syslog
script: script:
- echo "Y" | lpad reset - pip install --upgrade pip
- pip install . - pip install .[test]
- pytest - lpad reset --password="$(date +%Y-%m-%d)" # echo "fireworks" | lpad reset
- pytest
coverage: '/TOTAL.*\s+(\d+\.\d+)%$/'
after_script: after_script:
- mongod --shutdown - mongod --shutdown
docs:
stage: Build Docs
tags:
- docker
script:
- pip install -r docs/requirements.txt
- sphinx-build -M html docs docs/_build
# Read the Docs configuration file for Sphinx projects
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: '3.11'
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
# fail_on_warning: true
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: docs/requirements.txt
This diff is collapsed.
...@@ -15,11 +15,11 @@ Apart from the domain-specific notations, our VRE language has to satisfy furthe ...@@ -15,11 +15,11 @@ Apart from the domain-specific notations, our VRE language has to satisfy furthe
1. Support a full life cycle of modeling, simulation and data analysis. A model should be accessible and extensible dynamically, at any time. This is what we call *persistence* and *dynamics* of the model. To satisfy this requirement, we connect the interpreter to a workflow management system equipped with a database. 1. Support a full life cycle of modeling, simulation and data analysis. A model should be accessible and extensible dynamically, at any time. This is what we call *persistence* and *dynamics* of the model. To satisfy this requirement, we connect the interpreter to a workflow management system equipped with a database.
2. Use [Jupyter](https://jupyter.org/) as a front-end system. This poses a challenge for models with persistence and on the other hand a new Jupyter kernel with the VRE language interpreter has to be developed. 2. Use [Jupyter](https://jupyter.org/) as a front-end system. This poses a challenge for models with persistence and on the other hand a new Jupyter kernel with the VRE language interpreter has to be developed.
3. Make the complex workflow management systems and HPC systems / batch systems *transparent*. This is not obvious and also not trivial to implement. Particularly, notations in the program code about the granularity (which statements belong to the same workflow node) and the computing resources needed (such as computing time, number of CPUs, memory, disk space, ...) are necessary for computational performance or other practical reasons but difficult to hide completely from the language. 3. Make the complex workflow management systems and HPC systems / batch systems *transparent*. This is not obvious and also not trivial to implement. Particularly, notations in the program code about the granularity (which statements belong to the same workflow node) and the computing resources needed (such as computing time, number of CPUs, memory, disk space, ...) are necessary for computational performance or other practical reasons but difficult to hide completely from the language.
4. Use Python as a language for the interpreter. This is due to the fact that a plenty of libraries (APIs) for Python in the domain already exist: the [Atomic Simulation Environment (ASE)](https://wiki.fysik.dtu.dk/ase/), [Python Materials Genomics (Pymatgen)](https://pymatgen.org/) and [PyIron](https://pyiron.org/), to name only a few. These libraries cover the most relevant aspects of their domains but still are used in the general-purpose language Python. The use of Python implies in turn that a workflow management system and system of physical units providing Python APIs are required. 4. Use Python as a language for the interpreter. This is due to the fact that a plenty of libraries (APIs) for Python in the domain already exist: the [Atomic Simulation Environment (ASE)](https://wiki.fysik.dtu.dk/ase/), [Python Materials Genomics (Pymatgen)](https://pymatgen.org/) and [PyIron](https://pyiron.org/), to name only a few. These libraries cover the most relevant aspects of their domains but still are used in the general-purpose language Python. The use of Python implies in turn that a workflow management system and system of physical units providing Python APIs are required.
# Development status # Development status
The current developement status of the VRE language is *alpha*. The current developement status of the VRE language is *beta*.
If you are interested, you can have a look at the [issues](https://gitlab.kit.edu/kit/virtmat-tools/vre-language/-/issues) and even start contributing by forking and creating merge requests. If you are interested, you can have a look at the [issues](https://gitlab.kit.edu/kit/virtmat-tools/vre-language/-/issues) and even start contributing by forking and creating merge requests.
...@@ -27,7 +27,7 @@ If you want to use workflows for modeling and data analysis using Python in Jupy ...@@ -27,7 +27,7 @@ If you want to use workflows for modeling and data analysis using Python in Jupy
# Documentation # Documentation
An installation guide and preliminary documentation is provided on [these pages](docs/index.md). An installation guide and comprehensive documentation is provided on [these pages](https://vre-language.readthedocs.io).
# Support # Support
......
name: vre-language
dependencies:
- python=3.9 # Python version must be 3.9 or newer
- pip
- pip:
- .[test] #Install vre-language project (main package and dependencies) from local directory
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
docs/_static/textS-favicon_16x16.png

832 B

docs/_static/textS-logo_120x120.png

9.35 KiB

This diff is collapsed.
...@@ -160,9 +160,9 @@ d = 'x' ...@@ -160,9 +160,9 @@ d = 'x'
All `vary` statements in one script or in one Jupyter input cell are merged into one effective vary statement [after applying the constraints](#syntax-and-semantics-of-the-vary-statement). The `vary` statements in further input cells are interpreted independently. All `vary` statements in one script or in one Jupyter input cell are merged into one effective vary statement [after applying the constraints](#syntax-and-semantics-of-the-vary-statement). The `vary` statements in further input cells are interpreted independently.
## Behavior of print statements ## Behavior of `print` and `view` statements
The print statement is only applied to the active model. The active model can be selected in the interactive tools by using the `%uuid` magic. The active model cannot be selected in the script tool, i.e. in `texts script`, where it is always the first model in the group. The `print` and the `view` statement are only applied to the active model. The active model can be selected in the interactive tools by using the `%uuid` magic. The active model cannot be selected in the script tool, i.e. in `texts script`, where it is always the first model in the group. The bahavior of `print` and `view` implies that only parameters in the active model are evaluated in case of [on-demand](tools.md#workflow-mode) evaluation.
## Evaluation mode ## Evaluation mode
...@@ -170,4 +170,4 @@ The bulk processing feature is available only in [workflow evaluation mode](tool ...@@ -170,4 +170,4 @@ The bulk processing feature is available only in [workflow evaluation mode](tool
## Interactive sessions ## Interactive sessions
In interactive sessions (Jupyter notebook or `texts session`) the magic `%vary` prints the current varied parameters, together with their pertinent model UUIDs in table format. The magic `%uuid` displays the currently active model UUID and in parentheses `()` the UUIDs of all models in the processed group. The active model can be selected by specifying the model UUID after the `%uuid` keyword. In interactive sessions (Jupyter notebook or `texts session`) the `%vary` [magic command](tools.md#specific-features) prints the current varied parameters, together with their pertinent model UUIDs in table format. The magic `%uuid` displays the currently active model UUID and in parentheses `()` the UUIDs of all models in the processed group. The active model can be selected by specifying the model UUID after the `%uuid` keyword.
...@@ -7,15 +7,23 @@ This language extension implements the domain concept of chemical reactions. The ...@@ -7,15 +7,23 @@ This language extension implements the domain concept of chemical reactions. The
The syntax for a species definition is: The syntax for a species definition is:
``` ```
Species <name> [table with parameters and properties] Species <name> [, composition: <composition>] [table with parameters and properties]
``` ```
The word `Species` is a keyword, the species `name` is mandatory and the table is optional. Here an example for water: The word `Species` is a keyword and the species' `name` is mandatory. The specifications of composition and the properties table are optional. Here an example for water:
``` ```
water = Species H2O water = Species H2O
``` ```
The composition is either a [quoted string](scl.md#string-type) like `'H2O'` or a reference to any parameter of [string type](scl.md#string-type). Here an example for water with specified composition:
```
w = Species water, composition: 'H2O'
```
The composition string can be any brute chemical formula formatting, e.g. 'OH2' a 'HHO' are accepted.
Currently, the optional table can include the following columns: `energy`, `enthalpy`, `entropy`, `free_energy`, `zpe`, and `temperature`. For example: Currently, the optional table can include the following columns: `energy`, `enthalpy`, `entropy`, `free_energy`, `zpe`, and `temperature`. For example:
``` ```
...@@ -29,7 +37,6 @@ water = Species H2O ( ...@@ -29,7 +37,6 @@ water = Species H2O (
The provided input allows to evaluate the free energy at the given temperature. The free energy can be retrieved with `water.free_energy`. It is noted that `water.free_energy` is a series with the length of the series provided in the table in the species definition. To get the first element, `water.free_energy[0]` has to be used. Here an example with two temperatures: The provided input allows to evaluate the free energy at the given temperature. The free energy can be retrieved with `water.free_energy`. It is noted that `water.free_energy` is a series with the length of the series provided in the table in the species definition. To get the first element, `water.free_energy[0]` has to be used. Here an example with two temperatures:
``` ```
water = Species H2O ( water = Species H2O (
(energy: -14.22696999, -14.22696999) [electron_volt / particle], (energy: -14.22696999, -14.22696999) [electron_volt / particle],
...@@ -50,10 +57,10 @@ program output: >>> ...@@ -50,10 +57,10 @@ program output: >>>
<<< <<<
``` ```
The interpreter evaluates all themochemistry quantities that can be determined by using the available data. For example, if the free energy is given then the energy and the enthalpy will be evaluated: The interpreter evaluates all thermochemistry quantities that can be determined by using the available data. For example, if the free energy is given then the energy and the enthalpy will be evaluated:
``` ```
water = Species H2O ( water = Species H2O, composition: 'H2O' (
(free_energy: -14.739080832009071, -14.994145508249682) [electron_volt / particle], (free_energy: -14.739080832009071, -14.994145508249682) [electron_volt / particle],
(zpe: 0.558, 0.558) [eV / particle], (zpe: 0.558, 0.558) [eV / particle],
(entropy: 206.5, 213.1) [J/K/mol], (entropy: 206.5, 213.1) [J/K/mol],
...@@ -68,7 +75,6 @@ program output: >>> ...@@ -68,7 +75,6 @@ program output: >>>
<<< <<<
``` ```
## Chemical reactions ## Chemical reactions
An equation of a chemical reaction is defined with the syntax: An equation of a chemical reaction is defined with the syntax:
...@@ -76,7 +82,7 @@ An equation of a chemical reaction is defined with the syntax: ...@@ -76,7 +82,7 @@ An equation of a chemical reaction is defined with the syntax:
``` ```
Reaction <educts> [=|->] <products> [: table with parameters and properties] Reaction <educts> [=|->] <products> [: table with parameters and properties]
``` ```
The word `Reaction` is a keyword. The individual educts and products must be separated by a `+` sign and must be references to defined species. Every educt and product has a stoichiometric coefficient (a real number). If no coefficient is specified, then `1.0` is assumed. Example: The word `Reaction` is a keyword. The individual educts and products must be separated by a `+` sign and must be references to the variables defining the relevant species. Every educt and product has a stoichiometric coefficient (a real number). If no coefficient is specified, then `1.0` is assumed. Example:
``` ```
react = Reaction 2 H2 + O2 = 2 H2O: ((free_energy: -4.916) [eV]) react = Reaction 2 H2 + O2 = 2 H2O: ((free_energy: -4.916) [eV])
...@@ -86,28 +92,24 @@ Thermochemical quantities for a reaction will be evaluated if the necessary data ...@@ -86,28 +92,24 @@ Thermochemical quantities for a reaction will be evaluated if the necessary data
``` ```
react = Reaction 2 H2 + O2 = 2 H2O react = Reaction 2 H2 + O2 = 2 H2O
H2O = Species H2O ( H2O = Species H2O (
(free_energy: -2.458) [eV], (free_energy: -2.458) [eV],
(entropy: 2.1669e-3) [eV/K], (entropy: 2.1669e-3) [eV/K],
(zpe: 0.558) [eV], (zpe: 0.558) [eV],
(temperature: 298.15) [K] (temperature: 298.15) [K]
) )
H2 = Species H2 ( H2 = Species H2 (
(free_energy: 0.0) [eV], (free_energy: 0.0) [eV],
(zpe: 0.270) [eV], (zpe: 0.270) [eV],
(entropy: 1.3613e-3) [eV/K], (entropy: 1.3613e-3) [eV/K],
(temperature: 298.15) [K] (temperature: 298.15) [K]
) )
O2 = Species O2 ( O2 = Species O2 (
(free_energy: 0.0) [eV], (free_energy: 0.0) [eV],
(entropy: 2.1370e-3) [eV/K], (entropy: 2.1370e-3) [eV/K],
(zpe: 0.098) [eV], (zpe: 0.098) [eV],
(temperature: 298.15) [K] (temperature: 298.15) [K]
) )
print(react.free_energy) print(react.free_energy)
print(react.enthalpy) print(react.enthalpy)
print(react.entropy) print(react.entropy)
...@@ -119,4 +121,66 @@ program output: >>> ...@@ -119,4 +121,66 @@ program output: >>>
(enthalpy: -5.07276727) [electron_volt] (enthalpy: -5.07276727) [electron_volt]
(entropy: -0.0005258000000000007) [electron_volt / kelvin] (entropy: -0.0005258000000000007) [electron_volt / kelvin]
<<< <<<
``` ```
\ No newline at end of file
The calculation of thermochemical quantities assumes that the reaction equation is balanced. If all terms (species) in the equation have compositions specified then a check is performed and if the equation is not balanced the evaluation is interrupted with an error. Therefore, it is recommended to specify [species](#chemical-species) compositions to enable these checks. If some compositions are not available for the check, a warning about this is issued.
## Retrieve all properties of `Species` or `Reaction`
All properties of a `Species` or a `Reaction` parameter can be retrieved as `Table` using the `properties` keyword, for example:
```
print(H2O.properties)
print(H2O.composition)
```
```
program output: >>>
((free_energy: -2.458) [electron_volt], (entropy: 2.1669e-3) [electron_volt / kelvin], (zpe: 0.558) [electron_volt], (temperature: 298.15) [kelvin])
'H2O'
<<<
```
## Using `Species` and `Reaction` as iterables
The `Species` and `Reaction` parameters are table-like iterables can be used in any operations that are defined for the [Table](scl.md#table) type. These operations are, e.g., subscripting, slicing, filter function and expression, map and reduce, and base on the table with properties.
**Examples:**
```
H2O = Species H2O (
(free_energy: -14.739080832009071, -14.994145508249682) [eV],
(temperature: 500., 600.) [K]
)
H2O_500K = H2O select free_energy where temperature == 500. [K]
H2O_500K_alt = filter((x: x.temperature == 500.0 [K]), H2O)
H2O_500K_free_table = map((x: {free_energy: x.free_energy}), H2O_500K)
H2O_500K_free_series = H2O_500K.free_energy
MO = Species MO
M = Species M
H2 = Species H2
react = Reaction MO + H2 = M + H2O:
((free_energy: -1., -2.) [eV],
(temperature: 500., 600.) [K])
max(x, y) = if(y > x, y, x)
max_alt(x, y, ax, ay) = if(y > x, ay, ax)
react_550K = react where temperature > 550 [kelvin]
react_550K_alt = filter((x: x.temperature > 550 [K]), react)
react_max_temp = reduce((x, y: {temperature: max(x.temperature, y.temperature)}), react)
free_max_temp = reduce((x, y: {free_energy: max_alt(x.temperature, y.temperature, x.free_energy, y.free_energy)}), react);
```
## Visualize reaction energy profiles
Waterfall type of reaction energy profiles can be visualized with the following statement:
```
view waterfall (<series of reactions>[, <'orr' | 'oer'>])
```
The first parameter is a [series](scl.md#series) of [reactions](#chemical-reactions). The sesond optional string parameter indicates which reaction will be displayed - oxygen reduction reaction (`'orr'`), which is the default, or the oxygen evolution reaction (`'oer'`). A full example is provided in the script `TextM-oxycat_electrochem.vm` in the VRE Language software repository.
\ No newline at end of file
# pylint: skip-file
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'VRE Language'
copyright = '2023, Karlsruhe Institute of Technology'
author = 'The Virtmat Tools Team'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = ['myst_parser']
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'sphinx_rtd_theme'
html_theme_options = {
'navigation_depth': 3,
}
html_static_path = ['_static']
html_logo = "_static/textS-logo_120x120.png"
html_favicon = "_static/textS-favicon_16x16.png"
myst_heading_anchors = 4
This section of the documentation is inteded for developers interested in extending the Scientific Computing Language to other domains. # Extending the language
# Introduction This section of the documentation is inteded for developers interested in extending the Scientific Computing Language to other domains.
The [Scientific Computing Language (SCL)](scl.md) can be extended to cover other domains of scientific computing. Currently, the SCL extension [Atomic and Molecular Modeling Language (AMML)](amml.md) can be used as a blueprint. The modularity of the grammar and of the interpreter is continuously improved so that there may be frequent changes in this section until there is a stable package structure. The [Scientific Computing Language (SCL)](scl.md) can be extended to cover other domains of scientific computing. Currently, the SCL extension [Atomic and Molecular Modeling Language (AMML)](amml.md) can be used as a blueprint. The modularity of the grammar and of the interpreter is continuously improved so that there may be frequent changes in this section until there is a stable package structure.
# Test cases (inputs) ## Test cases (inputs)
It is strongly recommended to have a clear idea what abstractions from the new domain should be added to the language and with what language elements (such as types and operations) these will be implemented. It is strongly recommended to have a clear idea what abstractions from the new domain should be added to the language and with what language elements (such as types and operations) these will be implemented.
...@@ -14,7 +14,7 @@ In the following there are two examples of extensions of the SCL core language f ...@@ -14,7 +14,7 @@ In the following there are two examples of extensions of the SCL core language f
**Example 2**: Extend the `print` statement to enable units conversion of numeric parameters. A good test input will be, for example, `a = 1 [m]; print(a [cm])`. **Example 2**: Extend the `print` statement to enable units conversion of numeric parameters. A good test input will be, for example, `a = 1 [m]; print(a [cm])`.
# General procedure ## General procedure
The following steps include all changes needed to extend the language. The SCL and its supporting tools are based on [textX](http://textx.github.io/textX/), a tool for creating domain-specific languages and their supporting tools using Python. The following steps include all changes needed to extend the language. The SCL and its supporting tools are based on [textX](http://textx.github.io/textX/), a tool for creating domain-specific languages and their supporting tools using Python.
...@@ -37,23 +37,23 @@ The following steps include all changes needed to extend the language. The SCL a ...@@ -37,23 +37,23 @@ The following steps include all changes needed to extend the language. The SCL a
9. Write a documentation of the extension. 9. Write a documentation of the extension.
# Grammar, metamodel and model parser ## Grammar, metamodel and model parser
## Grammar ### Grammar
The main component of the domain-specific language is the *grammar*. The grammar describes the syntax of the langauge in a formal and machine-readable way. In SCL a [textX grammar](http://textx.github.io/textX/latest/grammar/) is used. The developer has to familiarize themself with the textX grammar before starting a language extension. A good tutorial section can be found [here](http://textx.github.io/textX/latest/tutorials). The main component of the domain-specific language is the *grammar*. The grammar describes the syntax of the langauge in a formal and machine-readable way. In SCL a [textX grammar](https://textx.github.io/textX/grammar.html) is used. The developer has to familiarize themself with the textX grammar before starting a language extension. A good tutorial section can be found [here](https://textx.github.io/textX/tutorials/hello_world.html).
The SCL grammar consists of a set of rules that are used to match the textual model. The SCL grammar consists of a set of rules that are used to match the textual model.
### Grammar version #### Grammar version
After significant changes in grammar, the grammar version must be increased and added to `compatibility.py`. If the grammar changes break the compatibility with the intepreter before the changes, then the previous grammar versions must be removed from `compatibility.py` After significant changes in grammar, the grammar version must be increased and added to `compatibility.py`. If the grammar changes break the compatibility with the intepreter before the changes, then the previous grammar versions must be removed from `compatibility.py`
### Use of references #### Use of references
While any reference allowed in textX can be used (for example `myref = [Variable:ID]`) only reference objects of class `GeneralReference` are mapped to links in FireWorks workflows. Therefore, to have a working model in workflow evaluation mode, only this type of references should be used. The rules `IterableProperty` and `IterableQuery` can be used as blueprints for such uses. While any reference allowed in textX can be used (for example `myref = [Variable:ID]`) only reference objects of class `GeneralReference` are mapped to links in FireWorks workflows. Therefore, to have a working model in workflow evaluation mode, only this type of references should be used. The rules `IterableProperty` and `IterableQuery` can be used as blueprints for such uses.
## Grammar location ### Grammar location
The grammar is located in the folder `src/virtmat/language/grammar` where `virtmat.tx` is the top-level grammar file. The grammar correctness can be checked by the command The grammar is located in the folder `src/virtmat/language/grammar` where `virtmat.tx` is the top-level grammar file. The grammar correctness can be checked by the command
...@@ -61,49 +61,49 @@ The grammar is located in the folder `src/virtmat/language/grammar` where `virtm ...@@ -61,49 +61,49 @@ The grammar is located in the folder `src/virtmat/language/grammar` where `virtm
textx check src/virtmat/language/grammar/virtmat.tx textx check src/virtmat/language/grammar/virtmat.tx
``` ```
## Metamodel ### Metamodel
By *parsing* the grammar, textX creates the so-called *metamodel* (see Figure 1). The textX metamodel is a set of Python classes with certain relationships, for example the *parent-child* relationship. Another important relationship is the *reference*. Every common rule in the grammar gives rise to one class in the metamodel with the same name as the grammar rule. The metamodel can be visualized using the `graphviz` package as described [here](http://textx.github.io/textX/latest/visualization/) so that the metamodel classes with their attributes and relationships can be inspected. By *parsing* the grammar, textX creates the so-called *metamodel* (see Figure 1). The textX metamodel is a set of Python classes with certain relationships, for example the *parent-child* relationship. Another important relationship is the *reference*. Every common rule in the grammar is used to generate one class in the metamodel with the same name as the grammar rule. The metamodel can be visualized using the `graphviz` package as described [here](https://textx.github.io/textX/visualization.html) so that the metamodel classes with their attributes and relationships can be inspected.
![Figure 1](figs/textx-overview.png "Figure 1. An overview of textX concepts") ![Figure 1](figs/textx-overview.png "Figure 1. An overview of textX concepts")
## DSL parser ### DSL parser
The second artifact created by parsing the grammar is the DSL *parser*, i.e. the code that will process a *textual model* written in the domain specific language. The DSL parser and the metamodel are not provided as source code but rather created in memory from the grammar *on-the-fly* every time a textual model is processed (see Figure 2). The second artifact created by parsing the grammar is the DSL *parser*, i.e. the code that will process a *textual model* written in the domain specific language. The DSL parser and the metamodel are not provided as source code but rather created in memory from the grammar *on-the-fly* every time a textual model is processed (see Figure 2).
![Figure 2](figs/textx-flowchart.png "Figure 2. A textX flow diagram") ![Figure 2](figs/textx-flowchart.png "Figure 2. A textX flow diagram")
# Run the regression tests ## Run the regression tests
Grammar extensions always require changing existing rules, e.g. extending an ordered choice rule with a newly added rule. Therefore, after checking the grammar correctness, the regression tests must be run. The regression tests are located in the top-level folder `tests`. The tests can be started, after changing to the test directory, with the command `pytest`. If any regression tests fail due to the changes in the grammar the grammar must be fixed so that all regression tests pass. Grammar extensions always require changing existing rules, e.g. extending an ordered choice rule with a newly added rule. Therefore, after checking the grammar correctness, the regression tests must be run. The regression tests are located in the top-level folder `tests`. The tests can be started, after changing to the test directory, with the command `pytest`. If any regression tests fail due to the changes in the grammar the grammar must be fixed so that all regression tests pass.
# Model ## Model
The top-level folder `scripts` contains the script `show_model.py`. Using this script, the textual model is parsed and if parsing is successful, i.e. the textual model has valid syntax, then the *abstract model* (or simply the *model*) is created. In addition, a graphviz dot file is created with the same base name as the textual model file is created. This can be used to create e.g. a PDF file displaying the model, for example: Using the option `--show-model` of the [CLI](tools.md#script-mode), the textual model is parsed and if parsing is successful, i.e. the textual model has valid syntax, then the *abstract model* (or simply the *model*) is created. In addition, a graphviz dot file is created with the same base name as the textual model file is created. This can be used to create e.g. a PDF file displaying the model, for example:
```bash ```bash
python ../scripts/show_model.py series.vm texts script --show-model -f series.vm
dot -Tpdf series.dot -o series.pdf dot -Tpdf series.dot -o series.pdf
``` ```
# Enrich the metamodel ## Enrich the metamodel
The generated metamodel needs certain extensions that are used within the interpreter stage. The generated metamodel needs certain extensions that are used within the interpreter stage.
## `type_` properties ### `type_` properties
The SCL is statically typed language and for this reason every new metamodel class must have a `type_` property method that evaluates and returns the Python type of a model object (instance of the metamodel class). The mapping between Python types and SCL types is provided in the internal module `src/virtmat/language/utilities/types.py`. If the values of the objects of newly added metamodel classes may have another type than one of the already provided types, then the type map must be extended with this new type correspondingly. If the type of an object cannot be inferred, `None` is returned. If the object returns no value, then `NoneType` is returned. The SCL is a statically typed language and for this reason every new metamodel class must have a `type_` property method that evaluates and returns the Python type of a model object (instance of the metamodel class). The mapping between Python types and SCL types is provided in the internal module `src/virtmat/language/utilities/typemap.py`. If the values of the objects of newly added metamodel classes may have another type than one of the already provided types, then the type map must be extended with this new type correspondingly. If the type of an object cannot be inferred, `None` is returned. If the object has no `value` attribute, then the `type_` attribute is also not defined.
The type methods are located in the internal module `src/virtmat/language/constraints/typechecks.py`. The type methods are located in the internal module `src/virtmat/language/constraints/typechecks.py`.
**NOTE**: To evaluate the type, the `value` property may not be used. **NOTE**: To evaluate the type, the `value` property may not be used.
## `value` properties ### `value` properties
Every metamodel class whose objects have values (i.e. `type_` property is different from `NoneType`) must provide a `value` property method. These methods are located in the internal module `src/virtmat/language/interpreter/instant_executor.py`. Every metamodel class, whose objects have values and have `type_` attribute, must provide a `value` property method. These methods are located in the internal module `src/virtmat/language/interpreter/instant_executor.py`.
## `func` properties ### `func` properties
For deferred and workflow evaluation, every class with a `value` property must also provide the `func` property method. The `func` property method is a Python function returning the `func` property that is a tuple consisting of a function returning eventually the object value (only if called) and a flat tuple of model objects whose values are used as *call parameters*. For deferred and workflow evaluation, every class with a `value` property must also provide the `func` property method. The `func` property method is a Python function returning the `func` property that is a tuple consisting of a function returning eventually the object value (only if called) and a flat tuple of model objects whose values are used as *call parameters*.
...@@ -120,38 +120,44 @@ def weighted_sum_func(self): ...@@ -120,38 +120,44 @@ def weighted_sum_func(self):
metamodel['WeightedSum'].func = property(weighted_sum_func) metamodel['WeightedSum'].func = property(weighted_sum_func)
``` ```
## Object processors ### Object processors
The textX [object processors](http://textx.github.io/textX/latest/metamodel/#object-processors) are useful if a constraint cannot be enforced by the grammar or a class attribute cannot be set by parsing, such as default attribute values or values implied by some convention, i.e. a specification in the input is missing. The textX [object processors](https://textx.github.io/textX/metamodel.html#object-processors) are useful if a constraint cannot be enforced by the grammar or a class attribute cannot be set by parsing, such as default attribute values or values implied by some convention, i.e. a specification in the input is missing. For example, a complex number with missing optional real part in the input will be an object with real part attribute than has value `None`. An object processor finds this and replaces `None` with `0.0`.
The object processor is an (optional) function that allows the processing (performing checks, adding/modifying attributes etc.) the objects of a certain metamodel class. Every object processor is registered on a per-class basis in the internal module `src/virtmat/language/metamodel/processors.py` and run on a per-object basis as soon as an object of the class is instantiated. The object processor is an (optional) function that allows the processing (performing checks, adding/modifying attributes etc.) the objects of a certain metamodel class. Every object processor is registered on a per-class basis in the internal module `src/virtmat/language/metamodel/processors.py` and run on a per-object basis as soon as an object of the class is instantiated.
# Interpreter ## Interpreter
The interpreter is implemented as a list of textX [model processors](http://textx.github.io/textX/latest/metamodel/#model-processors). The instant and the deferred evaluation is triggered by calling the `value` property of the top-level model object (named `Program`). The workflow evaluation is triggered by calling the model processor `workflow_model_processor(metamodel)`. The interpreter is implemented as a list of textX [model processors](https://textx.github.io/textX/metamodel.html#model-processors). The instant and the deferred evaluation is triggered by calling the `value` property of the top-level model object (named `Program`). The workflow evaluation is triggered by calling the model processor `workflow_model_processor(metamodel)`.
The model processors are only called within textX automatically (in the order of registration) right after the model is fully instantiated and all object processors have run. The model processors are only called within textX automatically (in the order of registration) right after the model is fully instantiated and all object processors have run.
The only needed action in this section upon language extension is to write and register relevant object and model processors. The only needed action in this section upon language extension is to write and register relevant object and model processors.
## Constraints ### Constraints
The purpose of constraints is to introduce semantics into the model that is not included in the grammar. For example, a circular reference cannot be prevented by grammar or in the best case such grammar will decrease parser performance significantly due to necessary and potentially very long look-aheads. Therefore, a check for a circular reference can be done more efficiently after the parsing phase, after the whole model is completely constructed. Another type of constraint is the *type* constraint. The purpose of constraints is to introduce semantics into the model that is not included in the grammar. For example, a circular reference cannot be prevented by grammar or in the best case such grammar will decrease parser performance significantly due to necessary and potentially very long look-aheads. Therefore, a check for a circular reference can be done more efficiently after the parsing phase, after the whole model is completely constructed. Another type of constraint is the *type* constraint.
All constraints in SCL are implemented as textX model processors that are registered in the internal module `src/virtmat/language/metamodel/processors.py`. The individual constraint processors are located in the folder `src/virtmat/language/constraints` and registered in the module `src/virtmat/language/constraints/processors.py`. One example of such constraints is to check validity of types in `check_types_processor(metamodel)`. Other kinds of constraints are defined in the same folder and registered in the same module. All constraints in SCL are implemented as textX model processors that are registered in the internal module `src/virtmat/language/metamodel/processors.py`. The individual constraint processors are located in the folder `src/virtmat/language/constraints` and registered in the module `src/virtmat/language/constraints/processors.py`. One example of such constraints is to check validity of types in `check_types_processor(metamodel)`. Other kinds of constraints are defined in the same folder and registered in the same module.
# Write serialization classes and print formatters ## Write serialization classes for new types
It can happend that for the language extension some language *parameters*, i.e. textX model objects with defined `value` property, have a new type. This new type has to be added to the internal module `src/virtmat/language/utilities/typemap.py` and mapped to the relevant Python type (class). For the Python class of such new type, a serialization class has to be written. The location of the serialization classes is `src/virtmat/language/utilities/serializable.py`. The serialization class is a subclass of the relevant Python class, that is the value type of the corresponding textX object, and of the base class [`FWSerializable`](https://materialsproject.github.io/fireworks/fireworks.utilities.html#fireworks.utilities.fw_serializers.FWSerializable). It provides the attribute `_fw_name` and implementations of the methods `to_dict()` and `from_dict()`.
The `to_dict()` method is used to serialize the values of the relevant textX objects for use in the workflow management system or for storage in the database or in a file in JSON format. When this method is changed or new serialization classes are added then the `DATA_SCHEMA_VERSION` must be incremented. The method must be decorated with `@versioned_serialize`.
It can happend that for the language extension some language *parameters*, i.e. textX model objects with defined `value` property, have a new type. This new type has to be added to the internal module `src/virtmat/language/utilities/types.py` and mapped to the relevant Python type (class). Fo the Python class of such new type, a serialization class has to be written. The location of the serialization classes is `src/virtmat/language/utilities/serializable.py`. The serialization class is a subclass of the relevant Python class, that is the value type of the corresponding textX object, and of the base class [`FWSerializable`](https://materialsproject.github.io/fireworks/fireworks.utilities.html#fireworks.utilities.fw_serializers.FWSerializable). It provides the attribute `_fw_name` and implementations of the methods `to_dict()` and `from_dict()`. The `to_dict()` method is used to serialize the values of the relevant textX objects for use in the workflow management system or for storage in the database or in a file in JSON format. The `from_dict()` is used to deserialize (re-construct) the thus serialized objects. The `_fw_name` attribute is used for automatic recursive serialization and deserialization by the workflow management system using generic methods such as `load_object()`. The `from_dict()` is used to deserialize (re-construct) the thus serialized objects. If breaking changes are made in the serialization schema after some `version` then this method is further provided under the name `from_dict_{version}` and the `from_dict()` is decorated with `@versioned_deserialize` to maintain compatibility. A list of supported schema versions is maintained in `versions['data_schema']` in `compatibility.py`.
For every new type, a print formatter has to be written. The formatter returns a string representation of the model object value matching the common rule corresponding to the metamodel class of the object. For example, the value of the model object of class `Series` has `Series` type, and is represented by the Python class `pandas.Series`. The value of the model object, that is a `pandas.Series` object is represented by the formatter in a string like `(a: 1, 2, 3)` and this is how the value is displayed on the screen. The `_fw_name` attribute is used for automatic recursive serialization and deserialization by the workflow management system using generic methods such as `load_object()`.
## Write print formatters for new types
# Add the test inputs to the tests For every new type, a print formatter has to be written in the module `src/virtmat/language/utilities/formatters.py`. The formatter returns a string representation of the model object value matching the common rule corresponding to the metamodel class of the object. For example, the value of the model object of class `Series` has `Series` type, and is represented by the Python class `pandas.Series`. The value of the model object, that is a `pandas.Series` object is represented by the formatter in a string like `(a: 1, 2, 3)` and this is how the value is displayed on the screen.
The test inputs should be used to create test functions for pytest in the top-level folder `tests`. These tests will be run every time and ensure that the newly added features will be working after every change. ## Add the test inputs to the tests
The test inputs should be used to create test functions for `pytest` in the top-level folder `tests`. These tests will be run every time and ensure that the newly added features will be working after every change.
# Write documentation ## Write documentation
Write about the language extensions in the top-level `docs` folder. Write about the language extensions in the top-level `docs` folder.
# Frequently asked questions (FAQs)
**Q**: I am getting the following error: `pymongo.errors.DocumentTooLarge: 'findAndModify' command document too large`. What can I do?
**A**: You can change the default setup for [background I/O](io.md#background-io-operations).
**Q**: I cannot find a model in the database, what can I do?
**A**: You can use [tags](query.md#the-tag-statement) and then [search](query.md#the-find-command) the database for known tags, metadata and data.
**Q**: The statements in the model are evaluated in an order that is non-intuitive. I wish certain statements to be evaluated now and other statements - only later.
**A**: You can consider using the `--on-demand` option to either `texts session` or `texts script`. Read more [here](tools.md#supporting-tools).
**Q**: Slurm does not accept batch jobs with `--account` but `texts` adds my username as the default account.
**A**: Open an `ipython` session and run the following code:
```python
from virtmat.middleware.resconfig import get_default_resconfig, get_resconfig_loc
cfg = get_default_resconfig()
cfg.default_worker.accounts.append(None)
cfg.default_worker.default_account = None
cfg.to_file(get_resconfig_loc())
```
Then run `texts` again. Then use the [variable update](scl.md#dealing-with-failures) (using `:=`) to inforce re-evaluation of the resources. A simple `%rerun var` will not be sufficient.
\ No newline at end of file
docs/figs/scl-view-plot.png

25.1 KiB

docs/figs/scl-view-plot2.png

23.9 KiB

docs/figs/scl-view-structure.png

38.2 KiB