# Supporting tools To enable the usage of textS and textM, a minimum set of supporting tools is necessary. These tools include a parser, a correctness checker, an interpreter, and a syntax highlighter. All these tools (or subsets of them) can be used via the command-line interface or the Jupyter/iPython kernel. ## Using the command-line interface (CLI) The command-line interface is invoked with the command `texts`. ### Script mode The command `texts script` runs a textS/textM *program* (also called a *model*) in one of three different evaluation modes. The basics on how to write a program in textS and in textM can be found in [this section](scl.md) and in [this section](amml.md), respectively. In all evaluation modes, the model is first parsed using a grammar. The grammar can be optionally specified by the flag `-g GRAMMAR_PATH, --grammar-path`. The default grammar used for parsing is in the file `src/virtmat/language/grammar/virtmat.tx`. Syntax errors are issued in this phase. The interpreter then starts applying static constraints such as type checks. Static errors (such as type errors) are issued at this stage. Then the evaluation of the model is performed. The evaluation (or execution) mode can be specified using the `-m | --mode` option. These modes are *instant*, *deferred*, and *workflow*. The instant evaluation mode is the default. More details are available in the following subsections. The *model source file* (with extension `.vm` ) must always be specified using the flag `-f MODEL_FILE, --model-file MODEL_FILE` even if it is empty. #### Instant and deferred modes In the *instant* mode the evaluation is performed *immediately* and *locally*. In *deferred* mode the evaluation is deferred but still performed *locally*. In *instant* and *deferred* modes the model does not persist after the interpreter has finished, i.e. the `texts script` has returned. Only parameters of `print` and `view` statements in the program will be evaluated. #### Workflow mode In the *workflow* mode the interpreter creates a workflow from the model and stores the workflow in a database. Therefore, the model is *persistent* after the interpreter returns, i.e. the *model instance* continues existing on the database. A model instance can be retrieved via a *universally unique identifier* (UUID) that is generated at the time when the model instance is created. A model instance can only be evaluated and extended but not otherwise modified. If no additional flags are specified, the model is not evaluated after interpretation except for parameters in `print` and `view` statements that contain no references to variables. Otherwise `n.c.` will be printed instead of the not yet computed values and `view` statements will produce warnings. Optionally, a model can be evaluated locally after the interpreter finishes by specifying the `-r | --autorun` flag. In this case all variables will be evaluated but only those in `print`/`view` statements will be printed/displayed. Additionally, the `-d | --on-demand` flag restricts the evaluation to only those variables that are referenced in `print` and `view` statements. In order to work in workflow mode, a launchpad describing a connection to a MongoDB database must be configured. Using the flag `-l LAUNCHPAD_FILE, --launchpad-file LAUNCHPAD_FILE` the launchpad data (such as hostname, database name and credentials) can be optionally specified. Otherwise `texts` looks up the current working directory and then the folder `$HOME/.fireworks` for a launchpad configuration. More information about configuring a launchpad can be found [here](https://vre-middleware.readthedocs.io/en/latest/installation.html#setting-up-fireworks-with-a-mongodb-instance). By using the `-h, --help` flag a summarized help can be obtained: ``` texts script --help usage: texts script [-h] -f MODEL_FILE [-g GRAMMAR_PATH] [-m {instant,deferred,workflow}] [-l LAUNCHPAD_FILE] [-u UUID] [-r] [-d] [-q QADAPTER_FILE] [-w] [--no-unique-launchdir] [--enable-logging] [--logging-level {NOTSET,DEBUG,INFO,WARNING,ERROR,CRITICAL}] [--logfile LOGFILE] [--no-duplicate-detection] Run a script options: -h, --help show this help message and exit -f MODEL_FILE, --model-file MODEL_FILE path to model file -g GRAMMAR_PATH, --grammar-path GRAMMAR_PATH path to grammar root file -m {instant,deferred,workflow}, --mode {instant,deferred,workflow} execution mode -l LAUNCHPAD_FILE, --launchpad-file LAUNCHPAD_FILE path to launchpad file (workflow mode only) -u UUID, --uuid UUID UUID of a model to extend/run (workflow mode only) -r, --autorun run the model (workflow mode only) -d, --on-demand run on demand -q QADAPTER_FILE, --qadapter-file QADAPTER_FILE path to default qadapter file (workflow mode only) -w, --ignore-warnings do not display warnings --no-unique-launchdir disable unique launchdir --enable-logging enable logging messages --logging-level {NOTSET,DEBUG,INFO,WARNING,ERROR,CRITICAL} logging level --logfile LOGFILE logfile --no-duplicate-detection disable duplicate detection ``` A persistent model can be retrieved in workflow mode by using the flag `-u UUID, --uuid UUID`. A model can be optionally evaluated in workflow mode by adding the `-r, --autorun` and `-d, --on-demand` flags or/and extended by specifying a model extension with the flag `-f MODEL_FILE, --model-file MODEL_FILE`. The evaluation with the `-r, --autorun` flag is effective only for workflow nodes of [_interactive_ category](resources.md#policies-for-interactive-and-batch-execution). By default, in workflow mode every statement will be evaluated in a unique launch directory. Because nodes, that are evaluated in parallel and that share a launch directory, may interfere due to possible local file I/O operations. The default use of unique launch directories can be deactivated for [_interactive_](resources.md#policies-for-interactive-and-batch-execution) workflow nodes by the flag `--no-unique-launchdir`. In this case, one has to make sure that statements giving rise to _interactive_ workflow nodes do not cause conflicting file I/O operations. Note that [_batch_](resources.md#policies-for-interactive-and-batch-execution) workflow nodes are always evaluated in unique launch directories. #### Turning the script into an executable A script can be turned into an executable by adding `#!/usr/bin/env -S texts script -f` to the top (first line) of the script. Then the file must be given execute permissions by running `chmod +x my_script.vm` and placed somewhere in the search path (defined in `$PATH`). After this, the script can be started as a normal executable by just running `my_script.vm`. ### Interactive session The interactive session, started with `texts session`, is a tool managing a session for processing a model in *workflow mode*. Some of the startup flags are the same as for `texts script`. By default no evaluation is performed. The evaluation with the `-r, --autorun` without the `-a, --async-run` flag is effective only for workflow nodes of [_interactive_ category](resources.md#policies-for-interactive-and-batch-execution). The flag `-a, --async-run` activates background evaluation using a workflow engine with a launcher thread. The evaluation includes workflow nodes of both [_interactive_ and _batch_ categories](resources.md#policies-for-interactive-and-batch-execution). For this feature the [vre-middleware package](https://vre-middleware.readthedocs.io) must be installed. The `WFEngine` object used in the run is dumped into a file in the same folder as the launchpad file. This object can be used independently with the Python API or the GUI of the [vre-middleware package](https://vre-middleware.readthedocs.io) as described in more detail [in this section](#evaluation-of-nodes-of-batch-category). The flag `-q, --qadapter-file` is explained in detail [in this section](#evaluation-of-nodes-of-batch-category). By using the `-h, --help` flag a summarized help can be obtained: ``` texts session --help usage: texts session [-h] [-g GRAMMAR_PATH] [-l LAUNCHPAD_FILE] [-u UUID] [-r] [-a] [-d] [-s SLEEP_TIME] [-q QADAPTER_FILE] [-f MODEL_FILE] [-w] [--no-unique-launchdir] [--enable-logging] [--logging-level {NOTSET,DEBUG,INFO,WARNING,ERROR,CRITICAL}] [--logfile LOGFILE] [--no-duplicate-detection] Start an interactive session options: -h, --help show this help message and exit -g GRAMMAR_PATH, --grammar-path GRAMMAR_PATH path to grammar root file -l LAUNCHPAD_FILE, --launchpad-file LAUNCHPAD_FILE path to launchpad file -u UUID, --uuid UUID UUID of a model -r, --autorun run the model -a, --async-run run in background -d, --on-demand run on demand -s SLEEP_TIME, --sleep-time SLEEP_TIME sleep time for background evaluation in seconds -q QADAPTER_FILE, --qadapter-file QADAPTER_FILE path to default qadapter file -f MODEL_FILE, --model-file MODEL_FILE path to model file -w, --ignore-warnings do not display warnings --no-unique-launchdir disable unique launchdir --enable-logging enable logging messages --logging-level {NOTSET,DEBUG,INFO,WARNING,ERROR,CRITICAL} logging level --logfile LOGFILE logfile --no-duplicate-detection disable duplicate detection ``` #### Session behavior In the session, inputs are interactively typed and the outputs are shown immediately. An empty model instance is created at startup and with every input the model instance is extended with the model source extension typed as input. The editing capabilities of the input fields are very limited. #### Specific features In the interactive session, if a valid parameter is typed it is interpreted as a `print` statement. For example, a typed input `a` is changed to `print(a)` before parsing. Multiline comments are not supported in the interactive session. A successfully parsed and interpreted input cannot be modified. It becomes permanently part of the model source. The session manager accepts additional inputs that are no parts of textS and textM. These are sometimes called *magic commands* (like in iPython and Jupyter) and begin with the symbol `%`. Magic commands | Action -----------------------------------|-------- `%start` | activate evaluation `%stop` | deactivate evaluation `%sleep [integer]` | set sleep time (sec) for background evaluation `%uuid [UUID]` | switch to model with UUID `%launchpad [file path]` | change the [launchpad](https://vre-middleware.readthedocs.io/en/latest/launchpad.html) file `%qadapter [file path]` | specify default [qadapter](https://vre-middleware.readthedocs.io/en/latest/qadapter.html) path `%new [file path]` | create a new model (optionally from from file) `%load ` | adds a model from file to current model `%hist`, `%history` | print the current model source `%rerun var1[, var2][, ...]` | reevaluate var1, var2, etc. `%cancel var1[, var2][, ...]` | cancel evaluation of var1, var2, etc. `%recover var1[, var2][, ...]` | recover evaluation of var1, var2, etc. `%vary` | print the [varied parameters](bulk.md#bulk-processing) `%tag` | print the [tag section](query.md#the-tag-statement) `%find [action]` | perform a global [search](query.md#the-find-command) `%logging [on\|off\|level]` | turn on/off logging or set the logging level `%logfile [file path]` | set a file for logging output `%warnings [on\|off]` | turn on/off warnings `%async [on\|off]` | turn on/off asynchronous evaluation `%on_demand [on\|off]` | turn on/off [evaluation on demand](io.md#evaluate-on-demand) `%unique_launchdir [on\|off]` | turn on/off unique launch directory `%detect_duplicates [on\|off]` | turn on/off duplicates detection `%version` | display version information `%help` | show this help `%exit`, `%bye`, `%close`, `%quit` | close (quit) the session The specifications in square brackets `[]` are optional. In some magic commands, when these specifications are omitted, the current setting is printed and no change is performed. All `file path` inputs must be provided as quoted strings, like `'/path/to/file'`. All command-line options (except for the grammar) of the interactive session (see above) can be changed interactively in the running session by using magics commands. The `%history` command prints all statements (without `print` statements that are not persisted), one per line, with timestamp of most recent evaluation update and current evaluation state. The evaluation state is currently passed through from the FireWorks workflow management system and is described in detail [here](https://materialsproject.github.io/fireworks/reference.html#fireworks-states). The `%rerun var` command can be used to reevaluate the parameter of a variable `var` and its descendants, i.e. all parameters containing references to `var`. This is useful when there was some error during evaluation of `var` that was not due to the provided input to `var` but due to side effects, for example there was a computing node or file system failure, network or power outage etc. The `%cancel var` command can be used to suspend the evaluation of the parameter of a variable `var`. Depending on the state, the final state of the variable will be different. The possible uses of the `%rerun` and `%cancel` magics, and the [variable update operator](scl.md#dealing-with-failures) (`:=`) are summarized in the following table: Original state | Final state | Magic / operator ----------------|--------------|-------------------- ARCHIVED | - | - FIZZLED | WAITING | `%rerun`, `:=` FIZZLED | DEFUSED | `%cancel` FIZZLED | WAITING | `%recover` DEFUSED | WAITING | `%rerun`, `:=` PAUSED | WAITING | `%rerun`, `:=` PAUSED | DEFUSED | `%cancel` WAITING | WAITING | `:=` WAITING | PAUSED | `%cancel` READY | READY | `:=` READY | PAUSED | `%cancel` RESERVED | WAITING | `%rerun` RESERVED | PAUSED | `%cancel` RUNNING | WAITING | `%rerun` RUNNING | DEFUSED | `%cancel` RUNNING | WAITING | `%recover` COMPLETED | WAITING | `%rerun`, `:=` **Note**: If the final state is WAITING and all referenced variables are in COMPLETED states then the final state is automatically changed to READY. **Note**: Variables in ARCHIVED state cannot be updated. #### Dealing with failures and lost launches For many different reasons the evaluation of variables may not be completed. Usually, in the case of a failure, the variable has FIZZLED state. The failure reason can be then investigated by [interpreting the error message](#interpreting-the-error-messages) that is shown if the variable is referenced in `print` and `view` statements or as parameter of the built-in `info` function. In the case of run-time environment or computing resource failure the variable can be rerun using the `%rerun` magic (see the [previous section](#specific-features)). In some cases it may be necessary to reinterpret the variable with or without parameter change by using the [variable update](scl.md#dealing-with-failures) operator. There is one more type of failures when the RUNNING or RESERVED state of a variable is not updated to FIZZLED. One possible cause of such failures is that a submitted computing job is accepted by Slurm and assigned a reservation ID but does not get started. Another situation is when a job crashes before getting into RUNNING state or is removed by Slurm (mostly due to exceeding the time limit) before changing to COMPLETED state. These so called *lost launches* are detected in `texts session` when calling the `%history` magic. Also the built-in `info` function applied to a variable provides this information. Variables with lost launches can (and should) be processed by using the `%cancel` and `%rerun` magics. For example, if variable `a` is in RESERVED state but the launch is lost, the reservation is canceled and the evaluation is restarted by using `%rerun`. The same applies to variables in RUNNING state. If the variable is not supposed to be further used, its state can be changed to DEFUSED by using the `%cancel` magic. #### Recovery from checkpoint In some specific cases of failures, the evaluation does not have to roll back to its initial state but to its most recent checkpoint. A variable is rerun with recovery by using the `%recover` magic. Such recovery saves computing resources and normally does not affect the repeatability of the evaluation, i.e. the value of the output. This method is equally applicable to variables in FIZZLED state and to variables in RUNNING state whose launches have not been completed due to timeout and marked as lost. A summary of lost runs can be found at the end of the output of the `%history` magic. In addition, the built-in [`info` function](scl.md#the-built-in-info-function) provides this information. More detailed description of checkpoint and recovery can be found in this [section](evaluation.md#checkpoint-and-recovery). ### Duplicate detection Both *script* and *session* modes have a duplicate detection feature to identify variables in other persistent models that have identical names, parameters and values. This feature ensures safe reuse of such variables and helps to avoid unnecessary repeated evaluations. The duplicate detection can be used in any model but is particularly useful in the cases of [sub-model reuse](submodel.md) and of [bulk processing](bulk.md). Duplicate detection is activated in *workflow* evaluation mode by default but it can be deactivated with the `--no-duplicate-detection` flag. ## Using the Jupyter kernel The VRE Language kernel for [Jupyter](https://jupyter.org/) provides equivalent functionalities as the [interactive session](#interactive-session). More detailed documentation can be found in [this section](jupyter.md). ## Interpreting the error messages Either the parser or the interpreter may detect *static errors* in the program. Then they issue specific error messages in the following format: ``` Error type: /absolute/path/to/model_source_file.vm:line:column --> context <-- Detailed error description ``` The `--> context <--` displays the section of the model source where the error has occurred. If the Jupyter kernel or `texts session` is used then `None` is printed instead of an absolute path to file with the model source. **NOTE:** If the error type is "Unknown error" or the error message is not in this particular format, especially if it is beginning with the word "Traceback", then it is most likely due to a bug in the interpreter and not due to an error in the model source. In such cases please [submit an issue](https://gitlab.kit.edu/kit/virtmat-tools/vre-language/-/issues) with the tag *Bug* and provide a minimal input to reproduce the error. ### Simple examples of errors Input: ``` b = 1 a = 2 ``` Error: ``` Syntax error: None:1:7 --> b = 1 *a = 2 <-- Expected '[' or '^|;|\,|\)|$' or '**' or '*' or '/' or '+' or '-' or '<=' or '>=' or '>' or '<' or '!=' or '==' or 'if' or 'for' or 'on' or '^|;' or EOF ``` All syntax errors are issued by the parser. Input: ``` b = a ``` Error: ``` Unknown object: None:1:5 Unknown object "a" of class "GeneralVariable" ``` Unknown object error is a semantic error issued by the parser when it cannot resolve a reference. Input: ``` s = 1 s = 'hello' ``` Error: ``` Initialization error: None:2:1 --> s = 'hello' <-- Repeated initialization of "s" ``` Repeated initialization error is issued by the interpreter when it applies semantic constraints before the beginning of evaluation. ### Run-time errors Some errors occur only during the evaluation. These are called *run-time errors*. Run-time errors have the same format as the static errors. Run-time errors only occur if the evaluation is requested, e.g. by `print` or `view` statements. For example, this input: ``` length = 1 [m] b = length + 1 ``` will produce no error message. Adding `print(b)` to the model and running the model in instant or deferred evaluation mode will yield this error: ``` Dimensionality error: None:2:5 --> length + 1 <-- Cannot convert from 'meter' ([length]) to 'dimensionless' (dimensionless) ``` In workflow evaluation mode this error occurs only if the evaluation is enabled and will be issued only if there is `print(b)` statement. ## Evaluation of nodes of batch category Once a model has been created in workflow mode, thus added to the database, it can be evaluated using either `texts script` or `texts session` with the `--autorun, -r` flag. In this mode, the workflow nodes of _interactive_ category are evaluated synchronously while the nodes of _batch_ category are not. More information about the workflow node categories can be found [here](resources.md#policies-for-interactive-and-batch-execution). To enable asynchronous background evaluation of nodes of batch category one has to add the `--async-run, -a` flag. As soon as the `texts session` is exited the background evaluation is terminated. This means that no further _batch_ nodes will be scheduled for execution. The already scheduled or running _batch_ nodes will be further processed without interruption or any user actions. The evaluation of a model can be continued either by loading the model in a new session with `texts session -u UUID -r -a` or by running the `wfengine` CLI tool from the [VRE Middware package](https://vre-middleware.readthedocs.io/en/latest/resconfig.html) independently. ```bash wfengine --load-from-file wfengine-.yaml -r -c all ``` The `wfengine-.yaml` file is always created by `texts session` in the same folder as the launchpad file used in the session when the `--async-run, -a` flag is used. The `wfengine-.yaml` file contains a dumped `WEngine` object with a complete configuration, including launchpad, model UUID, default qadapter (see below), default worker, etc. Further options for running the `wfengine` tool can be shown with the `--help` flag. The evaluation of nodes of batch category happens in an HPC environment governed by a batch system such as SLURM and requires an object called *qadapter*. ### Default qadapter A default qadapter will be automatically created by the workflow engine and used by the launcher thread. To this end, the default resources in the resource configuration (*resconfig*) object are used. These resources are: default worker, default queue, default launch directory, default group used for accounting, default queue with default computing resources (such as walltime, number of CPUs, amount of memory etc.), default loaded environment modules, default virtual environment. The resconfig object is stored in a resconfig file with default location `$HOME/.fireworks/res_config.yaml` that can be overridden by the environment variable `RESCONFIG_LOC`. If the resconfig file does not exist at the beginning of `texts session`, then it is generated automatically (a prompt will be displayed to accept this step). Further more technical information about res_config can be found [elsewhere](https://vre-middleware.readthedocs.io/en/latest/resconfig.html). If necessary, the default qadapter can be overridden by using the optional `--qadapter-file, -q` flag, which takes the name of a qadapter file (e.g. "qadapter.yaml"), containing a qadapter object, as argument. This can be necessary if the default qadapter does not specify some resource needed by the batch job to run. However, the recommended way to fix this is to modify the res_config object instead of providing a default qadapter. If the user has to write a qadapter file then [this tutorial](https://materialsproject.github.io/fireworks/qadapter_programming.html) can be used. ### Custom qadapter Different batch nodes may have different resource requirements and the (either auto-generated or manually provided) [default qadapter](#default-qadapter) may not fit to all of them. For this reason, a *custom qadapter* is created automatically for nodes of batch category. The resources specified in the custom qadapter override these in the default qadapter during node launch. The custom qadapter is created automatically for models with [resource annotations](resources.md#resource-annotations) and added to the node pertinent to the statement with the resource annotation in the model. All resources specified in the resource annotation are included in the custom qadapter. In addition, the custom qadapter includes the default virtual environment and all default modules so that these will be activated and loaded in the batch job before the evaluation step starts. These default settings are sourced from the resconfig. In addition, the application-specific environment modules and variables will be set. These are not sourced from the resconfig but from the calculator or the algorithm that requires these resources.