Documentation for the ALFAsim-SDK
The ALFAsim-SDK help developers to create plugins for ALFAsim application. Plugins can extend the ALFAsim capabilities in a lot of ways, from adding a simple input to a custom calculation of solver equations.
Some examples of the capabilities that can be extended are:
Creation of user-defined GUI models, allowing custom models to be available over the Tree and in the Model Explorer. Registration of additional variables that are not nonlinear system’s unknowns, for the ALFAsim solver. Also called “secondary variables” Customization of the hydrodynamic models, supporting the additions of custom Phases/Fields/Layers. Support for inclusion of custom mass, momentum and energy equations. Support for calculating source terms to solver equations. Support for calculating/updating plugin-registered Simulation Variables
Creation of user-defined GUI models, allowing custom models to be available over the Tree and in the Model Explorer.
Registration of additional variables that are not nonlinear system’s unknowns, for the ALFAsim solver. Also called “secondary variables”
Customization of the hydrodynamic models, supporting the additions of custom Phases/Fields/Layers.
Support for inclusion of custom mass, momentum and energy equations.
Support for calculating source terms to solver equations.
Support for calculating/updating plugin-registered Simulation Variables
For a list of all capabilities that can be expanded check the Full API Reference in the documentation.
Anyone with programming skills can create a Plugin for ALFAsim. To make it possible, ALFAsim-SDK provides hooks to customize the solver and the user interface. To customize the solver, an API in C is provided for application written in C/C++, while, for user interface customization, an API in Python allows the developer to customize the interface in a declarative way.
To get quick and running with ALFAsim-SDK you can read the Quick Start and the Plugin by Example sections
In this section, it is shown how to create a plugin from scratch with the template command provided by ALFAsim-SDK. With this template, you can easily customize your application to extend ALFAsim functionality.
This allows you to experience the complete creation of a plugin workflow in a short time.
The ALFAsim-SDK is a Python package that helps developers in the process to create a Plugin for ALFAsim, to use this tool it is necessary to have a Python Interpreter with at least version 3.6. For more details on how to install Python check the official docs.
Note
It is recommended that you install the ALFAsim-SDK using a Python Virtual Environment. For more details, see Virtual Environments and Packages in Python documentation.
From a terminal, and inside a virtual environment, update pip:
>>> python -m pip install -U pip
Install the ALFAsim-SDK with:
>>> pip install alfasim-sdk
Also, make sure to have at least the following version for this software:
CMake at least version 3.5.2 Ninja at least version 1.7.0
CMake at least version 3.5.2
CMake
Ninja at least version 1.7.0
Ninja
The alfasim-sdk package has several commands that can be visualized by running the help option.
alfasim-sdk
>>> alfasim-sdk --help
To create a new project, run:
>>> alfasim-sdk template
After the execution of the command above, you will be prompted to fill the following options (all required):
>>> alfasim-sdk template ... -- Plugin Caption: Myplugin ... -- Plugin Id: myplugin ... -- Author Name: ESSS ... -- Author Email: <email>@<server>
The caption to be used across the application to identify the plugin.
The name of the plugin to be referenced during the development.
Name of the plugin author to be displayed.
Email of the plugin author to be displayed.
To check all options, call the help command:
>>> alfasim-sdk template --help
After the execution of the template command the generated plugin project will have the following structure:
\---myplugin | CMakeLists.txt | compile.py | +---assets | plugin.yaml | README.md | \---src | CMakeLists.txt | hook_specs.h | myplugin.cpp | \---python myplugin.py
The highlights here are for:
File with all information about the plugin that will be used by ALFAsim.
Implementation of the hooks for customization of the UI interface, or the solver configuration hooks.
Implementation of the hooks for customization of solver.
Check out the Plugin Structure section for more details about how the folder and files are structured, and also, check the Plugin by Example that shows how to create simple plugins that make use of the User Interface Hooks and the Solver Hooks.
From the root directory of the plugin, execute the command alfasim-sdk package. This command will compile your C/C++ implementation and include the shared libraries inside a artifacts directory and the generated plugin on the root directory with the extension hmplugin.
>>> cd myplugin >>> alfasim-sdk package ... -- Package Name: myplugin
The plugin directory will have the following structure when executing from a Windows Operating System:
\---myplugin | CMakeLists.txt | compile.py | myplugin-1.0.0-win64.hmplugin | +---artifacts | myplugin.dll | myplugin.lib | +---assets | plugin.yaml | README.md | +---build | < ... > | < ... > | +---package | myplugin.dll | plugin.yaml | README.md | \---src | CMakeLists.txt | hook_specs.h | myplugin.cpp | \---python myplugin.py
With myplugin.hmplugin file, it is now possible to install it on ALFAsim application. From the menu bar select the Plugin Manager option, as illustrated in the figure below:
myplugin.hmplugin
In the Plugin Manager windows, install myplugin.hmplugin file plugin.
By clicking on the plugin name, it is possible to visualize the content from the README.md file.
README.md
Restart the application and check the recently installed plugin available over the Tree.
In this section, we will continue to customize the template plugin created from the previous section, this plugin will calculate the liquid velocity to the power of a given exponent provided by the user from the user interface.
The following equation describes the plugin:
Where
Liquid Velocity
Exponent, input from user interface
Plugin calculated value, that will be shown on the output.
For this, we will need to:
Create a simple input, on the user interface.
Add a secondary variable, to keep track of the value.
Retrieve the input data on the HOOK_INITIALIZE.
HOOK_INITIALIZE
Save the input data on a plugin internal data.
Get the liquid velocity from the solver, during run-time.
Export the value into the created/registered plugin secondary variable.
Application customization
Solver Configuration
Hooks for Solver
ALFAsim-SDK allows plugins to customize the user interface of ALFAsim by adding custom models, the image below shows the locations where a custom model can be inserted using the hook alfasim_get_data_model_type().
alfasim_get_data_model_type()
illustrates the section where the models alfasim_sdk.container_model() or alfasim_sdk.data_model() will be placed. illustrates the section where the inputs fields will be placed.
alfasim_sdk.container_model()
alfasim_sdk.data_model()
For this example we will use a data_model() entry over the Tree, using a Quantity() field to get exponent value from the user.
data_model()
Quantity()
The hook alfasim_get_data_model_type() needs to be implemented on the myplugin.py, located on myplugin/src/python folder.
myplugin.py
myplugin/src/python
Implementation of myplugin.py
import alfasim_sdk from alfasim_sdk import data_model from alfasim_sdk import Quantity @data_model(caption='My plugin model', icon='') class MyPluginModel: exponent = Quantity(value=1, unit='-', caption='Exponent value') @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyPluginModel]
Notice that only models that are returned by the hook alfasim_get_data_model_type() will be included on the user interface of ALFAsim.
The image below illustrates the application with the output from the snippet above.
For more details about all input fields available, check the section Types. And for more detail about the available models, check the section Models.
ALFAsim-SDK provides hooks to customize the settings of the application that configures the solver internally, some of these configurations are:
Creation/Registration of new secondary variables
Creation of new phases/fields/layers.
Update of default phases and layers from the application.
For this example, a new alfasim_sdk.SecondaryVariable() will be created, to track the liquid velocity to the power of a custom value provided from the user.
alfasim_sdk.SecondaryVariable()
A Secondary Variable is a variable that can be calculated along the Network. Also, if configured as external, this variable will be set an Output, and will be available within the Trends and Profiles plots.
To create these variables, the hook alfasim_get_additional_variables() must be implemented in the myplugin.py file.
alfasim_get_additional_variables()
@alfasim_sdk.hookimpl def alfasim_get_additional_variables(): import alfasim_sdk from alfasim_sdk import SecondaryVariable from alfasim_sdk import Visibility from alfasim_sdk import Location from alfasim_sdk import Scope return [ SecondaryVariable( name='U_liq_n', caption='Powered Liquid Velocity', unit='-', visibility=Visibility.Output, location=Location.Center, multifield_scope=Scope.Global, checked_on_gui_default=True, ), ]
For more details about SecondaryVariable, check the section Secondary Variables.
SecondaryVariable
ALFAsim-SDK provides hooks that can customize the Solver behavior, this customization are implemented in C/C++ and can make use of the ALFAsim-SDK C/C++ API in order to fetch information from the application.
Solver
At this point, we are going to implement the Solver Hooks that updates the secondary variable declared from myplugin.py file and retrieve the Liquid Velocity from the ALFAsim’s Solver.
First, we need to implement two mandatory hooks, the HOOK_INITIALIZE and the HOOK_FINALIZE
HOOK_FINALIZE
With them it is possible to initialize any custom data (to store any important information) for internal use. Also it is needed to load and unload the ALFAsim-SDK API, in which will allows the plugin to use the API in any implemented hook.
Implementation of myplugin.cpp
myplugin.cpp
ALFAsimSDK_API alfasim_sdk_api; struct MyPluginModel { double exponential = 0.0; }; HOOK_INITIALIZE(ctx) { alfasim_sdk_open(&alfasim_sdk_api); int errcode = -1; double n = 0.0; errcode = alfasim_sdk_api.get_plugin_input_data_quantity( ctx, &n, get_plugin_id(), (const char*) "MyPluginModel.exponent"); if (errcode != 0) { std::cout << "input_data_quantity error=" << errcode << "\n"; return errcode; } int n_threads = -1; errcode = alfasim_sdk_api.get_number_of_threads(ctx, &n_threads); for (int thread_id = 0; thread_id < n_threads; ++thread_id) { // MyPluginModel is a class or struct defined by plugin auto* model = new MyPluginModel(); model->exponential = n; errcode = alfasim_sdk_api.set_plugin_data( ctx, get_plugin_id(), (void*) model, thread_id ); } return OK; } HOOK_FINALIZE(ctx) { auto errcode = -1; auto number_of_threads = -1; errcode = alfasim.get_number_of_threads(ctx, &number_of_threads); for (int thread_id = 0; thread_id < n_threads; ++thread_id) { MyPluginModel* model = nullptr; errcode = alfasim.get_plugin_data(ctx, (void**) (&model), get_plugin_id(), thread_id); delete model; } alfasim_sdk_close(&alfasim_sdk_api); return OK; }
Then, since the plugin wants to calculate its own secondary variable, the HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES must be implemented. As can be seen in the example below, to retrieve the velocity of the continuous liquid field it is necessary to use the get_simulation_array() API function.
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES
get_simulation_array()
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES(ctx) { int errcode = -1; // Get Liquid Field ID int liquid_field_id = -1; errcode = alfasim_sdk_api.get_field_id( ctx, &liquid_field_id, "liquid" ) if (errcode != 0) { std::cout << "get_field_id error = " << errcode << "\n"; return errcode; } // Get Liquid Field Velocity int n_faces = -1; double* U_liq = nullptr; errcode = alfasim_sdk_api.get_simulation_array( ctx, &U_liq, (char*) "U", VariableScope { GridScope::CENTER, MultiFieldDescriptionScope::FIELD, TimestepScope::CURRENT }, liquid_field_id, &n_faces); if (errcode != 0) { std::cout << "get_simulation_array error = " << errcode << "\n"; return OK; } // Get Exponent input data double n = 0.0; { int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); MyPluginModel* model = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) (&model), get_plugin_id(), thread_id ); n = model->exponential; } // Get Plugin Secondary Variable int size = -1; double* U_liq_n_ptr = nullptr; errcode = alfasim_sdk_api.get_plugin_variable( ctx, (void**) &U_liq_n_ptr, "U_liq_n", 0, // Global Scope TimestepScope::CURRENT, &size); if (errcode != 0) { std::cout << "get_plugin_variable error = " << errcode << "\n"; return errcode; } // Calculating the 'U_liq' to power of 'n' for (int i = 0; i < size; ++i) { U_liq_n_ptr[i] = std::pow(U_liq[i], n); }; return OK; }
The image below illustrates the output from the solver, when running the plugin created in this section with the given network.
After reading the quick start section and the plugin by example section, check out these additional resources to help better understand the plugins infrastructure:
As mentioned in Quick Start, the ALFAsim-SDK package has some utilities to help in the process to create a new plugin project and to create a plugin file.
At any moment, it is possible to invoke the help command to list all commands available.
help
You can also learn about the available options of each command invoking the –help option for each command:
>>> alfasim-sdk template --help >>> alfasim-sdk package --help >>> alfasim-sdk compile --help
Generate a template with the necessary files and structure to create a plugin.
The template folder will be placed on the dst option, that by default is the current directory from where the command was invoked.
dst
The files generated and their contents are ready to be used or customized and have the following structure:
alfasim-sdk template [OPTIONS]
Options
--dst
<dst>
A path to where the plugin project should be created. Default: Current directory
--caption
<caption>
Caption to be used across the application to identify the plugin
--plugin-id
<plugin_id>
The name of the plugin
--author-name
<author_name>
Name of the plugin author, this value is stored in plugin metadata and not displayed on the application explicitly
--author-email
<author_email>
Email of the plugin author, this value is stored in plugin metadata and not displayed on the application explicitly
Creates a new <package-name>.hmplugin file containing all the necessary files.
<package-name>.hmplugin
This command will first invoke the compile command to generate the shared library, and after that, the plugin package will be generated with all the content available from the directory assets and artifacts.
compile
By default, the package command will assume that the plugin project is the current directory and the generated file will be placed also in the current directory.
package
In order to change that, it’s possible to use the options plugin-dir and dst
plugin-dir
alfasim-sdk package [OPTIONS]
--plugin-dir
<plugin_dir>
Path to the plugin directory, where configuration and the shared library is located.
A path to where the output package should be created.
--package-name
<package_name>
Name of the package
Generate a <package_name>.hmplugin file with all the content from the directory assets and artifacts.
<package_name>.hmplugin
By default, the package will be created inside the folder plugin_dir, however, it’s possible to give another path filling the dst argument.
alfasim-sdk package_only [OPTIONS]
Compile the plugin from the given plugin-dir option. When not provided plugin-dir will be the current folder location.
This command basically calls the compile.py informing the location of the header files of alfasim_sdk_api. For more details about the build steps, check the compile.py generated for your plugin project.
alfasim-sdk compile [OPTIONS]
The application hooks allow plugins to add custom models or custom checks in the application. To add an application hook it is necessary to implement the given hook in a python file that is already available on your plugin project folder.
As an example, if the alfasim-sdk template command was created with the name myplugin, the necessary file to be customized will be located on: myplugin ‣ src ‣ python ‣ myplugin.py
alfasim-sdk template
myplugin
Plugin Model
Status Monitor
alfasim_get_data_model_type
This hook allows the creation of models in ALFAsim, models can:
Customize items on ALFAsim application, by adding new components over the Tree.
Hold input data information to be accessed from the solver.
Validate input data or configuration made on ALFAsim, to ensure that the plugin has all configuration necessary to be run successfully.
This hook needs to return a class decorated with one of the following options:
alfasim_sdk.models.container_model()
alfasim_sdk.models.data_model()
The image below shows the locations where a custom model can be inserted implementing the hook.
Location to where the models container_model() or data_model() will be placed. Location to where the inputs fields will be placed.
container_model()
Example 1: The following example shows how to create a new model.
import alfasim_sdk from alfasim_sdk import data_model from alfasim_sdk import Quantity @data_model(icon="", caption="My Plugin") class MyModel: distance = Quantity(value=1, unit="m", caption="Distance") @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModel]
The image below shows the output of example 1 when executing on ALFAsim.
Example 2: This second example shows how to create a new container model.
Notice that when using the container_model() you only need to inform the container class to the alfasim_get_data_model_type() hook
import alfasim_sdk from alfasim_sdk import data_model, container_model from alfasim_sdk import Quantity, String @data_model(icon="", caption="My Child") class ChildModel: distance = Quantity(value=1, unit="m", caption="Distance") @container_model(icon='', caption='My Container', model=ChildModel) class MyModelContainer: my_string = String(value='Initial Value', caption='My String') @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModelContainer]
The image below shows the output of example 2 when executing on ALFAsim.
Example 3: This third example demonstrates that it’s possible to create multiple models within the plugin
import alfasim_sdk from alfasim_sdk import data_model, container_model from alfasim_sdk import Quantity, String @data_model(icon="", caption="My Model") class MyModel: distance = Quantity(value=1, unit="m", caption="Distance") @data_model(icon="", caption="My Child") class ChildModel: distance = Quantity(value=1, unit="m", caption="Distance") @container_model(icon='', caption='My Container', model=ChildModel) class MyModelContainer: my_string = String(value='Initial Value', caption='My String') @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModelContainer, MyModel]
The image below shows the output of example 3 when executing on ALFAsim.
alfasim_get_status
Allows plugins to execute custom checks on ALFAsim. These checks can be used to guarantee the consistency of the data or compatibility with some configuration made on ALFAsim.
The status monitor accepts two types of message:
ErrorMessage():Signalize the application to block the simulation until the error is fixed. WarningMessage():Signalize the application that the user needs to fix this problem, but does not need to block the simulation.
ErrorMessage()
Signalize the application to block the simulation until the error is fixed.
WarningMessage()
Signalize the application that the user needs to fix this problem, but does not need to block the simulation.
When no errors are detected, an empty list must be returned.
The alfasim_get_status will be called for:
Each time a model from the plugin is modified. Each time a Physics options from ALFAsim are modified. Ex.: Hydrodynamic model changed
Each time a model from the plugin is modified.
Each time a Physics options from ALFAsim are modified. Ex.: Hydrodynamic model changed
Physics options
The ctx parameter is provided to retrieve information about the current state of the application and the current value of the models implemented by the user.
ctx
Check out the full documentation of alfasim_sdk.context.Context for more details.
alfasim_sdk.context.Context
The following example shows how to display an ErrorMessage when a Quantity() field does not have the desired value.
import alfasim_sdk from alfasim_sdk import data_model from alfasim_sdk import Quantity from alfasim_sdk import ErrorMessage # Define MyModel used in this plugin @data_model(icon="", caption="My Plugin Model") class MyModel: distance = Quantity( value=1, unit="m", caption="Distance" ) @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModel] # Add status monitor in the plugin @alfasim_sdk.hookimpl def alfasim_get_status(ctx): results = [] distance = ctx.GetModel("MyModel").distance.value if distance < 0: message = f"Distance must be greater than 0, got {distance}" results.append( ErrorMessage( model_name="MyModel", message=message, ) ) return results
For the status monitor above, the application will show the following message when the distance is less than 0:
The solver configuration hooks allow plugins to configure internal settings from ALFAsim. To add a configuration hook it is necessary to implement the given hook in a python file that is already available on your plugin project folder.
As an example, if a plugin was created using alfasim-sdk template command and named as myplugin the necessary file to be customized would be located on: myplugin ‣ src ‣ python ‣ myplugin.py
Additional Variables
Hydrodynamic Model
User Defined Tracers
alfasim_get_additional_variables
Allows plugins to register new additional variables on ALFAsim.
It can be used to store the internal variable from the plugin (on solver), or it can be used to expose as an output to the user in the plot window (on application). To calculate and update the registered variables the Solver hooks described on Update plugin variables section must be implemented.
This method expects to return a list of alfasim_sdk.variables.SecondaryVariable(), for more details checkout the reference section with all details about variables
alfasim_sdk.variables.SecondaryVariable()
Usage example:
from alfasim_sdk import SecondaryVariable from alfasim_sdk import Visibility from alfasim_sdk import Location from alfasim_sdk import Scope @alfasim_sdk.hookimpl def alfasim_get_additional_variables(): return [ SecondaryVariable( name='dummy_variable', caption='Plugin 1', unit='m', visibility=Visibility.Internal, location=Location.Center, multifield_scope=Scope.Global, checked_on_gui_default=True, )]
ALFAsim provides a way to customize the hydrodynamic model available within the application, with the usage of the hook listed below, the plugin can:
Add new fields Add/update phases Add/update layers
Add new fields
Add/update phases
Add/update layers
For each new added field is considered a mass conservation equation and for each new added layer is considered a momentum conservation and an energy conservation equations, depending on the energy model used at ALFAsim.
field
layer
alfasim_configure_fields
Allows plugins to configure new fields to be added in ALFAsim’s hydrodynamic model.
An added field must be associated with:
Phase, defined by AddPhase or UpdatePhase. Layer, defined by AddLayer or UpdateLayer.
Phase, defined by AddPhase or UpdatePhase.
AddPhase
UpdatePhase
Layer, defined by AddLayer or UpdateLayer.
AddLayer
UpdateLayer
Example of usage:
@alfasim_sdk.hookimpl def alfasim_configure_fields(): return [ AddField(name='plugin_continuous_field'), AddField(name='plugin_dispersed_field'), ]
alfasim_configure_phases
Allows plugins to configure new phases or associate a new field with a existing phase from the application. In order to configure a new phase it is necessary to return an AddPhase object defining the required fields.
@alfasim_sdk.hookimpl def alfasim_configure_phases(): return [ AddPhase( name='plugin_phase', fields=[ 'plugin_continuous_field', 'plugin_dispersed_field', ], primary_field='plugin_continuous_field', is_solid=False, ) ]
With this new phase, all existing hydrodynamic models from the application will have this additional phase. Notice that the fields parameter must be a field registered from the hook alfasim_configure_fields().
fields
alfasim_configure_fields()
You can restrict the operation of your plugin in the application to certain settings by using the status monitor. For example, if your plugin does not work with the water phase you can block the simulation if the user is using a hydrodynamic model with water.
For more details check out the documentation of alfasim_get_status()
alfasim_get_status()
The image below shows the new added phase on the application.
It is also possible to add additional fields to existent phases using the UpdatePhase.
@alfasim_sdk.hookimpl def alfasim_configure_phases(): return [ UpdatePhase( name=OIL_PHASE, additional_fields=['plugin_dispersed_field'], ) ]
alfasim_configure_layers
Allows plugins to configure new layers or associate a new field with a existing layer for ALFAsim’s hydrodynamic model
In order to configure a new layer, it is necessary to return an AddLayer object defining the required fields.
@alfasim_sdk.hookimpl def alfasim_configure_layers(): return [ AddLayer( name='plugin_layer', fields=['plugin_continuous_field'], continuous_field='plugin_continuous_field', ), UpdateLayer( name=OIL_LAYER, additional_fields=['plugin_dispersed_field'], ), ]
In order to complement the Hydrodynamic model customization, it is possible to inform ALFAsim which phases (added from plugin or not) will have the state variables calculated by plugin.
Hydrodynamic model
alfasim_get_phase_properties_calculated_from_plugin
Allows the plugin to calculate the properties (state variables) of a phase.
Must return a list of phase names in which state variables will be computed for. If the plugin implements this hook four C/C++ Solver hooks also must be implemented. They are:
HOOK_INITIALIZE_STATE_VARIABLE_CALCULATOR HOOK_CALCULATE_STATE_VARIABLE HOOK_CALCULATE_PHASE_PAIR_STATE_VARIABLE HOOK_FINALIZE_STATE_VARIABLE_CALCULATOR
HOOK_INITIALIZE_STATE_VARIABLE_CALCULATOR
HOOK_CALCULATE_STATE_VARIABLE
HOOK_CALCULATE_PHASE_PAIR_STATE_VARIABLE
HOOK_FINALIZE_STATE_VARIABLE_CALCULATOR
The first and last hooks are called immediately before and after the state variables are calculated, respectively.
from alfasim_sdk import GAS_PHASE @alfasim_sdk.hookimpl def alfasim_get_phase_properties_calculated_from_plugin(): return [GAS_PHASE, 'solid']
alfasim_get_phase_interaction_properties_calculated_from_plugin
Allows the plugin to calculate the properties that are related to a pair of phases, like surface tension.
Must return a list of tuple of phases in which state variables will be computed for. In order to implement the properties, HOOK_CALCULATE_PHASE_PAIR_STATE_VARIABLE must be implemented on the C/C++ part of the plugin.
from alfasim_sdk import GAS_PHASE, OIL_PHASE, WATER_PHASE @alfasim_sdk.hookimpl def alfasim_get_phase_interaction_properties_calculated_from_plugin(): return [ (GAS_PHASE, OIL_PHASE), (GAS_PHASE, WATER_PHASE), ]
Warning
This is advanced customization. We strongly encourage the plugin developer to read the Tracers chapter of ALFAsim’s Technical Report available on the Help menu at ALFAsim application.
alfasim_get_user_defined_tracers_from_plugin
Allows the plugin to add new tracers in the ALFAsim’s Tracer Solver, in which the transport equation will be modified by Solver hooks listed below.
Must return a list of tracers in which the internal tracer model hooks will be implemented. The following C/C++ Solver hooks must be implemented:
HOOK_INITIALIZE_MASS_FRACTION_OF_TRACER HOOK_COMPUTE_MASS_FRACTION_OF_TRACER_IN_PHASE HOOK_COMPUTE_MASS_FRACTION_OF_TRACER_IN_FIELD HOOK_SET_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER HOOK_UPDATE_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER
HOOK_INITIALIZE_MASS_FRACTION_OF_TRACER
HOOK_COMPUTE_MASS_FRACTION_OF_TRACER_IN_PHASE
HOOK_COMPUTE_MASS_FRACTION_OF_TRACER_IN_FIELD
HOOK_SET_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER
HOOK_UPDATE_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER
@alfasim_sdk.hookimpl def alfasim_get_user_defined_tracers_from_plugin(): return ['my_tracer']
The tracer added in the user-defined tracers from plugin list will not be considered as a standard tracer, which has an output of its mass fraction and appears in the tracer container at ALFAsim’s User Interface. The user-defined tracer is hidden (does not appear in the User Interface) and the plugin developer can modify the transport equation to use its results internally. However, the user-defined tracers will be solved together with the standard tracers (Added via User Interface).
The present section describes all solver Hooks available on ALFAsim plugin infrastructure. Solver Hooks are ALFAsim’s pre-defined functions that allows the plugin developer to modify/extend ALFAsim’s Solver. As already informed in Quick Start section once created a plugin using template option on ALFAsim-SDK’s CLI a new file named plugin.c will be available to implement those hooks.
template
plugin.c
There is no need to implement all solver hooks in the plugin. It depends on which functionality the developer wants to extend in the ALFAsim model.
In order to help the developer to decide which hooks to implement in the plugin, they are shown below according to their classification which identifies what part of the solver workflow is related to.
To better visualize the interaction of the hooks with the solver, the Simulator WorkFlow chapter has several graphs illustrating the solver’s walkthrough, showing where each hook will be called. The following graph is the same one available at Main Overview section from Simulator WorkFlow. It illustrates where the HOOK_INITIALIZE and the HOOK_FINALIZE will be called.
digraph { nodesep = 0.6; newrank=true node [fillcolor="#FAAC2C" style="rounded, filled" color="#FAAC2C" fontcolor="#ffffff"] edge [color="#8699A3" fontcolor="#2c3e50"] init [label="Initialize Simulation"] end [label="End of Simulation"] node [shape=point, width=0] invisible_point hook_initialize_point [peripheries="2"] hook_finalize_point [peripheries="2"] time [fixedsize=true, label="Time Step", width="1.0", shape="circle"]; decision [label="Final \n Time?", shape="diamond", fixedsize=true, width=2.0, height=1.0, labelcolor="#8699A3", style="filled"] node[shape="rectangular", target="_top"] config [label="Solver Configuration"] hyd_solver [label="Hydrodynamic Solver", URL="../07_workflow.html#hydrodynamic-solver"] tracer_solver [label="Tracer Solver" URL="../07_workflow.html#tracer-solver"] output [label="Output Variables"] node[peripheries="0" shape="cds", color="#DA5961", fontcolor="#DA5961", style=""] hook_initialize [ label="HOOK_INITIALIZE", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.initialize"] hook_finalize [label="HOOK_FINALIZE", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.finalize"] {rank = same; hook_initialize_point; hook_initialize} {rank = same; hook_finalize_point; hook_finalize; } {rank=same; time;tracer_solver} {rank=same; invisible_point;hyd_solver} init -> config; config -> hook_initialize_point [arrowhead= none]; hook_initialize_point -> invisible_point [arrowhead=none]; hook_initialize_point -> hook_initialize [style=dotted, color="#DA5961"]; subgraph cluster_a{ label="Transient Solver" style="dashed, rounded" shape="reactangular" color="#8699A3" fontcolor="#2c3e50" labeljust="l" invisible_point -> time; time:ne -> hyd_solver:w [style=dashed]; hyd_solver -> tracer_solver [weight=1000]; tracer_solver -> output [weight=1000]; output:nw -> time:se [style=dashed]; time:s -> decision:n [weight=10]; decision:w -> time:sw [label="No"]; } decision -> hook_finalize_point [arrowhead= none, label="Yes"]; hook_finalize_point -> hook_finalize [style=dotted, color="#DA5961"]; hook_finalize_point -> end; }
Initial configuration and plugin internal data
Update plugin variables
Source Terms
State Variables for additional phases
Additional solid phase
Internal deposit layer
Unit Cell Model (UCM) Friction Factor
In the User Interface Hooks section is explained that the plugins are allowed to customize the ALFAsim’s user interface extending it in order to get some input data from the user. Using the solver HOOK_INITIALIZE the developer can obtain the input data from user interface and use it to initialize the plugin internal data.
As already mentioned, it is allowed that the plugins have internal data, in which can hold some important information that will be used during the simulation, and also by other hooks.
The plugin internal data will be hold by ALFAsim’s solver, however the plugin has full responsibility to allocate and deallocate its data from memory.
initialize
c++ signature : HOOK_INITIALIZE(void* ctx)
HOOK_INITIALIZE(void* ctx)
This hook allows the plugin to initialize its internal data and also some simulator configurations available via API. If any API function is used the ALFAsim-SDK API must be loaded, see ALFAsim-SDK API Loading section for more information.
ctx – ALFAsim’s plugins context
Return OK if successful or anything different if failed
Examples of usage:
A minimal HOOK_INITIALIZE needed could be:
1 2 3 4 5 6 7 8 9 10 11
ALFAsimSDK_API alfasim_sdk_api; HOOK_INITIALIZE(ctx) { const char* plugin_id = get_plugin_id() // Loading ALFAsim-SDK API int load_error_code = alfasim_sdk_open(alfasim_sdk_api) if (load_error_code != 0){ return load_error_code; } return OK; }
Where OK is an error_code value and get_plugin_id() function is created automatically to each plugin template and accessible from hook_specs.h file. As can be seen in the example above at least the ALFAsim-SDK API should be loaded.
OK
error_code
get_plugin_id()
hook_specs.h
ALFAsim-SDK
However, if the plugin has internal data the minimal HOOK_INITIALIZE implementation would be
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
ALFAsimSDK_API alfasim_sdk_api; HOOK_INITIALIZE(ctx) { const char* plugin_id = get_plugin_id() // Loading ALFAsim-SDK API int load_error_code = alfasim_sdk_open(alfasim_sdk_api) if (load_error_code != 0){ return load_error_code; } // Threads Information int n_threads = -1; int errcode = alfasim_sdk_api.get_number_of_threads( ctx, &n_threads); if (errcode != 0){ return errcode; } // Setting internal data to each thread for (int thread_id = 0; thread_id < n_threads; ++thread_id){ double value; alfasim_sdk_api.get_plugin_input_data_quantity( ctx, &value, plugin_id, thread_id); void* data = new double(value); alfasim_sdk_api.set_plugin_data( ctx, plugin_id, data, thread_id); } return OK; }
It is important to note that void* data at line 22 could be a more complex data structure, like a class object for example.
void* data
As can be seen in the example above the function set_plugin_data() is used to tell the ALFAsim’s solver to hold the plugin internal data.
set_plugin_data()
Since ALFAsim’s solver uses multi-threading to perform all possible parallelizable calculation, it is important that the plugins provide internal data to each thread to avoid data access concurrency problems. As can be seen the HOOK_INITIALIZE example above, a for-loop is performed over the threads to set the plugin internal data. The ALFAsim-SDK API function get_number_of_threads() is used to do it properly. See Plugin Internal Data section for more information.
for-loop
get_number_of_threads()
finalize
c++ signature : HOOK_FINALIZE(void* ctx)
HOOK_FINALIZE(void* ctx)
This Hook must be used to delete all plugin internal data and unload the ALFAsim-SDK API. Otherwise, a memory leak could occur from your plugin.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
HOOK_FINALIZE(ctx) { // Threads information int n_threads = -1; int errcode = alfasim.get_number_of_threads(ctx, &n_threads); f (errcode != 0){ // or errcode != OK return errcode; } const char* plugin_id = get_plugin_id(); // Plugin internal data for (int thread_id = 0; thread_id < n_threads; ++thread_id) { void* data = nullptr; errcode = alfasim.get_plugin_data( ctx, &data, plugin_id, thread_id); delete data; } // Unloading ALFAsim-SDK API int load_error_code = alfasim_sdk_close(alfasim_sdk_api) if (load_error_code != 0){ return load_error_code; } return OK; }
Where OK is an error_code value.
As can be seen in the example above the function get_plugin_data() is used to retrieved the plugin internal data for each thread identified as thread_id.
get_plugin_data()
thread_id
In the examples of usage of both HOOK_INITIALIZE and HOOK_FINALIZE there are many times where an error code is returned (return errcode; or return OK;). As can be seen, it is possible to return error codes from ALFAsim-SDK API functions, however the developer can intercept this error code and handle it instead of returning it to the ALFAsim’s Solver.
return errcode;
return OK;
The hooks described in this section are related to plugin secondary variables that were registered in the python config file, as already explained in Solver Configuration section. They are called secondary variables because they are not obtained from ALFAsim’s Solver, these ones are called primary variables and examples of those variables are pressure, temperature, volume fractions and velocities.
Using the following hooks the plugin is able to calculate/update those variables in three different moments of the simulation step. Two of them are called in the Hydrodynamic Solver scope and the last one is called in the Tracers Solver scope as illustrated on Hydrodynamic Solver and Tracer Solver workflow section. Once the solver obtain results for primary variables, it updates all secondary variables in which depend on primary variables. After that, HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES is called, but if it is running the first time step HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP is called before. It is necessary because usually during the first time step some initialization tasks are needed. Then, if the plugin needs to initialize with some value that is different from the initial nan value, this hook is the place to do that.
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP
nan
Different from plugin internal data, the secondary variables registered by plugins are allocated, deallocated and held by ALFAsim’s Solver. It is necessary because the variables arrays are dependent on network with its discretization and on hydrodynamic model, which defines the fluid flow’s phases, fields and layers.
update_plugins_secondary_variables
c++ signature : HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES(void* ctx)
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES(void* ctx)
Internal simulator hook to update plugin’s secondary variables. This is called as the last step on ALFAsim’s update internal secondary variables workflow.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES(ctx) { int errcode = -1; int size_U = -1; int size_E = -1; int liq_id = -1; errcode = alfasim_sdk_api.get_field_id( ctx, &oil_id, "oil"); double* vel; VariableScope Fields_OnFaces = { GridScope::FACE, MultiFieldDescriptionScope::FIELD, TimestepScope::CURRENT } errcode = alfasim_sdk_api.get_simulation_array( ctx, &vel, (char*) "U", Fields_OnFaces, liq_id, &size_U); double* kinetic_energy; char* name = "kinetic_energy_of_oil"; int global_idx = 0; errcode = alfasim_sdk_api.get_plugin_variable( ctx, (void**) (&kinetic_energy), name, global_idx, TimestepScope::CURRENT, &size_E); if (size_U != size_E){ return OUT_OF_BOUNDS; } for (int i =0; i < size_U; ++i){ kinetic_energy[i] = vel[i] * vel[i] / 2.; } return OK; }
In the example above the variable kinetic_energy_of_oil was registered as a global variable, but its value is obtained for oil field. If this variable would be calculated to all fields then the global_idx would be substituted by field_idx and it would be performed to each field.
kinetic_energy_of_oil
global_idx
field_idx
update_plugins_secondary_variables_on_first_timestep
c++ signature : HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP(void* ctx)
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP(void* ctx)
Internal simulator hook to update plugin’s secondary variables on the first timestep. This is called as the first step on ALFAsim’s update internal variables workflow. This method is specially important when you have a plugin which the secondary variables depend on old values. In the first timestep, there is no old values, so you may use this hook to initialize your variables contents.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP(ctx) { int errcode = -1; int size_E = -1; double* kinetic_energy; char* name = "kinetic_energy_of_oil"; int global_idx = 0; errcode = alfasim_sdk_api.get_plugin_variable( ctx, (void**) (&kinetic_energy), name, global_idx, TimestepScope::CURRENT, &size_E); for (int i =0; i < size_U; ++i){ kinetic_energy[i] = 0.0; } return OK; }
The ALFAsim’s Solver is divided in two non-linear solvers solvers that will solve different group of equations. The first one is the hydrodynamic solver which solves the Mass Conservation of fields, Momentum Conservation of layers and Energy Conservation equations all together for all elements in the network. The second one is the Tracer Solver which solves the Mass Conservation Equation for each added tracer. Since the tracers mass conservation is a transport equation it is solved after hydrodynamic solver and using its results (such as velocities) as input data in the Tracer Solver. See the ALFAsim’s Technical Report for more information.
To complete the group of hooks related to the plugins secondary variables there is the HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER. This hook is used to update plugin’s variables that depends on Tracer’s mass fractions and has to be updated in the Tracer Solver scope.
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER
update_plugins_secondary_variables_on_tracer_solver
c++ signature : HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER(void* ctx)
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER(void* ctx)
Internal simulator hook to update plugin’s secondary variables in the Tracer Solver scope. Tracer Solver is used to solve the tracer transport equation. This is called as the last step on ALFAsim’s Tracer Solver update variables workflow.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER(ctx) { const char* plugin_id = get_plugin_id() int errcode = -1; int size_t = -1; int size_p_var = -1; int liq_id = -1; errcode = alfasim_sdk_api.get_field_id( ctx, &oil_id, "oil"); double* tracer_mass_fraction; VariableScope global_OnCenters = { GridScope::FACE, MultiFieldDescriptionScope::FIELD, TimestepScope::CURRENT } // Tracer information void* tracer_ref; errcode = alfasim_sdk_api.get_tracer_ref_by_name( ctx, &tracer_ref, "my_tracer", // Added by User interface plugin_id); int tracer_id = -1; errcode = alfasim_sdk_api.get_tracer_id( ctx, &tracer_id, tracer_ref); double *tracer_mass_fraction errcode = alfasim_sdk_api.get_simulation_tracer_array( ctx, &tracer_mass_fraction, (char*) "phi", global_OnCenters, tracer_id, 0, // GLOBAL &size_t); // Plugin secondary variable array double* plugin_var; errcode = alfasim_sdk_api.get_plugin_variable( ctx, (void**) (&plugin_var), name, 0, // GLOBAL TimestepScope::CURRENT, &size_p_var); if (size_t != size_p_var){ return OUT_OF_BOUNDS; } for (int i =0; i < size_t; ++i){ // Do some calculations with plugin_var // using tracer_mass_fraction values } return OK; }
Note that functions like get_tracer_ref_by_name(), get_tracer_id() and get_simulation_tracer_array() were used to obtain information related to tracers.
get_tracer_ref_by_name()
get_tracer_id()
get_simulation_tracer_array()
It is important that the plugin developer take care of registered plugin’s secondary variables, since their values will be set equal to nan at first place and it will not be changed by ALFAsim’s Solver at any time during the simulation.
The hooks showed in this section can be considered as the most important. Since they allow the plugin to change the conservation equations. This is achieved by adding source terms in the residual function of mass, momentum and energy conservation equations. Since the equations are in residual form, the negative values of source terms indicate that mass, momentum and energy will be consumed. Otherwise, some amount of mass, momentum, and energy will be generated.
calculate_mass_source_term
c++ signature : HOOK_CALCULATE_MASS_SOURCE_TERM(void* ctx, void* mass_source, int n_fields, int n_control_volumes)
HOOK_CALCULATE_MASS_SOURCE_TERM(void* ctx, void* mass_source, int n_fields, int n_control_volumes)
Internal simulator hook to calculate source terms of mass equation. This is called after all residual functions are evaluated.
The plugin is supposed to change the given mass_source array pointer. Its values are contiguous in memory and the dimensions are given by n_fields and n_control_volumes. It has unit equal to [kg/s].
mass_source
n_fields
n_control_volumes
[kg/s]
mass_source – Source term of mass equation
n_fields – Number of fields
n_control_volumes – Number of control volumes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
HOOK_CALCULATE_MASS_SOURCE_TERM( ctx, mass_source, n_fields, n_control_volumes) { int liq_id = -1; errcode = alfasim_sdk_api.get_field_id( ctx, &oil_id, "oil"); // Convertion from void* to double* and getting the // array range related to oil field double* oil_mass_source = (double*) mass_source + n_control_volumes * liq_id; // Make some calculations and add it to oil_mass_source. // In this example, we add a mass source of 3.1415 kg/s to all control volumes. for (int i = 0; i < n_control_volumes; ++i) { oil_mass_source[i] = 3.1415; // [kg/s] } return OK; }
In the example above is shown how to manage the mass_source array to get the mass source term array related to a specific field (oil field in this case). Note that oil_mass_source has size equal to n_control_volumes.
oil_mass_source
calculate_momentum_source_term
c++ signature : HOOK_CALCULATE_MOMENTUM_SOURCE_TERM(void* ctx, void* momentum_source, int n_layers, int n_faces)
HOOK_CALCULATE_MOMENTUM_SOURCE_TERM(void* ctx, void* momentum_source, int n_layers, int n_faces)
Internal simulator hook to calculate source terms of momentum equation. This is called after all residual functions are evaluated.
The plugin is supposed to change the given momentum_source array pointer. Its values is contiguous in memory and the dimensions are given by n_layers and n_faces. It has unit equal to [N].
momentum_source
n_layers
n_faces
[N]
momentum_source – Source term of momentum equation
n_layers – Number of layers
n_faces – Number of faces (equal to n_control_volumes minus 1)
1 2 3 4 5 6 7 8 9 10 11 12 13
HOOK_CALCULATE_MOMENTUM_SOURCE_TERM( ctx, momentum_source, n_layers, n_faces) { int gas_id = -1; errcode = alfasim_sdk_api.get_layer_id( ctx, &gas_id, "gas"); // Convertion from void* to double* and getting the // array range related to gas layer double* gas_momentum_source = (double*) momentum_source + n_faces * gas_id; // Make some calculations and add it to gas_momentum_source return OK; }
In the example above is shown how to manage the momentum_source array to get the momentum source term array related to a specific layer (gas layer in this case). Note that gas_momentum_source has size equal to n_faces.
gas_momentum_source
calculate_energy_source_term
c++ signature : HOOK_CALCULATE_ENERGY_SOURCE_TERM(void* ctx, void* energy_source, int n_energy_equation, int n_control_volumes)
HOOK_CALCULATE_ENERGY_SOURCE_TERM(void* ctx, void* energy_source, int n_energy_equation, int n_control_volumes)
Internal simulator hook to calculate source terms of energy equation. This is called after all residual functions are evaluated.
The plugin is supposed to change the given energy_source array pointer. Its values is contiguous in memory and the dimensions are given by n_energy_equation and n_control_volumes. It has unit equal to [J/s].
energy_source
n_energy_equation
[J/s]
Since ALFAsim considers two energy models, if n_energy_equation is equal to 1 it means that the global energy model is being used. Otherwise the layers energy model is being used. See the ALFAsim’s Technical Report for more information about the equations system.
ALFAsim
energy_source – Source term of energy equation
n_energy_equation – Number of Energy Equation being solved
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
HOOK_CALCULATE_ENERGY_SOURCE_TERM( ctx, energy_source, n_energy_equation, n_control_volumes) { double* gas_energy_source; if (n_energy_equation > 1){ // Layers Energy model // One energy equation for each layer int gas_id = -1; errcode = alfasim_sdk_api.get_layer_id( ctx, &gas_id, "gas"); // Convertion from void* to double* and getting the // array range related to gas layer gas_energy_source = (double*) energy_source + n_faces * gas_id; } else { // Global energy model // Only one global energy equation // Convertion from void* to double* gas_energy_source = (double*) energy_source; } // Make some calculations and add it to gas_energy_source return OK; }
In the example above is shown how to manage the energy_source array to get the energy source term array related to a specific layer (gas layer in this case). Note that gas_energy_source has size equal to n_control_volumes.
gas_energy_source
calculate_tracer_source_term
c++ signature : HOOK_CALCULATE_TRACER_SOURCE_TERM(void* ctx, void* phi_source, int n_tracers, int n_control_volumes)
HOOK_CALCULATE_TRACER_SOURCE_TERM(void* ctx, void* phi_source, int n_tracers, int n_control_volumes)
Internal simulator hook to calculate source terms of tracer transport equation. This is called after all residual functions are evaluated.
The plugin is supposed to change the given phi_source array pointer. Its values is contiguous in memory and the dimensions are given by n_tracers and n_control_volumes. It has unit equal to [kg/s].
phi_source
n_tracers
phi_source – Source term of tracers mass equation
n_tracers – Number of tracers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
HOOK_CALCULATE_TRACER_SOURCE_TERM( ctx, phi_source, n_tracers, n_control_volumes) { // Tracer information void* tracer_ref; errcode = alfasim_sdk_api.get_tracer_ref_by_name( ctx, &tracer_ref, "my_tracer", // Added by User interface plugin_id); int tracer_id = -1; errcode = alfasim_sdk_api.get_tracer_id( ctx, &tracer_id, tracer_ref); // Convertion from void* to double* and getting the // array range related to gas layer double* my_tracer_phi_source = (double*) phi_source + n_control_volumes * tracer_id; // Make some calculations and add // it to my_tracer_phi_source return OK; }
In the example above is shown how to manage the phi_source array to get the tracer source term array related to a specific tracer (my_tracer in this case). Note that gas_energy_source has size equal to n_control_volumes.
As can be seen in Hydrodynamic Model section the plugins can add new fields, phases and layers. Also, it is possible to indicate if a phase will have its state variables calculated from plugin implementing the alfasim_get_phase_properties_calculated_from_plugin().
alfasim_get_phase_properties_calculated_from_plugin()
initialize_state_variables_calculator
c++ signature : HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR(void* ctx, void* P, void* T, void* T_mix, int n_control_volumes, int n_layers)
HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR(void* ctx, void* P, void* T, void* T_mix, int n_control_volumes, int n_layers)
Hook for the state variables calculator initialization (internal ALFAsim structure).
At this point, it is possible to pre-calculate and cache any relevant information. Then, for each state variable of the phases in the python configuration file, the hook HOOK_CALCULATE_STATE_VARIABLE is called and return the pre-calculated values.
P – Pressure values array
T – Temperature values array
T_mix – Mixture temperature values array
The P and T_mix have size equal to n_control_volumes. However, T has values contiguous in memory and its dimensions are given by n_layers and n_control_volumes
P
T_mix
T
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR( void* ctx, void* P, void* T, void* T_mix, int n_control_volumes, int n_layers) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } // MyStruct is a developer defined struct to hold // all important information for plugin hooks. MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); // MyFunction is a function implemented by // plugin developer that computes de density data.density = MyFunction(P, T_mix, n_control_volumes); return OK; } // Then, to use the cached value: HOOK_CALCULATE_STATE_VARIABLE( void* ctx, void* P, void* T, int n_control_volumes, i nt n_layers, int phase_id, int property_id, void* output) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); if (phase_id != data.my_added_phase_id) { return OK; } if (property_id == StateVariable::RHO) { for (int i = 0; i < n_control_volumes; ++i) { output[i] = data.density[i]; } } return OK; }
For pre-calculated values, the plugin developer must cache it in the plugin internal data. See the example above.
However, if the state variable is considered constant or the developer doesn’t need to cache the values, just return OK.
calculate_state_variable
c++ signature : HOOK_CALCULATE_STATE_VARIABLE(void* ctx, void* P, void* T, int n_control_volumes, int n_layers, int phase_id, int property_id, void* output)
HOOK_CALCULATE_STATE_VARIABLE(void* ctx, void* P, void* T, int n_control_volumes, int n_layers, int phase_id, int property_id, void* output)
Hook to calculate the state variable given by the property_id (See StateVariable values), for the phase with phase_id (Note that the phase id is the same as the one retrieved from the get_phase_id() API function - It is not advisable to use hardcoded numbers).
StateVariable
get_phase_id()
List of affected variables: - Density - Viscosity - Heat Capacity - Partial Derivative of Density in Relation to Pressure - Partial Derivative of Density in Relation to Temperature - Enthalpy - Thermal Conductivity
Density
Viscosity
Heat Capacity
Partial Derivative of Density in Relation to Pressure
Partial Derivative of Density in Relation to Temperature
Enthalpy
Thermal Conductivity
n_phase_id – Id of phase in which the property must be calculated
property_id – A StateVariable value. It indicates which property must be calculated
output – Output values array
The output parameter must be filled with the calculated property for each control volume. The pressure P and layer or mixture temperature T (Depending on the energy model being used) are given in order to perform the calculation. The number of control volumes is also given for convenience.
output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
HOOK_CALCULATE_STATE_VARIABLE( void* ctx, void* P, void* T, int n_control_volumes, int n_layers, int phase_id, int property_id, void* output) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); if (phase_id != data.my_added_phase_id) { return OK; } if (property_id == StateVariable::RHO) { for (int i = 0; i < n_control_volumes; ++i) { // If the property has a constant value output[i] = data.constant_density; // If the property must be computed // MyStruct has a function called 'compute_density()' output[i] = data.compute_density( (double *)P[i], (double *)T[i]); } } return OK; }
The plugin developer must NOT change any variable other than the output. The output size is n_control_volumes .
calculate_phase_pair_state_variable
c++ signature : HOOK_CALCULATE_PHASE_PAIR_STATE_VARIABLE(void* ctx, void* P, void* T_mix, int n_control_volumes, int phase1_id, int phase2_id, int property_id, void* output)
HOOK_CALCULATE_PHASE_PAIR_STATE_VARIABLE(void* ctx, void* P, void* T_mix, int n_control_volumes, int phase1_id, int phase2_id, int property_id, void* output)
Hook to calculate the state variable given by the property_id (See :cpp:enum:StateVariable values), for the phase pair (phase1_id, phase2_id) (Note that the phase id is the same as the one retrieved from the get_phase_id() API function - It is not advisable to use hardcoded numbers).
List of affected variables: - Interfacial Tension
Interfacial Tension
n_phase1_id – Id of phase one in which the property must be calculated
n_phase2_id – Id of phase two in which the property must be calculated
The output parameter must be filled with the calculated property for each control volume. The pressure P and mixture temperature T_mix are given in order to perform the calculation. The number of control volumes is also given for convenience.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
HOOK_CALCULATE_PHASE_PAIR_STATE_VARIABLE( void* ctx, void* P, void* T_mix, int n_control_volumes, int phase1_id, int phase2_id, int property_id, void* output) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); int gas_phase_id = -1; errcode = alfasim_sdk_api.get_phase_id( ctx, &gas_phase_id, "gas"); if (( (phase1_id == data.my_added_phase_id) && (phase1_id == gas_phase_id) ) || ( (phase1_id == gas_phase_id) && (phase1_id == data.my_added_phase_id) )) { for (int i = 0; i < n_control_volumes; ++i) { // If the property has a constant value output[i] = data.constant_surface_tension; // If the property must be computed // MyStruct has a function // called 'compute_surface_tension()' output[i] = data.compute_surface_tension( (double *)P[i], (double *)T_mix[i]); } } return OK; }
The plugin developer must NOT change any variable other than the output. The output size is n_control_volumes.
finalize_state_variables_calculator
c++ signature : HOOK_FINALIZE_STATE_VARIABLES_CALCULATOR(void* ctx)
HOOK_FINALIZE_STATE_VARIABLES_CALCULATOR(void* ctx)
Hook for the state variables calculator finalization. The plugin developer should free/delete any allocated data from the HOOK_INITIALIZE_STATE_VARIABLE_CALCULATOR.
If there is no need memory deallocation a minimal implementation would be:
1 2 3 4
HOOK_FINALIZE_STATE_VARIABLES_CALCULATOR(void* ctx) { return OK; }
When a new phase is added to the hydrodynamic model using the AddPhase type, it is possible to set as a solid phase. In this case, the particle size of fields that are solid phase can be calculated by implementing the following Solver Hooks.Otherwise, the particle size will be considered constant and equal to \(1\times10^{-4}\) meters.
initialize_particle_diameter_of_solids_fields
c++ signature : HOOK_INITIALIZE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS(void* ctx, void* particle_diameter, int n_control_volumes, int solids_field_id)
HOOK_INITIALIZE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS(void* ctx, void* particle_diameter, int n_control_volumes, int solids_field_id)
Internal simulator hook to initialize particle diameter of solid fields. This hook follows the same idea of HOOK_UPDATE_PLUGIN_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP, which makes the initialization in the moment that there is no previous time step data available.
HOOK_UPDATE_PLUGIN_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP
particle_diameter – Particle diameter of a given solid field,
n_control_volumes – Number of control volumes,
solid_field_id – Index of the solid field in which the particle_diameter Should be calculated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
HOOK_INITIALIZE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS( void* ctx, void* particle_diameter, int n_control_volumes, int solids_field_id) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); if (solids_field_id != data.my_added_solid_field_id) { return OK; } else { for (int i = 0; i < n_control_volumes; ++i) { // If the particle size is constant output[i] = data.constant_particle_size; // The value is calculated // MyStruct has a function // called 'initial_particle_size()' output[i] = data.initial_particle_size( // List of params that can be // retrieved by get_simulation_array() ); } } return OK; }
update_particle_diameter_of_solids_fields
c++ signature : HOOK_UPDATE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS(void* ctx, void* particle_diameter, int n_control_volumes, int solids_field_id)
HOOK_UPDATE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS(void* ctx, void* particle_diameter, int n_control_volumes, int solids_field_id)
Internal simulator hook to update/calculate particle diameter of solid fields. It is called right before any update secondary variable from ALFAsim’s Solver, because they may depend on the solids particle size (for example Slurry Viscosity calculated by Solids Model)
Solids Model
HOOK_UPDATE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS( void* ctx, void* particle_diameter, int n_control_volumes, int solids_field_id) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); if (solids_field_id != data.my_added_solid_field_id) { return OK; } else { for (int i = 0; i < n_control_volumes; ++i) { // If the particle size is constant output[i] = data.constant_particle_size; // The value is calculated // MyStruct has a function // called 'compute_particle_size()' output[i] = data.compute_particle_size( // List of params that can be // retrieved by get_simulation_array() ); } } return OK; }
When a new phase is added to the hydrodynamic model using the AddPhase type, it is possible to consider the deposition inside the pipeline walls. If so, calculate the thickness of the deposited layer on a given phase through the usage of update_internal_deposition_layer(). By default, the layer thickness will be considered equal to zero meters.
update_internal_deposition_layer()
update_internal_deposition_layer
c++ signature : HOOK_UPDATE_INTERNAL_DEPOSITION_LAYER(void* ctx, void* thickness, void* density, void* heat_capacity, void* thermal_conductivity, int n_control_volumes)
HOOK_UPDATE_INTERNAL_DEPOSITION_LAYER(void* ctx, void* thickness, void* density, void* heat_capacity, void* thermal_conductivity, int n_control_volumes)
Internal simulator hook to evaluate the thickness and thermal properties of the deposited layer at the inside of the pipeline walls. This is called for accounting the diameter reduction and wall thermal effects.
The plugin is supposed to change the given thickness, density, heat_capacity, thermal_conductivity array pointers. Its values are contiguous in memory and the dimension is given by n_control_volumes. It has unit equal to [m].
thickness
density
heat_capacity
thermal_conductivity
[m]
thickness – Thickness of the internal deposit layer
density – Density of the internal deposit layer [kg/m3]
heat_capacity – Heat capacity of the internal deposit layer [J/(kg.K)]
thermal_conductivity – Thermal conductivity of the internal deposit layer [W/(m.K)]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
HOOK_UPDATE_INTERNAL_DEPOSITION_LAYER( ctx, thickness, density, heat_capacity, thermal_conductivity, n_control_volumes) { auto errcode = -1; double dt = -1.0; errcode = alfasim.get_simulation_quantity( ctx, &dt, TimestepScope::CURRENT, (char*) "dt"); if (errcode != 0) { return errcode; } // Handle first time step, because you won't have the previously information double current_time = -1.0; errcode = alfasim.get_simulation_quantity( ctx, ¤t_time, TimestepScope::CURRENT, (char*) "time"); if (errcode != 0) { return errcode; } double wax_density = 900.0 // [kg/m3] double wax_heat_capacity = 2140.0 // [J/(kg.K)] double wax_thermal_conductivity = 0.25 // [W/(m.K)] if (current_time == 0.0){ // Set a value for the deposition layer thickness for (int i = 0; i < n_control_volumes; ++i) { (double*) thickness[i] = 0.0; // [m] (double*) density[i] = wax_density; // [kg/m3] (double*) heat_capacity[i] = wax_heat_capacity; // [J/(kg.K)] (double*) thermal_conductivity[i] = wax_thermal_conductivity; // [W/(m.K)] } } else{ // Get previously deposition layer thickness to obtain the current void* thickness_old_raw_ptr; errcode = alfasim.get_plugin_variable( ctx, &thickness_old_raw_ptr, "thickness", 0, TimestepScope::PREVIOUS, &size); if (errcode != 0) { return errcode; } auto* thickness_old = (double*) (thickness_old_raw_ptr); // Calculate the variation of the deposition layer in one time step double* d_deposit_layer_dt = 0.0001; // [m/s] // Sum this variation with the thickness of the older time step for (int i = 0; i < n_control_volumes; ++i) { (double*) thickness[i] = thickness_old[i] + d_deposit_layer_dt * dt; // [m] (double*) density[i] = wax_density; // [kg/m3] (double*) heat_capacity[i] = wax_heat_capacity; // [J/(kg.K)] (double*) thermal_conductivity[i] = wax_thermal_conductivity; // [W/(m.K)] } } return OK; }
In the example above is shown how to manage the thickness, density, heat_capacity and thermal_conductivity arrays for each control volume. Note that the thickness should be always the total value for that time step, so the first time step should be handle in a separately way, since there is no previously information.
When the Unit Cell Model is used in ALFAsim simulation any plugin can implement your own friction factor correlation. For that, two hooks MUST be implemented, one for stratified flow and one for annular flow. Both of them must be implemented because the ALFAsim’s Solver will call them depending on which flow pattern the fluid flow is in the control volume.
It is important to know that the main input variables needed to compute the friction factor is available in the API function get_ucm_friction_factor_input_variable(). Note that, the variables listed in the documentation of the cited function are related to one control volume, in which the Unit Cell Model is applied.
get_ucm_friction_factor_input_variable()
calculate_ucm_friction_factor_stratified
c++ signature : HOOK_CALCULATE_UCM_FRICTION_FACTOR_STRATIFIED(void* ctx, double* ff_wG, double* ff_wL, double* ff_i)
HOOK_CALCULATE_UCM_FRICTION_FACTOR_STRATIFIED(void* ctx, double* ff_wG, double* ff_wL, double* ff_i)
Internal unit cell model hook to calculate the wall and interfacial friction factors for stratified fluid flow pattern. The unit cell model represents a two phase flow with Gas and Liquid Phases. The output variables ff_wG, ff_wL and ff_i are the Gas-Wall friction factor, Liquid-Wall friction factor and interfacial Gas-Liquid friction factor, respectively.
ff_wG
ff_wL
ff_i
This hook allows the developer to implement your own correlation for friction factor in a stratified flow.
ff_wG – Gas-Wall Friction Factor
ff_wL – Liquid-Wall Friction Factor
ff_i – Interfacial Gas-Liquid Friction Factor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
int HOOK_CALCULATE_UCM_FRICTION_FACTOR_STRATIFIED( void* ctx, double* ff_wG, double* ff_wL, double* ff_i) { int errcode = -1; int G = TwoPhaseSystem::GAS int L = TwoPhaseSystem::LIQUID // Getting friction factor input data from context double alpha[2]; errcode = alfasim_sdk_api.get_ucm_friction_factor_input_variable( ctx, &alpha[G], "alpha", TwoPhaseSystem::GAS); if (errcode != OK){ return errcode; } errcode = alfasim_plugins_api.get_ucm_friction_factor_input_variable( ctx, &alpha[L], "alpha", TwoPhaseSystem::LIQUID); if (errcode != OK){ return errcode; } // And so on to each friction factor input variable // U(velocities), rho(densities), mu(viscosities) and D(pipe diameter) // Getting the fluid geometrical properties double S_w[2]; double S_i; double H[2]; errcode = alfasim_sdk_api.get_ucm_fluid_geometrical_properties( ctx, S_w, &S_i, H, alpha[G], D); if (errcode != OK){ return errcode; } // Compute the friction factors using your own correlation. // Also, using the variables: alpha, U, rho, mu, D, S_w, S_i and H *ff_wG = gas_wall_ff; *ff_wL = liq_wall_ff; *ff_i = gas_liq_ff; return OK; }
calculate_ucm_friction_factor_annular
c++ signature : HOOK_CALCULATE_UCM_FRICTION_FACTOR_ANNULAR(void* ctx, double* ff_wG, double* ff_wL, double* ff_i)
HOOK_CALCULATE_UCM_FRICTION_FACTOR_ANNULAR(void* ctx, double* ff_wG, double* ff_wL, double* ff_i)
Internal unit cell model hook to calculate the wall and interfacial friction factors for annular fluid flow pattern. The unit cell model represents a two phase flow with Gas and Liquid Phases. The output variables ff_wG, ff_wL and ff_i are the Gas-Wall friction factor, Liquid-Wall friction factor and interfacial Gas-Liquid friction factor, respectively.
This hook allows the developer to implement your own correlation for friction factor in a annular flow.
The same example presented in HOOK_CALCULATE_UCM_FRICTION_FACTOR_STRATIFIED can be used, just change the hook name to HOOK_CALCULATE_UCM_FRICTION_FACTOR_ANNULAR.
HOOK_CALCULATE_UCM_FRICTION_FACTOR_STRATIFIED
Another important API function for UCM is get_ucm_fluid_geometrical_properties(). This function computes the geometrical properties properly in each previous presented hooks depending on the flow pattern.
get_ucm_fluid_geometrical_properties()
The hooks described in this section must be implemented when at least one user defined tracer is added via alfasim_get_user_defined_tracers_from_plugin() hook.
alfasim_get_user_defined_tracers_from_plugin()
These hooks can modify the tracer transport equation from the initialization to configuration of boundary conditions. The plugin developer has complete freedom to change the equations, however it is important to be aware that it can be made manipulating the transport equation terms inside the hooks. For that, it is important to read the Tracers Chapter at ALFAsim’s Technical Manual.
initialize_mass_fraction_of_tracer
c++ signature : HOOK_INITIALIZE_MASS_FRACTION_OF_TRACER(void* ctx, void* phi_initial, int tracer_index)
HOOK_INITIALIZE_MASS_FRACTION_OF_TRACER(void* ctx, void* phi_initial, int tracer_index)
Internal tracer model Hook to initialize the mass fraction of tracer, given by tracer_id, in the entire network. The output variable phi_initial is the initial mass fraction of the given tracer in respect to the mass of the mixture.
phi_initial – Initial mass fraction of tracer in respect to the mass of the mixture
tracer_index – Tracer ID
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
HOOK_INITIALIZE_MASS_FRACTION_OF_TRACER( void* ctx, void* phi_initial, int tracer_index) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); if (tracer_index != data.my_user_defined_tracer_id) { return OK; } else { // Set a initial value to the tracer mass fraction // phi_initial has size equal to 1 *static_cast<double*>(phi_initial) = 0.0; } return OK; }
calculate_mass_fraction_of_tracer_in_phase
c++ signature : HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_PHASE(void* ctx, void* phi, void* phi_phase, int tracer_index, int phase_index, int n_control_volumes)
HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_PHASE(void* ctx, void* phi, void* phi_phase, int tracer_index, int phase_index, int n_control_volumes)
Internal tracer model Hook to calculate the mass fraction of tracer, given by tracer_index, in phase, given by phase_index. The input variable phi is the mass fraction of the given tracer in respect to the mass of the mixture. The output variable phi_phase is the mass fraction of the given tracer in respect to the mass of the given phase. Both phi and phi_phase have size equal to n_control_volumes.
tracer_index
phase_index
phi
phi_phase
phi – Array of mass fraction of tracer in respect to the mass of the mixture
phi_phase – Array of mass fraction of tracer in respect to the mass of the phase given by phase_index
phase_index – Phase ID
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_PHASE( void* ctx, void* phi, void* phi_phase, int tracer_index, int phase_index, int n_control_volumes) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); // Casting to double pointer double* phi_ptr = static_cast<double*>(phi); double* phi_phase_ptr = static_cast<double*>(phi_phase); // Check if the tracer_index was added by this plugin if (tracer_index != data.my_user_defined_tracer_id){ return OK } // Let suppose that this tracer is only in the gas phase if(phase_index != data.gas_id) { for (int i = 0; i < n_control_volumes; ++i) { phi_phase_ptr[i] = 0.0; } } else { // Calculate and set the Phi_phase value for (int i = 0; i < n_control_volumes; ++i) { phi_phase_ptr[i] = data.calculate_mass_fraction_of_tracer_in_gas( phi_ptr[i], // List of params that can be // retrieved by get_simulation_array() ); } } return OK; }
The plugin developer must NOT change phi variable, only the output variable phi_phase.
calculate_mass_fraction_of_tracer_in_field
c++ signature : HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_FIELD(void* ctx, void* phi_phase, void* phi_field, int tracer_index, int field_index, int phase_index_of_field, int n_control_volumes)
HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_FIELD(void* ctx, void* phi_phase, void* phi_field, int tracer_index, int field_index, int phase_index_of_field, int n_control_volumes)
Internal tracer model Hook to calculate the mass fraction of tracer, given by tracer_index, in field, given by field_index. The input variable phi_phase is the mass fraction of the given tracer in respect to the mass of the given phase, in which the ID is phase_index_of_field. The output variable phi_field is the mass fraction of the given tracer in respect to the mass of the given field. Both phi_phase and phi_field have size equal to n_control_volumes.
field_index
phi_field
phi_phase – Array of mass fraction of tracer in respect to the mass of the phase given by phase_index_of_field
phi_field – Array of mass fraction of tracer in respect to the mass of the field given by field_index
field_index – Field ID
phase_index_of_field – Phase ID of field
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_FIELD( void* ctx, void* phi_phase, void* phi_field, int tracer_index, int field_index, int phase_index_of_field, int n_control_volumes) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); // Casting to double pointer double* phi_phase_ptr = static_cast<double*>(phi_phase); double* phi_field_ptr = static_cast<double*>(phi_field); // Check if the tracer_index was added by this plugin if (tracer_index != data.my_user_defined_tracer_id){ return OK } // Let suppose that this tracer is only in the gas phase if(phase_index_of_field != data.gas_phase_id) { for (int i = 0; i < n_control_volumes; ++i) { phi_field_ptr[i] = 0.0; } } else { // Calculate and set the Phi_field value for (int i = 0; i < n_control_volumes; ++i) { phi_field_ptr[i] = data.mass_fraction_of_tracer_in_gas_fields( phi_phase_ptr[i], // List of params that can be // retrieved by get_simulation_array() ); } } return OK; }
The plugin developer must NOT change phi_phase variable, only the output variable phi_field.
set_prescribed_boundary_condition_of_mass_fraction_of_tracer
c++ signature : HOOK_SET_PRESCRIBED_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER(void* ctx, void* phi_presc, int tracer_index)
HOOK_SET_PRESCRIBED_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER(void* ctx, void* phi_presc, int tracer_index)
Internal tracer model hook to set the initial prescribed boundary condition of mass fraction of tracer, given by tracer_index`. The output variable ``phi_presc is the prescribed mass fraction of the given tracer in respect to the mass of the mixture. Note that all boundary nodes will be populated with phi_presc value set by this hook.
tracer_index`. The output variable ``phi_presc
Please note that this hook sets the first mass fraction related boundary conditions value to the user defined tracer. However the hook HOOK_UPDATE_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER allows the plugin developer to update this value.
phi_presc – Prescribed mass fraction of tracer
HOOK_SET_PRESCRIBED_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER( void* ctx, void* phi_presc, int tracer_index) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); if (tracer_index != data.my_user_defined_tracer_id) { return OK; } else { // Set a initial boundary condition // to the tracer mass fraction. // phi_presc has size equal to 1. *static_cast<double*>(phi_presc) = 0.0; } return OK; }
update_boundary_condition_of_mass_fraction_of_tracer
c++ signature : HOOK_UPDATE_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER(void* ctx, void* phi_presc, void* phi_field, int tracer_index, void* vol_frac_bound, int n_fields)
HOOK_UPDATE_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER(void* ctx, void* phi_presc, void* phi_field, int tracer_index, void* vol_frac_bound, int n_fields)
Internal tracer model hook to update the prescribed mass fraction of tracer, given by tracer_id. The output variable phi_presc is the prescribed mass fraction of the given tracer in respect to the mass of the mixture. The vol_frac_bound is the volume fraction of fields at the boundary in which the phi_presc is being calculated.
tracer_id
phi_presc
vol_frac_bound
This hook allows the developer to update the boundary conditions of mass fraction that may depend on ALFAsim’s internal variables that may change during the simulation. So, this update will be performed to each time step.
vol_frac_bound – Volume fraction of fields in the boundary
HOOK_UPDATE_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER( void* ctx, void* phi_presc, int tracer_index) { // getting plugin internal data int errcode = -1; int thread_id = -1; errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); if (errcode != OK) { return errcode; } MyStruct* data = nullptr; errcode = alfasim_sdk_api.get_plugin_data( ctx, (void**) &data, plugin_id, thread_id); // Casting to double pointer double* phi_presc_ptr = static_cast<double*>(phi_presc); double* vol_frac_bound_ptr = static_cast<double*>(vol_frac_bound); // Let suppose that this tracer is only in the gas field if (tracer_index != data.my_user_defined_tracer_id) { return OK; } else { // Update the boundary condition // to the tracer mass fraction. phi_presc_ptr = data.calc_bc_mass_fraction_of_tracer_in_gas_field( vol_frac_bound_ptr[data.continuous_gas_field_id], // List of params that can be // retrieved by get_simulation_array() ); } return OK; }
The plugin developer must NOT change vol_frac_bound variable, only the output variable phi_presc.
Dig deeper into specific topics:
Here are shown some graphs of the ALFAsim simulator workflow. In those graphs, it is possible to identify when the Solver Hooks are called during the simulation. Some of them, like Hydrodynamic Solver and Tracer Solver, have their graphs expanded to make it possible to see more internal hooks.
digraph { nodesep = 0.6; newrank=true; node [fillcolor="#FAAC2C", style="rounded, filled", color="#FAAC2C", fontcolor="#ffffff", target="_top"] edge [color="#8699A3", fontcolor="#2c3e50"] hydrodynamic_1 [label="Primary Variables \n (Solver Unknowns)"] hydrodynamic_2 [label="Calculate \n State Variables" URL="../07_workflow.html#state-variable-calculator"] hydrodynamic_3 [label="Calculate \n Secondary Variables"] hydrodynamic_4 [label="Calculate \n Source Terms"] invisible_init [shape=point, style=invis] invisible_end [shape=point, style=invis] hook_update_variables_point [shape = point, width = 0, peripheries="2"] hook_calculate_source_terms_point [shape = point, width = 0, peripheries="2" ] // Align Hooks node[peripheries="0", shape="cds", color="#DA5961", fontcolor="#DA5961", style=""] hook_update_variables [label="HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.update_plugins_secondary_variables"] hook_calculate_mass_source_terms [label="HOOK_CALCULATE_MASS_SOURCE_TERM", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.calculate_mass_source_term"] hook_calculate_momentum_source_terms [label="HOOK_CALCULATE_MOMENTUM_SOURCE_TERM", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.calculate_momentum_source_term"] hook_calculate_energy_source_terms [label="HOOK_CALCULATE_ENERGY_SOURCE_TERM", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.calculate_energy_source_term"] {rank = same; hook_update_variables_point; hook_update_variables } {rank = same; hook_calculate_source_terms_point; hook_calculate_momentum_source_terms; } invisible_init -> hydrodynamic_1 hook_calculate_source_terms_point -> invisible_end ; // Align all hooks hook_calculate_mass_source_terms -> hook_calculate_momentum_source_terms -> hook_calculate_energy_source_terms [constraint=true, style=invis] subgraph cluster1{ labeljust="l" style="rounded, dashed" color="#8699A3" hydrodynamic_1 -> hydrodynamic_2 -> hydrodynamic_3 hydrodynamic_3 -> hook_update_variables_point [arrowhead=none, ltail=cluster1] hook_update_variables_point -> hydrodynamic_4 hydrodynamic_4 -> hook_calculate_source_terms_point [arrowhead=none] } hook_update_variables_point -> hook_update_variables [constraint=false, style=dotted, color="#DA5961"] hook_calculate_source_terms_point -> hook_calculate_mass_source_terms:w [constraint=false, style=dotted, color="#DA5961"] hook_calculate_source_terms_point -> hook_calculate_momentum_source_terms [constraint=false, style=dotted, color="#DA5961"] hook_calculate_source_terms_point -> hook_calculate_energy_source_terms:w [constraint=false, style=dotted, color="#DA5961"] // Align Notes subgraph cluster2{ labeljust="l" style="rounded, dashed" fontcolor="#2c3e50" color="#8699A3" node[shape=box, color="#FAAC2C",fillcolor="#FFFFFF", fontcolor="#FAAC2C", peripheries="1" shape="rectangular"] note_1 [label="α, P, U, T"] note_2 [label="ρ, μ, Cₚ, ... = ƒ(P,T)"] note_3 [label="Mass Flow Rate, Flow Pattern ..."] } {rank=same; hydrodynamic_1; note_1} {rank=same; hydrodynamic_2; note_2} {rank=same; hydrodynamic_3; note_3} note_1->note_2->note_3[ style = invis ] edge[arrowhead=none, style=dashed, constraint=false,] hydrodynamic_1 -> note_1 hydrodynamic_2 -> note_2 hydrodynamic_3 -> note_3 }
digraph { newrank=true nodesep=0.7 node [fillcolor="#FAAC2C" style="rounded, filled" color="#FAAC2C" fontcolor="#ffffff" shape="rectangular"] edge [ color="#8699A3" fontcolor="#2c3e50" ] node_1 [label="Calculate State Variables \n for ALFAsim Phases"] node_2 [label="Setup"] node_3 [label="Calculate State Variables"] node_4 [label="Calculate Phase Pair \n State Variables \n (Surface Tension)"] node_5 [label="Finalize"] loop_1 [fixedsize=true, label="Phases Set \n By Plugins", width="1.2", shape="circle"] node [shape=point style=invis width=0] invisible_init invisible_end invisible_1 invisible_2 invisible_3 node[peripheries="0" shape="cds", color="#DA5961", fontcolor="#DA5961" , style="" target="_top" fontsize=10] hook_initialize_state_variables_calculator [label=" HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR" URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.initialize_state_variables_calculator"] hook_calculate_state_variable [label=" HOOK_CALCULATE_STATE_VARIABLE", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.calculate_state_variable"] hook_calculate_phase_pair_state_variable [label=" HOOK_CALCULATE_PHASE_PAIR_STATE_VARIABLE", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.calculate_phase_pair_state_variable"] hook_finalize_state_variables_calculator [label=" HOOK_FINALIZE_STATE_VARIABLES_CALCULATOR" URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.finalize_state_variables_calculator"] {rank = same node_2 hook_initialize_state_variables_calculator } {rank = same node_3 hook_calculate_state_variable } {rank = same node_4 hook_calculate_phase_pair_state_variable} {rank = same node_5 hook_finalize_state_variables_calculator } {rank=same loop_1 node_3} invisible_init -> node_1 subgraph cluster1{ label="" labeljust="l" style="rounded, dashed" color="#8699A3" node_2->node_3->node_4->node_5 [weight=9999] loop_1:ne -> node_2:w [style=dashed] node_5:w -> loop_1:se [style=dashed] invisible_1 -> loop_1 [weight=9999] edge[arrowhead=none style=normal] node_1 -> invisible_1 [weight=9999] loop_1 -> invisible_2 invisible_2 -> invisible_3 } invisible_3 -> invisible_end edge[constraint=false, style=dotted, color="#DA5961"] node_2 -> hook_initialize_state_variables_calculator node_3 -> hook_calculate_state_variable node_4 -> hook_calculate_phase_pair_state_variable node_5 -> hook_finalize_state_variables_calculator }
digraph { nodesep = 0.7 newrank=true node [fillcolor="#FAAC2C" style="rounded, filled" color="#FAAC2C" fontcolor="#ffffff" shape="rectangular"] edge [ color="#8699A3" fontcolor="#2c3e50" ] tracer_1 [label="Primary Variables \n (Solver Unknowns, ϕ) "] tracer_2 [label="Calculate \n Secondary Variables"] tracer_3 [label="Calculate \n Source Terms"] invisible_init [shape=point, style=invis] invisible_end [shape=point, style=invis] node[shape = point, width = 0, peripheries="2" ] hook_initialize_user_defined_tracer_point hook_set_bc_user_defined_tracer_point hook_update_variables_point hook_calculate_source_terms_point node[peripheries="0" shape="cds", color="#DA5961", fontcolor="#DA5961" , style="" target="_top" fontsize=10] hook_initialize_user_defined_tracer [label=" HOOK_INITIALIZE_MASS_FRACTION_OF_TRACER" URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.initialize_mass_fraction_of_tracer"] hook_set_bc_user_defined_tracer [label=" HOOK_SET_PRESCRIBED_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.set_prescribed_boundary_condition_of_mass_fraction_of_tracer"] hook_update_variables [label=" HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.update_plugins_secondary_variables_on_tracer_solver"] hook_calculate_tracer_source_terms [label=" HOOK_CALCULATE_TRACER_SOURCE_TERM" URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.calculate_tracer_source_term"] hook_update_bc_user_defined_tracer [label=" HOOK_UPDATE_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER" URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.update_boundary_condition_of_mass_fraction_of_tracer"] hook_calculate_mass_fraction_of_tracer_in_field [label=" HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_FIELD \n HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_PHASE" URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.calculate_mass_fraction_of_tracer_in_phase" ] {rank = same hook_update_variables_point hook_update_variables} {rank = same hook_calculate_source_terms_point hook_calculate_tracer_source_terms } {rank = same hook_initialize_user_defined_tracer_point hook_initialize_user_defined_tracer } {rank = same hook_set_bc_user_defined_tracer_point hook_set_bc_user_defined_tracer } {rank = same tracer_1 hook_update_bc_user_defined_tracer } {rank = same tracer_2 hook_calculate_mass_fraction_of_tracer_in_field} invisible_init -> hook_initialize_user_defined_tracer_point [arrowhead=none] hook_calculate_source_terms_point -> invisible_end subgraph cluster1{ labeljust="l" style="rounded, dashed" color="#8699A3" hook_initialize_user_defined_tracer_point -> hook_set_bc_user_defined_tracer_point [arrowhead=none] hook_set_bc_user_defined_tracer_point-> tracer_1 tracer_1 -> tracer_2 tracer_2 -> hook_update_variables_point [arrowhead=none] hook_update_variables_point -> tracer_3 tracer_3 -> hook_calculate_source_terms_point [arrowhead=none] } edge[constraint=false, style=dotted, color="#DA5961"] subgraph cluster2{ label="Hooks for User Defined Tracers" labeljust="l" fontcolor="#2c3e50" style="rounded, dashed" color="#8699A3" hook_initialize_user_defined_tracer_point -> hook_initialize_user_defined_tracer hook_set_bc_user_defined_tracer_point -> hook_set_bc_user_defined_tracer tracer_1 -> hook_update_bc_user_defined_tracer tracer_2 -> hook_calculate_mass_fraction_of_tracer_in_field } hook_calculate_source_terms_point -> hook_calculate_tracer_source_terms hook_update_variables_point -> hook_update_variables }
This page contains the full reference to ALFAsim-SDK API.
Here is listed the completed API available to implement the Solver Hooks.
Enums
Structs
Functions
ALFAsim-SDK API Loading
Plugin Input Data (From user interface)
Plugin Internal Data
ALFAsim’s Solver Data
Unit Cell Model (UCM) helpers
Variable Name Parsing
It holds the possible returning error code from ALFAsim-SDK-API functions.
Values:
REFERENCE_NOT_SET
Some reference from input data wasn’t set.
UNKNOWN_REFERENCE_TYPE
Reference type is unknown.
OUT_OF_BOUNDS
Index out of array bounds.
UNKNOWN_CONTEXT
The context is unknown.
NOT_AVAILABLE_DATA
Data from ALFAsim is not available.
BUFFER_SIZE_INSUFFICIENT
Buffer size is insufficient.
UNDEFINED_DATA
Plugin internal data is undefined.
NOT_IMPLEMENTED
A feature is not implemented in an API function.
Everything was fine.
GridScope
It holds the variable scope in the grid to retrieve a simulation array.
CENTER
Variable located in the control volume center
FACE
Variable located in the control volume face
MultiFieldDescriptionScope
It holds the variable scope in the Multifield description (phases/fields/layers) to retrieve a simulation array.
MIXTURE
Variable associated to the mixture
GLOBAL
Global variable
FIELD
Variable associated to the field
LAYER
Variable associated to the layer
PHASE
Variable associated to the phase
TimestepScope
It holds the variable scope in the time level to retrieve a simulation array.
CURRENT
Variable in the current time step
PREVIOUS
Variable in the previous (old) time step
It holds the possible state variables that can be computed to a phase inside the plugin. See solver hooks calculate_state_variable and calculate_phase_pair_state_variable
RHO
MU
CP
DRHO_DP
Partial derivative of density in relation to pressure
DRHO_DT
Partial derivative of density in relation to temperature
H
K
SIGMA
Interfacial tension
WallLayerProperty
It holds the possible wall layer property that can be obtained from ALFAsim’s solver. This Enum is used by The #set_wall_layer_property API function.
Enum
THICKNESS
Wall layer tickness
DENSITY
Wall layer material density
THERMAL_CONDUCTIVITY
Wall layer material thermal conductivity
HEAT_CAPACITY
Wall layer material specifc heat capacity
INNER_EMISSIVITY
Wall layer material inner emissivity
OUTER_EMISSIVITY
Wall layer material outer emissivity
EXPANSION
Wall layer material thermal expansion coefficient
VISCOSITY
Wall layer material viscosity (if it is a deposit layer)
sdk_load_error_code
It holds the possible returning error code when trying to open ALFAsim-SDK API.
SDK_DLL_PATH_TOO_LONG
Path to SDK dll too long (Windows limitation).
SDK_ALREADY_OPEN_ERROR
SDK dll already Opened.
SDK_OK
VariableScope
It holds all variable scopes (grid, multifield and timestep)
Public Members
grid_scope
Which grid scope of the variable
mfd_scope
Which multifield scope of the variable
ts_scope
Which timestep scope of the variable
The ALFAsim-SDK API must be loaded with alfasim_sdk_open() inside HOOK_INITIALIZE of any plugin, otherwise the plugin will not be able to use any function available in the API. In addition, to avoid memory leak it is important to unload the ALFAsim-SDK API in the last called hook, HOOK_FINALIZE, using the alfasim_sdk_close() function.
alfasim_sdk_open()
alfasim_sdk_close()
alfasim_sdk_open
alfasim_sdk_close
All API functions on this section has the parameter var_name. This parameter must be filled following the rules exposed in Variable Name Parsing section.
var_name
get_plugin_input_data_boolean
Gets the data provided from the user on a Boolean input field. For more detail about the Boolean input field check alfasim_sdk.types.Boolean
alfasim_sdk.types.Boolean
An error_code value.
[in] ctx: ALFAsim’s plugins context.
[in] ctx
[out] out: Retrieved variable value.
[out] out
[in] plugin_id: Plugin ID.
[in] plugin_id
[in] var_name: Name of the variable to be retrieved.
[in] var_name
get_plugin_input_data_enum
Gets the data provided from the user on a Enum input field. For more detail about the Enum input field check alfasim_sdk.types.Enum.
alfasim_sdk.types.Enum
get_plugin_input_data_quantity
Gets the data provided from the user on a Quantity input field. For more detail about the quantity input field check alfasim_sdk.types.Quantity.
alfasim_sdk.types.Quantity
get_plugin_input_data_string
Gets the data provided from the user on a String input field. For more detail about the string input field check alfasim_sdk.types.String.
alfasim_sdk.types.String
[in] size: Size of output string (param out).
[in] size
out
get_plugin_input_data_string_size
Gets the size of the data provided from the user on a String input field.
[out] out: String size of a variable in which its name is informed by var_name.
get_plugin_input_data_file_content
Gets the data provided from the user on a FileContent input field. For more detail about the FileContent input field check alfasim_sdk.types.FileContent
alfasim_sdk.types.FileContent
get_plugin_input_data_file_content_size
Gets the size of the data provided from the user on a FileContent input field.
[out] out: File content size of a variable in which its name is informed by var_name.
get_plugin_input_data_table_quantity
Gets the values from a column of an input table. column_id is the string defined in the plugin’s configuration file. If the var_name or the column_id are invalid, UNDEFINED_DATA is returned.
column_id
int size = -1; double* values = NULL; int errcode = get_plugin_input_data_table_quantity( ctx, &values, &size, "temperature", get_plugin_id(), "Model.some_table" ); for (int i = 0; i < size; ++i) { some_plugin_data = 1.1 * values[i]; }
[out] out: Variable values array.
[out] size: Size of variable values array.
[out] size
[in] column_id: Table column ID which values are retrieved.
[in] column_id
get_plugin_input_data_reference
Gets an ALFAsim input data internal Reference. Note that a Reference is a specific concept of ALFAsim-SDK and plugins - It is a way to retrieve data from an input outside of the current model. See the ALFAsim’s SDK python configuration file for more information.
void* tracer_ref = nullptr; errcode = get_plugin_input_data_reference( ctx, &tracer_ref, get_plugin_id(), "Model.tracer_reference"); int tracer_id = -1; errcode = get_tracer_id(ctx, &tracer_id, tracer_ref);
[out] out: ALFAsim data reference.
[in] var_name: Name of the variable to be retrived.
get_plugin_input_data_multiplereference_selected_size
Get the number of selected references in a multiple-reference selection. User should be able to iterate over the selections to get information.
int errcode = -1; int indexes_size = -1; errcode = get_plugin_input_data_multiplereference_selected_size( ctx, &indexes_size, get_plugin_id(), "Model.internal_multiple_reference"); for (int i = 0; i < indexes_size; ++i) { auto value = -1.0; auto reference_str = std::string( "Model.internal_multiple_reference[" + std::to_string(i) + "]->quantity"); errcode = get_plugin_input_data_quantity( ctx, &value, get_plugin_id(), reference_str.c_str()); } }
[out] indexes_size: Number of selected references in a multiple reference input data.
[out] indexes_size
[in] var_name: Name of the variable.
set_plugin_data
Set the data provided from the plugin developer.
When a plugin has internal data and it has to be accessed by all C/C++ Hooks during the simulation this function allows the plugin to ask the ALFAsim’s solver to hold its internal data.
Hooks
[in] data: Plugin internal data.
[in] data
[in] thread_id: Thread ID, see get_thread_id for more information.
[in] thread_id
get_plugin_data
Gets the data provided from the plugin developer.
Once the plugin set an internal data, it can be accessed from any C/C++ Hook during the simulation using this function.
Hook
[out] out: Plugin internal data.
get_number_of_threads
Gives the number of running threads on the solver
ALFAsim’s Solver runs in multiple threads. To avoid data access concurrency problems the plugin developer must set one internal data to each running thread during the initialization. Then, with number of threads, the developer can do it properly.
[out] n_threads: Number of threads.
[out] n_threads
get_thread_id
Gives the current running thread id (in the solver process)
Once the plugin sets one internal data to each running thread, to access this data properly it has to know which thread is trying to access this data. For that, this function retrieves this information from solver.
[out] thread_id: Thread ID.
[out] thread_id
get_plugin_variable
Gets the contents of a plugin-registered secondary variable (Given by name).
It is allowed to the plugins to add new secondary variables via python config file. ALFAsim’s solver registers/holds these variables and make them available in the solver hooks by this function.
hooks
[out] out: Plugin-registered secondary variable values array.
[in] variable_name: Name of the secondary variable.
[in] variable_name
[in] line_index: It can represent Layer/Field/Phase ID, since the secondary variables can be associated to different MultiFieldDescriptionScope.
[in] line_index
[in] ts_scope: A TimestepScope value.
[in] ts_scope
[out] size: Size of out array of values. It can be the number of volumes or number of faces depending in which GridScope the secondary variable was registered.
get_field_id
Gets the field ID of the given name. Althought this depends on the hydrodynamic model being solved, common values include “gas”, “oil”, “droplet” and “bubble”. This functions supports retrieve ID of field added by plugin.
[out] out: Field ID.
[in] name: Name of the field to retrieve the ID.
[in] name
get_primary_field_id_of_phase
Gets the primary field ID of the phase with given name. For example, the “oil” phase has primary field “oil”. Different phases may have different primary fields. Use this function when you need a variable from a field, but you aren’t sure about the field name, but you know the phase name.
[in] name: Name of the phase to retrieve the primary field ID.
get_phase_id
Gets the phase ID of the given name. Althought this depends on the hydrodynamic model being solved, common values include “gas”, “oil” and “water”. This functions supports retrieve ID of phase added by plugin.
[out] out: Phase ID.
[in] name: Name of the phase to retrieve the ID.
get_layer_id
Gets the layer ID of the given name. Althought this depends on the hydrodynamic model being solved, common values include “gas”, “oil” and “water”. This functions supports retrieve ID of layer added by plugin.
[out] out: Layer ID.
[in] name: Name of the layer to retrieve the ID.
get_state_variable_array
Gets the current contents of a given state variable (For an array data pointer). A state variable is any variable calculated from pressure and temperature, as any thermodynamic variable.
errcode = get_state_variable_array( ctx, enthalpy, StateVariable::H, FIELD_GAS, size);
[out] out: State Variable values array.
[in] state_var: A StateVariable value. It indicates which variable to be retrieved.
[in] state_var
[in] field_index: Index of the field in which the state variable is retrieved.
[in] field_index
[out] size: Size of the out array of values.
Changing the contents retrieved by this function (out array) has UNDEFINED BEHAVIOR. The plugin must NEVER change the contents returned by this function.
get_simulation_array
Gets the current contents of a given secondary variable (For an array data pointer). A secondary variable is any variable calculated in the solver iterative procedure. Note that not all variables are available at any time. If a given variable is not available in one of the chosen scopes, a NOT_AVAILABLE_DATA error is returned.
List of variable_name values:
variable_name
"rho": Density [kg/m3]
"rho"
"mu": Viscosity [Pa.s]
"mu"
"alpha": Volume Fraction [m3 of field|layer|phase /m3 of mixture]
"alpha"
field|layer|phase
"mass_concentration": Mass Concentration [kg of field|layer|phase /m3 of mixture]
"mass_concentration"
"P": Pressure [Pa]
"P"
"T": Temperature [K]
"T"
"h": Specific Enthalpy [J/kg]
"h"
"cp": Specific Heat Capacity [J/kg.K]
"cp"
"k": Thermal Conductivity [W/m.K]
"k"
"eta_inner": Heat Transfer Coefficient between inner pipe wall and the fluid layers [W/m2.K]
"eta_inner"
"U": Velocity [m/s]
"U"
"U_superficial": Superficial Velocity [m/s]
"U_superficial"
"RS": Gas mass fraction in gas/oil mixture [kg/kg]
"RS"
"RSW": Water vapour mass fraction in gas phase [kg/kg]
"RSW"
"ff_S_wall": Wall friction factor times wall perimeter [-]
"ff_S_wall"
"ff_S_interface": Interface Friction factor times interface perimeter [-]
"ff_S_interface"
"D": Pipe Inner Diameter [m]
"D"
"A": Cross-sectional Area in each control volume [m2]
"A"
"theta": Inclination of each control volume [rad]
"theta"
"dx": Control Volume Length along the Pipe Axis [m]
"dx"
"dv": Volume of the control volume [m3]
"dv"
"D_eff": Effective Pipe Inner Diameter, considering the internal deposit layers [m]
"D_eff"
"A_eff": Cross-sectional Area Effective in each control volume, considering the internal deposit layers [m2]
"A_eff"
"dv_eff": Effective Volume of the control volume, considering the internal deposit layers [m3]
"dv_eff"
It is important to know that the listed variable_names are no available in all MultiFieldDescriptionScope and GridScope. Because of that, the error_code must be checked.
[in] variable_name: String with the variable name. See the list of possible values above.
[in] var_scope: It must be configured to determine all scopes in which the variable will be retrieved. See VariableScope for more information.
[in] var_scope
[in] line_index: It can represent Layer/Field/Phase ID, since the secondary variables can be associated to different MultiFieldDescriptionScope. When it is a GLOBAL variable line_index must be 0.
line_index
get_simulation_tracer_array
Gets the current contents of a given tracer mass fraction (For an array data pointer). A tracer mass fraction is calculated in the extra solver iterative procedure. Note that not all tracer mass fraction are available at any time. If a given tracer mass fraction (in an inexistent field) is not available, a NOT_AVAILABLE_DATA error is returned.
List of variable_name_c values:
variable_name_c
"phi": Mass Fraction [kg of tracer (in field|phase) / kg of mixture]
"phi"
field|phase
[in] variable_name_c: String with the variable name. See the list of possible values above.
[in] variable_name_c
[in] tracer_index: Tracer ID, it can be retrieved by get_tracer_id.
[in] tracer_index
[in] line_index: It can represent Field or Phase ID, since the tracer masss fraction can be calculated related to Field or Phase. When it is the mass fraction on mixture the line_index must be 0.
get_simulation_quantity
Gets the current contents of a given secondary variable (For a single quantity). A secondary variable is any variable calculated in the solver iterative procedure. Note that not all variables are available at any time. If a given variable is not available, a NOT_AVAILABLE_DATA error is returned.
"dt": Time Step [s]
"dt"
"time": Current time [s]
"time"
[out] out: Variable value.
[in] ts_scope: TimestepScope value.
get_tracer_id
Retrieves the tracer ID given a tracer reference. A tracer reference may be obtained from the user input data (See get_plugin_input_data_reference API function for an example).
[out] tracer_id: Tracer ID.
[out] tracer_id
[in] reference: Tracer reference.
[in] reference
get_tracer_name_size
Retrieves the size of the tracer name, given a tracer reference. A tracer reference may be obtained from the user input data (See get_plugin_input_data_reference API function for an example).
[out] tracer_name_size: Size of tracer name string.
[out] tracer_name_size
get_tracer_name
Retrieves the tracer name, given a tracer reference. The tracer_name parameter must be a valid and pre-allocated memory region where the name string will be copied to. A tracer reference may be obtained from the user input data (See get_plugin_input_data_reference API function for an example).
tracer_name
int tracer_name_size = -1; errcode = get_tracer_name_size(ctx, &tracer_name_size, tracer_ref); char* tracer_name = (char*)malloc(sizeof(char) * tracer_name_size); errcode = get_tracer_name( ctx, tracer_name, tracer_ref, tracer_name_size); std::cout << "TRACER NAME: " << tracer_name << std::endl; free(tracer_name);
[out] out: String with tracer name.
[in] size: Size of out string.
get_tracer_ref_by_name
Gets the tracer reference for a given tracer name. This function is important to obtain the tracer reference of a user defined tracer added by the plugin.
[out] reference: Tracer reference.
[out] reference
[in] tracer_name: Tracer name.
[in] tracer_name
get_tracer_partition_coefficient
Gets the partition coefficient input data for a given tracer reference. The phase_id must also be given (See get_phase_id API function). A tracer reference may be obtained from the user input data (See get_plugin_input_data_reference API function for an example).
phase_id
[out] out: Partition coefficient value related to the specified phase.
[in] phase_id: Phase ID.
[in] phase_id
get_wall_interfaces_temperature
Gets the wall interface temperature for a given control volume. Each control volume has an array of temperatures, one for each wall layer. The temperatures are given in the wall interfaces.
[out] out: Wall interfaces temperature values array.
[in] control_volume: Control Volume ID.
[in] control_volume
[in] size: Size of out array of values.
get_flow_pattern
Gets the flow pattern for each control volume.
List of possible values of Flow Pattern is:
Flow Pattern
0 - Unknown
1 - Stratified
2 - Dispersed Bubble
3 - Bubble
4 - Slug
5 - Annular Mist
[out] out: Flow Pattern values array. See list of possible values above.
[in] grid_scope: A GridScope value.
[in] grid_scope
get_ucm_friction_factor_input_variable
Gets the current UCM (unit cell model) input data for friction factor calculation. Any available variable by this function is considered for a unit cell, which means that there are variables with one value and there are variables with two values related to the two phase system (GAS and LIQUID). If a given variable name is not available, a NOT_AVAILABLE_DATA error is returned.
List of variable_name with two values (Two phase):
"alpha": Volume Fraction [m3 of phase /m3 of mixture]
phase
It is important to know that the listed variable_names are not available in any phase, only for two phase systems, in which Gas id is 0 (zero) and Liquid id (sum of all liquid phases) is 1 (One). Because of that, the error_code must be checked.
Gas id
Liquid id
List of variable_name with one value:
"D": Unit Cell Inner Diameter [m]
"ks": Roughness [m]
"ks"
"theta": Inclination of the Unit Cell [rad]
"sigma": Gas-liquid Surface Tension [N/m]
"sigma"
[in] var_name: String with the variable name. See the list of possible values above.
[in] phase_id: A TwoPhaseSystem value. When the requested variable is not associated to a phase any value can be passed.
get_ucm_fluid_geometrical_properties
Gets the current UCM (unit cell model) fluid geometrical properties for friction factor calculation.
During the implementation of any HOOK related to the UCM friction factor, this function provides the following fluid geometrical properties:
"S_w": Wetted perimeters of phases [m].
"S_w"
"S_i": Interface perimeter [m].
"S_i"
"H": Phase height [m].
"H"
It is important to know that
S_w
[out] S_w: Wetted Perimeters [m].
[out] S_w
[out] S_i: Interface Perimeter [m].
[out] S_i
[out] H: Phase height [m]. For annular flow, H[GAS] is the core diameter and H[LIQUID] is the total liquid film height.
[out] H
[in] alpha_G: Unit Cell Gas Volume Fraction [m3 of gas phase /m3 of mixture].
[in] alpha_G
gas phase
[in] D: Unit Cell Inner Diameter [m].
[in] D
To retrieve input data from the plugin’s GUI, the plugin must pass a var_name in a specific format. API functions that use this kind of variable described on Plugin Input Data (From user interface) section.
All variables must begin with the model name described on the plugin model, followed by . (For nested objects) or -> (For references). Lists must be accessed with the list index directly, for example, Model.lst[0] will be the first element of the list “lst”, inside the plugin model named “Model”. References can be internal (Reference to a plugin model) or external (Reference to an ALFAsim model).
.
->
Model.lst[0]
Imagine you have the following simple GUI model defined as
@data_model(icon='', caption='Plugin Model') class Model: boolean_data = Boolean(value=True, caption="BOOLEAN CAPTION")
To extract the plugin input data content on C++, the plugin must use the proper API function call:
int errcode = 0; bool test_api_boolean = false; errcode = alfasim_sdk_api.get_plugin_input_data_boolean( ctx, &test_api_boolean, get_plugin_id(), "Model.boolean_data"); std::cout << " BOOLEAN:" << test_api_boolean << " ERROR CODE:" << errcode << std::endl;
See get_plugin_input_data_boolean() for details.
get_plugin_input_data_boolean()
For the cases were the model is a container, it is possible to retrieve the information for each element individually.
@data_model(icon='', caption='Plugin Model 2') class Model: name = String(value='default', caption='Name') boolean = Boolean(value=True, caption="Boolean") quantity = Quantity(value=1, unit='m', caption='Quantity') @container_model(icon='', caption='Plugin Container', model=Model) class ModelContainer: pass
int errcode = 0; double test_api_quantity = 0.; errcode = alfasim_sdk_api.get_plugin_input_data_quantity( ctx, &test_api_quantity, get_plugin_id(), "ModelContainer[0].quantity"); std::cout << " Quantity from container[0]:" << test_api_quantity << " ERROR CODE:" << errcode << std::endl;
See get_plugin_input_data_quantity() for details.
get_plugin_input_data_quantity()
Internal references are references to models defined in the plugin itself. They are useful when you have a list of models, for example, but need to let the user decide from one specific model from the list. Assuming the model container defined in the previous, example, an internal reference for an element inside that container can be programmed as follows. The plugin must use -> to access referenced data, instead of . as in other examples.
@data_model(icon='', caption='Plugin Model') class OtherModel: internal_reference = Reference( container_type='ModelContainer', ref_type=Model, caption="Internal Reference" )
Data from the referenced model can then be extracted on C++ code as follows. Note that the developer will extract the values directly, not the model itself, that is, in the example below, there is never an object of type Model. Raw data values such as boolean, strings or floats are directly retrieved instead.
Model
int errcode = 0; double test_api_quantity = 0.; errcode = alfasim_sdk_api.get_plugin_input_data_quantity( ctx, &test_api_quantity, get_plugin_id(), "OtherModel.internal_reference->quantity"); std::cout << " Quantity from internal reference:" << test_api_quantity << " ERROR CODE:" << errcode << std::endl;
External references gives the user a way to interact with references to specific ALFAsim’s GUI object configurations. Those types of references work a bit different, because ALFAsim developers must provide an API for each specific entity. As of today, the only exposed ALFAsim model is the Tracer model. See the tracer-related functions to have an overview about the available data that can be used:
get_simulation_tracer_array() get_tracer_id() get_tracer_name() get_tracer_ref_by_name() get_tracer_partition_coefficient()
get_tracer_name()
get_tracer_partition_coefficient()
The example below extracts the tracer Id configured in the plugin.
@data_model(icon='', caption='Plugin Model') class OtherModel: tracer_reference = Reference( ref_type=TracerType, caption="Tracer Reference", )
int errcode = 0; void* tracer_ref = nullptr; errcode = get_plugin_input_data_reference( ctx, &tracer_ref, get_plugin_id(), "OtherModel.tracer_reference"); int tracer_id = -1; errcode = get_tracer_id(ctx, &tracer_id, tracer_ref); std::cout << "TRACER ID: " << tracer_id << std::endl;
See get_plugin_input_data_reference() for details.
get_plugin_input_data_reference()
The plugin developer may need to let the user select not one, but several references (This is valid for both internal and external references). To tackle this problem, ALFAsim developers created the notion of Multiple References. It is basically a container of referenced objects, and the usage is simply a mix of the container with the reference syntax.
Example of a GUI model in which has both types of multiple references:
@data_model(icon='', caption='Plugin Model') class OtherModel: multiple_reference = MultipleReference( ref_type=TracerType, caption='Multiple Reference' ) internal_multiple_reference = MultipleReference( ref_type=Model, container_type='ModelContainer', caption='Internal Multiple Reference' )
Example of accessing the external multiple references:
int errcode = -1; int indexes_size = -1; errcode = get_plugin_input_data_multiplereference_selected_size( ctx, &indexes_size, get_plugin_id(), "OtherModel.multiple_reference"); void* tracer_ref = nullptr; for (int i = 0; i < indexes_size; ++i) { auto reference_str = std::string( "OtherModel.multiple_reference[" + std::to_string(i) + "]"); errcode = get_plugin_input_data_reference( ctx, &tracer_ref, get_plugin_id(), reference_str.c_str()); int tracer_id = -1; errcode = get_tracer_id(ctx, &tracer_id, tracer_ref); std::cout << "TRACER ID: " << tracer_id << std::endl; }
Example of accessing the internal multiple references:
int errcode = -1; int indexes_size = -1; errcode = get_plugin_input_data_multiplereference_selected_size( ctx, &indexes_size, get_plugin_id(), "OtherModel.internal_multiple_reference"); for (int i = 0; i < indexes_size; ++i) { auto test_api_bool = false; auto reference_str = std::string( "OtherModel.internal_multiple_reference[" + std::to_string(i) + "]->boolean"); errcode = get_plugin_input_data_boolean( ctx, &test_api_bool, get_plugin_id(), reference_str.c_str()); std::cout << " Bool from referenced container[" << i << "]:" << (test_api_bool ? "true" : "false") << " ERROR CODE:" << errcode << std::endl; }
see get_plugin_input_data_multiplereference_selected_size() for details.
get_plugin_input_data_multiplereference_selected_size()
Here is listed the completed API available to implement the Application Hooks.
Models
Types
Layout
Status
Context
data_model
`data_model` is an object that keeps together many different properties defined by the plugin and allows developers to build user interfaces in a declarative way.
`data_model`
Application Required:
The following options are required when declaring a data_model and are used into the user interface
caption A text to be displayed over the Tree. icon Name of the icon to be used over the Tree.
A text to be displayed over the Tree.
Name of the icon to be used over the Tree.
Even though the icon parameter is required, it’s not currently being used.
Plugin Defined:
Visual elements that allow the user to input information into the application, or to arrange better the user interface.
Visual elements that allow the user to provide input information into the application.
Elements that assist the developer to arrange input fields in a meaningful way.
Check the section visual elements to see all inputs available, and layout elements to see all layouts available.
Example:
@data_model(icon='', caption='My Plugin') class MyModel: distance = Quantity(value=1, unit='m', caption='Distance') @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModel]
container_model
container_model is an object that keeps together many different properties defined by the plugin and allows developers to build user interfaces in a declarative way similar to data_model().
container_model() can also hold a reference to a data_model() declared from the plugin, making this object a parent for all new data_model() created.
The following options are required when declaring a container_model().
A reference to a class decorated with data_model().
Plugin defined:
Elements that assist the developer to arrange input fields in meaningfully way.
Example myplugin.py
@data_model(icon="", caption="My Child") class ChildModel: distance = Quantity(value=1, unit="m", caption="Distance") @container_model(icon='', caption='My Container', model=ChildModel) class MyModelContainer: my_string = String(value='Initial Value', caption='My String') @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModelContainer]
Container data also includes automatically two actions for the model:
Action: Create new Model
An action that creates a new model inside the container selected, you can activate this action by right-clicking in the container over the Tree, or by clicking on the “Plus” icon available at the Model Explorer.
Model Explorer
Action: Remove
An action that remove the selected model, only available for models inside a container, you can activate this action by right-clicking the model over the Tree, or by clicking on the “Trash” icon available at the Model Explorer.
The types module supplies UI elements for creating user interfaces with the classic desktop-style, each type has a related model.
types
Models are the primary elements to create user interfaces on ALFAsim, models can display data, receive user input, and provide a container for other fields that should be grouped together.
BaseField
A base field for all types available at ALFAsim.
caption – Label to be displayed on the right side of the component.
tooltip – Shows a tip, a short piece of text.
enable_expr (Callable) – Function to evaluate if the component will be enabled or not.
visible_expr (Callable) – Function to inform if the component will be visible or not.
Caption and Tooltip:
Caption is the most basic information that all fields must inform, it will display Label over the right side of the component on the Model Explorer window.
Tooltips are short pieces of text to reminder/inform the user about some specificity about the property when they keep the mouse over the field. Tooltips must be a string and can have HTML tags and Unicode characters as well.
TypeError – if the tooltip informed is not a string.
@data_model(icon='', caption='My Plugin') class MyModel: my_string_1= String( value='String 1', caption='My String 1', tooltip="Some Text <br> <b> More Information</b>", ) my_string_2 = String( value='String 2', caption='My String 2', tooltip="∩ ∪ ∫ ∬ ∮", ) @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModel]
The images below shows the output from the example above.
Enable Expression:
Accepts a python function that controls either the component will be enabled, or disabled. The python function will receive two arguments, an instance of itself (to check local values) and an instance of alfasim_sdk.context.Context() to retrieve information about the application.
alfasim_sdk.context.Context()
This function must return a boolean, informing True (for enabled) or False (for disabled).
enabled: The component will handle keyboard and mouse events.
disabled: The component will not handle events and it will be grayed out.
def my_check(self, ctx): return self.bool_value @data_model(icon="", caption="My Plugin") class MyModel: bool_value = Boolean(value=True, caption="Enabled") N_ions = Quantity( caption='Number of Ions', value=1, unit='-', enable_expr=my_check, ) @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModel]
The image below shows the N_ions property disabled, when the property bool_value is disabled (False)
N_ions
bool_value
Visible Expression:
Accepts a python function that controls either the component will be visible, or not. The python function will receive two arguments, an instance of itself (to check local values) and an instance of alfasim_sdk.context.Context() to retrieve information about the application.
This function must return a boolean, informing True (for visible) or False (for invisible).
def my_check(self, ctx): return self.bool_value @data_model(icon="", caption="My Plugin") class MyModel: bool_value = Boolean(value=True, caption="Enabled") N_ions = Quantity( caption="Number of Ions", value=1, unit="-", visible_expr=my_check, ) @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModel]
The image below shows the N_ions property visible, when the property bool_value is enabled (True)
String
The String field represents an input that allows the user to enter and edit a single line of plain text.
The String field have all options available from BaseField(), plus the following ones
BaseField()
value (str) – property to hold the value informed by the user.
@data_model(icon="", caption="My Plugin") class MyModel: string_field = String( value="Default Value", caption="String Field", )
Accessing String Field from Plugin:
In order to access this field from inside the plugin implementation, in C/C++ you need to use get_plugin_input_data_string_size() together with get_plugin_input_data_string_size()
get_plugin_input_data_string_size()
Accessing String Field from Context:
When accessed from the Context(), the String field will return the currently text as str.
Context()
str
>>> ctx.get_model("MyModel").string_field 'Default Value' >>> type(ctx.get_model("MyModel").string_field) <class 'str'>
The Enum field provides list of options to the user, showing only the select item but providing a way to display a list of all options through a combo-box.
The Enum field have all options available from BaseField(), besides the listed the ones listed above:
values – A list of strings with the available options.
initial – Indicates which one of the options should be selected per default. If not given, the first item in values will be used as default.
values
@data_model(icon="", caption="My Plugin") class MyModel: enum_field = Enum( values=["Option 1, Option 2"], initial="Option 1", caption="Enum Field", )
Accessing Enum Field from Plugin:
In order to access this field from inside the plugin implementation, in C/C++, you need to use get_plugin_input_data_enum()
get_plugin_input_data_enum()
Accessing Enum Field from Context:
When accessed from the Context(), the Enum field will return the currently selected option as str.
@data_model(icon="", caption="My Plugin") class MyModel: enum_field = Enum( values=["Option 1", "Option 2"], initial="Option 1", caption="Enum Field", )
# From Terminal >>> ctx.get_model("MyModel").enum_field 'Option 1' >>> type(ctx.get_model("MyModel").enum_field) <class 'str'>
Reference
The Reference field provides a list of options to the user and displays the current item selected.
There are two types of models supported by this field.
models from ALFAsim, for example, Tracers.
a model defined within the plugin.
In order to reference custom data, the model must be inside a container.
caption (str) – Property used as a label for the field.
ref_type – Property that indicates which type of data the Reference will hold.
container_type – The name of the class that holds the ref_type, this property must be used when the ref_type references model from the plugin.
ref_type
Example using ALFAsimTypes on myplugin.py
ALFAsimTypes
@data_model(icon="", caption="My Plugin") class MyModel: tracer_ref = Reference( ref_type=TracerType, caption="Tracer Type", )
Example using Custom Data on myplugin.py
Custom Data
@data_model(caption="My Model") class MyModel: field_1 = String(value="Value 1", caption="String 1") @container_model(caption="My Container", model=MyModel, icon="") class MyContainer: internal_ref = Reference( ref_type=MyModel, container_type="MyContainer", caption="Internal Reference", )
Accessing Reference Field from Plugin:
In order to access this field from inside the plugin implementation, in C/C++, you need to use get_plugin_input_data_reference()
Accessing Reference Field from Context:
When accessed from the Context(), the Reference field will return the currently selected option object instance.
With the instance, you can access all attributes from the object normally. Check the example below.
@data_model(caption="My Model") class MyModel: field_1 = String(value="Value 1", caption="String 1") @container_model(caption="My Container", model=MyModel, icon="") class MyContainer: tracer_ref = Reference( ref_type=TracerType, caption="Tracer Type", ) internal_ref = Reference( ref_type=MyModel, container_type="MyContainer", caption="Internal Reference", ) # Example with Tracer >>> ctx.get_model("MyContainer").tracer_ref TracerModel(gas_partition_coefficient=[...]) >>> ctx.get_model("MyContainer").tracer_ref.gas_partition_coefficient Scalar(0.0, 'kg/kg', 'mass fraction') # Example with Custom Data >>> ctx.get_model("MyContainer").internal_ref MyModel(field_1='Value 1', name='My Model 1') >>> ctx.get_model("MyContainer").internal_ref.field_1 'Value 1'
MultipleReference
The MultipleReference field works similar to Reference(), providing a list of options to the user, but allowing multiple values, of the same type, to be chosen.
Reference()
There are two types of models supported by this field. :ALFAsimTypes: models from ALFAsim, for example, Tracers. :Custom Data: a model defined within the plugin.
In order to reference a custom data the model must be inside a container.
@data_model(icon="", caption="My Plugin") class MyModel: tracer_ref = MultipleReference( ref_type=TracerType, caption="Tracer Type" )
@data_model(caption="My Model") class MyModel: field_1 = String(value="Value 1", caption="String 1") @container_model(caption="My Container", model=MyModel, icon="") class MyContainer: internal_ref = MultipleReference( ref_type=MyModel, container_type="MyContainer", caption="Internal Reference", )
Accessing MultipleReference Field from Plugin:
In order to access this field from inside the plugin implementation, in C/C++, you need to use get_plugin_input_data_multiplereference_selected_size()
Accessing MultipleReference Field from Context:
When accessed from the Context(), the MultipleReference field will return a list with the currently selected option objects instances.
With the instance, you can access all attributes from the object. Check the example below.
@data_model(caption="My Model") class MyModel: field_1 = String(value="Value 1", caption="String 1") @container_model(caption="My Container", model=MyModel, icon="") class MyContainer: internal_ref = MultipleReference( ref_type=MyModel, container_type="MyContainer", caption="Internal Reference", ) # Example >>> ctx.get_model("MyContainer").internal_ref [MyModel(field_1='Value 1', name='My Model 1'), MyModel(field_1='Value 1', name='My Model 4')] >>> type(ctx.get_model("MyContainer").internal_ref) <class 'list'> >>> ctx.get_model("MyContainer").internal_ref[0] MyModel(field_1='Value 1', name='My Model 1')
Quantity
The Quantity field provides a way to the user provide a scalar value into the application.
The Quantity field have all options available from BaseField(), besides the listed the ones listed above: :param values: A number value. :param unit: Unit for the given scalar.
All scalar values are created using the Barril library
Checkout the Barril documentation, to see all available units
If you want to check the input value, is recommended to include a status monitor in your plugin to make sure that the provided value is valid.
For more details about status monitor check alfasim_get_status()
@data_model(icon="", caption="My Plugin") class MyModel: quantity_field = Quantity( value=1, unit="degC", caption="Quantity Field" )
Accessing Quantity Field from Plugin:
In order to access this field from inside the plugin implementation, in C/C++, you need to use get_plugin_input_data_quantity()
Accessing Quantity Field from Context:
When accessed from the Context(), the Quantity field will return a Scalar object, with the current value and unit. Check out the Scalar documentation from Barril for more details about the usage.
Scalar
@data_model(icon="", caption="My Plugin") class MyModel: quantity_field = Enum( values=["Option 1", "Option 2"], initial="Option 1", caption="Enum Field", ) # From Terminal >>> ctx.get_model("MyModel").quantity_field Scalar(1.0, 'degC', 'temperature') >>> ctx.get_model("MyModel").quantity_field.value 1.0 >>> ctx.get_model("MyModel").quantity_field.unit 'degC' >>> ctx.get_model("MyModel").quantity_field.GetValue('K') 274.15
Table
The Table component provides a table to the user to be able input values manually or by importing it from a file.
@data_model(icon="", caption="My Model") class MyModel: Table( rows=[ TableColumn( id="temperature", value=Quantity( value=1, unit="K", caption="Temperature Column Caption", ), ), TableColumn( id="pressure", value=Quantity( value=2, unit="bar", caption="Pressure Column Caption", ), ), ], caption="Table Field", )
The image above illustrates the output from the example above.
With this component, the user can easily import the content from a file by clicking on the last icon from the toolbar menu.
The wizard assistance supports multiple types of file, the user just needs to inform which kind of configuration the file has.
By the end, it’s possible for the user select to which unit the values must be converted and which columns.
Accessing Table Field from Plugin:
In order to access this field from inside the plugin implementation, in C/C++, you need to use get_plugin_input_data_table_quantity()
get_plugin_input_data_table_quantity()
Accessing Table Field from Context:
When accessed from the Context(), the Table field will return a model, with information about all columns.
@data_model(icon="", caption="My Model") class MyModel: Table( rows=[ TableColumn( id='temperature', value=Quantity(value=1, unit='K', caption='Temperature Column Caption'), ), TableColumn( id='pressure', value=Quantity(value=2, unit='bar', caption='Pressure Column Caption'), ), ], caption="Table Field" ) # From Terminal >>> ctx.get_model("MyModel").table_field TableContainer([...]) >>> len(ctx.get_model("MyModel").table_field) 6 >>> len(ctx.get_model("MyModel").table_field) TableRow(temperature=Scalar(1.0, 'K', 'temperature'), pressure=Scalar(2.0, 'bar', 'pressure')) >>> ctx.get_model("MyModel").table_field[0].pressure Scalar(2.0, 'bar', 'pressure')
TableColumn
The TableColumn component provides columns for a Table() field. Currently only columns with a Quantity() fields are available.
Table()
Check out the documentation from Table() to see more details about the usage and how to retrieve values.
Boolean
The Boolean field provides a checkbox to select/deselect a property.
The Boolean fields have all options available from BaseField(), besides the listed the ones listed above: :param value: A boolean informing the initial state from the Field
@data_model(icon="", caption="My Plugin") class MyModel: boolean_field = Boolean( value=False, caption="Boolean Field", )
Accessing Boolean Field from Plugin:
In order to access this field from inside the plugin implementation, in C/C++, you need to use get_plugin_input_data_boolean()
When accessed from the Context(), the Boolean field will return a boolean value
@data_model(icon="", caption="My Plugin") class MyModel: quantity_field = Boolean( value=False, caption="Boolean Field", ) # From Terminal >>> ctx.get_model("MyModel").boolean_field False
FileContent
The FileContent component provides a platform-native file dialog to the user to be able to select a file. The name of the selected file will be available over the GUI.
If you want to make the file mandatory it is recommended to include a status monitor in your plugin to make sure that a file is selected.
@data_model(icon="", caption="My Plugin") class MyModel: file_content_field = FileContent(caption="FileContent Field")
Accessing FileContent Field from Plugin:
In order to access this field from inside the plugin implementation, in C/C++, you need to use get_plugin_input_data_file_content() together with get_plugin_input_data_file_content_size()
get_plugin_input_data_file_content()
get_plugin_input_data_file_content_size()
When accessed from the Context(), the FileContent field will return a FileContent object, a Model that represent a file from the filesystem.
Class FileContent
Return a Path object of the file.
The content from the file in binary format.
The size of the file in bytes.
Return a Datetime object, with the last time the file was modified
>>> ctx.get_model("MyModel").file_content_field.path WindowsPath('C:/ol-wax-1.wax')
>>> ctx.get_model("MyModel").file_content_field.content b"!Name of Table [...] "
>>> ctx.get_model("MyModel").file_content_field.size 90379
>>> ctx.get_model("MyModel").file_content_field.modified_data datetime.datetime(2019, 5, 10, 14, 22, 11, 50795)
group
The group layout is a container to organize ALFAsim types, only fields that derives from BaseField can be defined inside a group.
Example.:
@data_model(icon="", caption="My Model") class MyModel: string_field_1 = String(caption="Outside", value="Default") @group(caption="Group Container") class GroupMain: string_field_2 = String(value="Group 1", caption="Inside") bool_field = Boolean(value=True, caption="Boolean Field")
The image below shows the output from the example above.
group is a layout component, and will not have an attribute to be accessed through context or API.
tabs
Create a tab bar layout, to group multiples :func:”~alfasim_sdk.layout.tab” instances.
With the tabs, you can split up complex dialog into “pages” using a :func:”~alfasim_sdk.layout.tab” instance.
Notice that only classes decorated with :func:”~alfasim_sdk.layout.tab” can be placed inside a tab bar.
tab bar
@data_model(icon="", caption="My Model") class MyModel: field = String(caption="String outside tabs", value="Default") @tabs() class MainPage: @tab(caption="Fist Tab") class Tab1: field_1 = String(caption="First Tab", value="Default") @tab(caption="Second Tab") class Tab2: field_2 = String(caption="Second Tab", value="Default")
The image below shows the output from the command above.
tabs is a layout component, and will not have an attribute to be accessed through context or API.
tab
The tab represents a single entry, on the tabs() layout.
tabs()
Notice that only components available at the types modules can be placed inside a tab.
ErrorMessage
ErrorMessage allows the plugin to display a message over the status monitor, and signalize to the application to block the simulation until the issue is fixed.
model_name – Name of the model that issues the error.
message – Message that will be displayed over the status monitor.
Checkout the alfasim_get_status() for some examples of ErrorMessage() in action.
WarningMessage
WarningMessage allows the plugin to display a message to the user over the status monitor, and signalizes a minor issue that needs to be fixed but doesn’t block the simulation.
model_name – Name of the model that issues the warning.
Checkout the alfasim_get_status() for some examples of WarningMessage() in action.
The context class provides information about the current state of the application and the models implemented by the user.
The following methods provide an instance of Context() to inform the current state of the application:
Visible Expression parameter from all fields
Enable Expression parameter from all fields
alfasim_get_status() hook
get_edges
Return a list of all Edges available on ALFAsim. Each Edge is represented by an instance of EdgeInfo().
EdgeInfo()
Example of GetEdges
The image above has two Edges configured, in order to access the available Edges, it’s possible to use the method GetEdges as demonstrated below.
GetEdges
Accessing GetEdges from the context
>>> ctx.get_edges()[0] EdgeInfo(name='Pipe 1', number_of_phases_from_associated_pvt=2) >>> ctx.get_pipelines()[0].number_of_phases_from_associated_pvt 'Pipe 1'
Checkout the EdgeInfo() section to know more about the properties available.
get_model
Returns an instance of the given model_name.
model_name
The parameter model_name must be the name of a model defined within the plugin.
In the example below, the Context is used to access a property from the model MyModel
MyModel
ctx.GetModel("Acme") as exemplified in the code below.
ctx.GetModel("Acme")
Setting up the model
@data_model(caption="MyPlugin", icon="") class MyModel: name = String(value="ALFAsim", caption="Field") scalar = Quantity(value=1, unit="degC", caption="Field") @alfasim_sdk.hookimpl def alfasim_get_data_model_type(): return [MyModel]
Accessing the context
>>> ctx.get_model('MyModel') MyModel(name='ALFAsim', scalar=Scalar(1.0, 'degC', 'temperature')) >>> ctx.get_model('MyModel').name 'ALFAsim'
At runtime, you can also verify the names of the models defined by a given plugin. For this, you need to For more information check GetPluginInfoById()
GetPluginInfoById()
TypeError – When the given model_name does not exist.
FrozenInstanceError – When trying to modify a value
get_nodes
Return a list of all Nodes available on ALFAsim. Each Node is represented by an instance of alfasim_sdk.context.NodeInfo().
alfasim_sdk.context.NodeInfo()
Usage Example of GetNodes
The image above has three nodes configured, you can access this information by using the method GetNodes as demonstrated below.
GetNodes
>>> ctx.get_nodes[0] NodeInfo(name='Node 1', number_of_phases_from_associated_pvt=2) >>> ctx.get_nodes[0].name 'Node 1'
The values from NodeInfo are read-only, they cannot be modified.
Checkout the NodeInfo() section to know more about the properties available.
NodeInfo()
get_physics_options
Return the physics options from the current project from ALFAsim.
Example of GetPhysicsOptions
The image below shows a configuration from a given project.
It’s possible to access this information from inside the plugin, by using context api as demonstrate below.
Accessing GetPhysicsOptions from the context
>>> ctx.get_physics_options() PhysicsOptionsInfo( [...] ) >>> ctx.get_physics_options().emulsion_model.value 'EmulsionModelType.brinkman1952' >>> ctx.get_physics_options().hydrodynamic_model HydrodynamicModelInfo( [ ... ] ) >>> ctx.get_physics_options().hydrodynamic_model.fields ['gas', 'oil', 'droplet', 'bubble'] >>> ctx.get_physics_options().hydrodynamic_model.layers ['gas', 'oil'] >>> ctx.get_physics_options().hydrodynamic_model.phases ['gas', 'oil']
Checkout the PhysicsOptionsInfo() section to know more about the properties available.
PhysicsOptionsInfo()
get_pipelines
Return a list with all Pipes available on the Network from the Project. Each Pipe is represented by an instance of PipelineInfo().
PipelineInfo()
Usage Example of GetPipelines
The image above has two Pipelines configured, you can access this information by using the method GetPipelines as demonstrated below.
GetPipelines
>>> ctx.get_pipelines()[0] PipelineInfo(name='Pipe 1 > Pipeline', [ ... ]) >>> ctx.get_pipelines()[0].edge_name 'Pipe 1' >>> ctx.get_pipelines()[0].total_length Scalar(1000.0, 'm', 'length') >>> len(ctx.get_pipelines()[0].segments) 1
The values from PipelineInfo are read-only, they cannot be modified.
Checkout the PipelineInfo() section to know more about the properties available.
get_plugin_info_by_id
Similar to GetPluginsInfos() but returns a single instance of PluginInfo() from the given plugin_id parameter.
GetPluginsInfos()
PluginInfo()
plugin_id
Checkout the PluginInfo() section to know more about the properties available.
ValueError – When the plugin informed by plugin_id it’s not available.
get_plugins_infos
Return a list of all plugins available on ALFAsim. Each plugin is represented by an instance of PluginInfo().
Usage Example of GetPluginsInfos
The example demonstrated how you can access information about the plugin from using the GetPluginsInfos() method.
>>> ctx.get_plugins_infos() [PluginInfo(caption='myplugin', name='myplugin', enabled=True, models=['MyModel'])] >>> ctx.get_plugins_infos()[0].enabled True >>> ctx.get_plugins_infos()[0].models ['MyModel']
EdgeInfo
The EdgeInfo provides information about a Edge from ALFAsim, it provides the name of the Node and the number of phases that the associate pvt model has.
Edge
HydrodynamicModelInfo
HydrodynamicModelInfo provides information about which layer, fields, and phases the currently Hydrodynamic model is using.
NodeInfo
The NodeInfo provides information about a Node from ALFAsim, it provides the name of the Node and the number of phases that the associate PVT model has.
Node
PhysicsOptionsInfo
PhysicsOptionsInfo provides information about the Physics Options available at ALFAsim.
Physics Options
The following option can be accessed:
Emulsion Model: Informs which emulsion model the application is currently using. For more information about all options available check alfasim_sdk.context.EmulsionModelType
alfasim_sdk.context.EmulsionModelType
Solids Model: Informs the current solid model being used by the application For more information about all options available check alfasim_sdk.context.SolidsModelType
alfasim_sdk.context.SolidsModelType
Hydrodynamic Model: Provides a alfasim_sdk.context.HydrodynamicModelInfo informing which layers, fields and phases the application is currently using. For more information about all options available check alfasim_sdk.context.HydrodynamicModelInfo
alfasim_sdk.context.HydrodynamicModelInfo
PipelineInfo
The PipelineInfo provides information about the geometry of a pipeline.
name: Name associated with this Pipeline on ALFAsim
Pipeline
edge_name: Name of the edge that this Pipeline is associated with.
segments: List of segments associates with this Pipeline For more information check alfasim_sdk.context.PipelineSegmentInfo
total_length: Total length of the pipeline.
PipelineSegmentInfo
The PipelineSegmentInfo provides information about segments associated with a pipeline.
edge_name: name of the edge that the segment is associated with
start_position: Defines point where this segment starts in MD (measured depth).
inner_diameter: Inner diameter of pipe annulus.
When `is_custom` is true, the reported roughness is customized for this segment, otherwise, the reported roughness is the original reported by the wall.
`is_custom`
is_custom: Informs either the roughness value is custom or original from the wall
PluginInfo
PluginInfo provides information about the plugin name, its current state (either enabled or not) and all models defined from this plugin.
Here is listed the completed API available to implement the Solver Configuration Hooks.
Secondary Variables
Constants
AddField
Allows the plugin to add new fields to Hydrodynamic model.
An added field must be associated to a phase (Using AddPhase or UpdatePhase) and added to a layer (Using AddLayer or UpdateLayer)
name – Name of the new field.
This type is supposed to be used in the alfasim_configure_fields() hook.
Allows the plugin to add new phases to Hydrodynamic model.
name – Name of the new phase.
fields – List of fields names associated to the added phase. It is important to know how to calculate the state variables of fields.
primary_field – Reference field when a phase property calculation is performed through the fields of the phase.
is_solid – A boolean variable to identify if the added phase is solid.
This type is supposed to be used in the alfasim_configure_phases() hook.
alfasim_configure_phases()
Allows the plugin update existing phases of the Hydrodynamic model.
GAS_PHASE
OIL_PHASE
WATER_PHASE (If a three phase hydrodynamic model is used)
WATER_PHASE
additional_fields – List of additional fields names to be appended in the fields list of the phase.
Allows the plugin to add new layers to Hydrodynamic model.
name – Name of the new layer.
fields – List of fields names contained in the added layer.
continuous_field – Name of the continuous field of the added layer (must be in the fields list).
This type is supposed to be used in the alfasim_configure_layers() hook.
alfasim_configure_layers()
Allows the plugin to update existing layer of the Hydrodynamic model.
GAS_LAYER
OIL_LAYER
WATER_LAYER (If a three phase hydrodynamic model is used)
WATER_LAYER
name – Name of the updated layer.
additional_fields – List of additional fields names to be appended in the fields list of the layer.
Secondary variables are those variables that are not unknowns from the nonlinear system. That is, they are not directly solved in the nonlinear system, but they are calculated based on the nonlinear system results.
name – Plugin secondary variable name. This name will be used to access it in the Solver Hooks.
caption – Caption to be shown in the GUI (For output purpose).
type – a Type value.
Type
unit – A string with the unit of the variable.
visibility – a Visibility value.
Visibility
location – a Location value.
Location
multifield_scope – a Scope.
Scope
default_value – Default value to be set.
checked_on_gui_default – If the added variable has Visibility equal to Output, it indicates that this variable will be exported as output by default.
Output
The unit param accepts all units available on Barril Unit Manager, for more information read its documentation.
unit
This type is supposed to be used in the alfasim_get_additional_variables() hook.
Double: Double precision floating point data type.
Double
Int: Integral data type.
Int
Internal: The variable should only be used by the plugin, but not available to the end-user.
Internal
Output: The variable should be available to the end user, as a Property on Plot Window
Center: Center of the control volumes.
Center
Face: Faces of control volumes.
Face
Energy: One value for each energy equation (One for GLOBAL model and number of layers for LAYER model).
Energy
Global: One global value (or related to the mixture).
Global
Field: One value for each field of the hydrodynamic model.
Field
Layer: One value for each layer of the hydrodynamic model.
Layer
Phase: One value for each phase of the hydrodynamic model.
Phase
str(object=’‘) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.
The ALFAsim-SDK allows the user to create or edit a project for ALFAsim application by writing the project specification directly in an ALFAcase file.
An ALFAcase file (.alfacase) contains a textual description of a complete case in text format (YAML). This file allows the user to write case files directly and execute them directly using the command line. Being a text file in a standard and well supported format, it also allows the user to execute complex workflows by manipulating the files using external software or programming languages, providing flexibility and power.
.alfacase
ALFAcase is also referenced as ALFAsim case file
ALFAsim case file
To get quick and running with ALFAsim-SDK you can read the ALFAcase Quick Start and the ALFAcase Syntax sections
In this section, it is shown how to create an ALFAcase from an existent project, with this exported project you can easily modify your project and reintroduce it, with the modification, back to ALFAsim.
One of the easiest ways to get started is to export an existing project into a .alfascase file directly from the interface. Open an existing project and export it using the option Export ALFAsim Case file... as illustrated on the figure below:
.alfascase
Export ALFAsim Case file...
The generated file will contain all project settings, including the default values used by ALFAsim.
Note that in general default values can be omitted when producing .alfacase files manually.
For illustration, an .alfacase file looks like this:
pipes: - name: Conn 1 source: Node 1 target: Node 2 segments: start_positions: values: [0.0] unit: m diameters: values: [0.1] unit: m roughnesses: values: [5e-05] unit: m nodes: - name: Node 1 node_type: mass_source_boundary - name: Node 2 node_type: pressure_boundary
An ALFAcase file is a text-based file that must be written following the YAML syntax, only a restricted subset of the YAML specification is supported and the this section and the next cover the differences.
Our root object is a map (equivalent to a dictionary) that represents a CaseDescription with its attributes.
CaseDescription
The majority of the values from ALFAcase are based on key and value, the example below illustrates some of these cases:
key
value
key: value # Case 1 material_name: string # Case 2 string: string # Case 3 mass_fractions: string: value: number unit: string # Case 4 position: values: [ number ] unit: string # Case 5 node_type: NodeCellType⠀ # Case 6 physics: physics_description_schema⠀
material_name is a pre-defined key and you can just inform the value (string).
material_name
string
Example
material_name: Steel
Check the String section for more information on the possible ways to enter a string
Both key and value must be informed (note the string indication)
PVTModelName: some_name
The key mass_fractions is creating a mapping with the string informed as key, and for each entry, two keys are required value and unit.
mass_fractions
mass_fractions: first entry: value: 42 unit: m second entry: value: 1.5 unit: m
Info
All entries that accept a string as a key can have multiples entries, as demonstrated above.
About the unit
The unit depends on the category of the attribute, the Full API Reference lists the category and the valid units for each attribute.
Check the Number section for more information on the possible ways to enter a number
number
Similar to Case 3, but instead of a single value it accepts multiples values
Case 3
position: values: [ 1.5, 4.5 ] unit: m
Check the section List for more information about how to creates a list
list
In this case, the value is an Enum and one of the options must be filled, each attribute listed on Full API Reference has a link for the respective Enum to check all options, on the example, bellow is used a NodeCellType that has the following options
NodeCellType
An enumeration.
node_type: mass_source_boundary⠀
The last case is a composition of components, the definition is informing that the value of physics must be filled with the key and values defined for PhysicsDescription
PhysicsDescription
physics: hydrodynamic_model: hydrodynamic_model_4_fields simulation_regime: simulation_regime_transient
All the definitions offer default values, this allows us to abbreviate the syntax and let ALFAsim-SDK just use its defaults. Check the Full API Reference section which informs all the default values of each attribute on each Description.
Description
The next sections go deep on the syntax, showing different ways to fill some values.
# key: value material_name: Another value goes here. # It is possible to put quotes in a string, but it is not necessary material_name: 'A string, enclosed in quotes.' # variable: variable key with spaces: value
# Integer value: 100 # Float value: 1.5 # Scientific Notation value: 1e+12
list is a sequence of values and on ALFAcase list is denoted by a series of dashes (-) It is possible to define a list in a compressed inserting the value between brackets ([ ]):
-
[
]
values: - 1 - 2 - 3 # Flow style values: [ 1, 2 , 3 ]
bool is case-insensitive and accepts the following options:
bool
boolean syntax¶ enable_solver_caching: True # True enable_solver_caching: true # True enable_solver_caching: yes # True enable_solver_caching: on # True enable_solver_caching: 1 # True enable_solver_caching: False # False enable_solver_caching: false # False enable_solver_caching: no # False enable_solver_caching: off # False enable_solver_caching: 0 # False
enable_solver_caching: True # True enable_solver_caching: true # True enable_solver_caching: yes # True enable_solver_caching: on # True enable_solver_caching: 1 # True enable_solver_caching: False # False enable_solver_caching: false # False enable_solver_caching: no # False enable_solver_caching: off # False enable_solver_caching: 0 # False
In this section, we will walk trough the creation of a simple network, with two nodes and one pipe, to illustrate how to crete a project and how to interpret the definitions available on Full API Reference.
The root level of our ALFAcase file is always a CaseDescription which has the following attributes:
name: string # optional physics: physics_description_schema⠀ time_options: time_options_description_schema⠀ numerical_options: numerical_options_description_schema⠀ ipr_models: ipr_models_description_schema⠀ pvt_models: pvt_models_description_schema⠀ tracers: tracers_description_schema⠀ outputs: case_output_description_schema⠀ ....
In the following section, this steps will be covered:
How to configure the project options.
How to add a PVtModel.
How to add Nodes.
How to add Pipes.
How to add output curves.
For the full reference check the Full API Reference
We will start teh example by configuring the project options, as discussed in the previous section, the root level of an ALFacase file is the CaseDescription and it has the following options:
ALFacase
physics
time_options
numerical_options
For this example, the application will be configured with the ALFAsim correlation package using a hydrodynamic model with two-phase and four fields, the time steps will be changed as well and the tolerance will be set to 1e-4
As indicated in ALFAcase Syntax section, each option has its own schema definition that needs to be filled accordingly to the reference showed at Options section.
name: basic_case physics: correlations_package: correlation_package_alfasim hydrodynamic_model: hydrodynamic_model_4_fields numerical_options: tolerance: 1e-4 time_options: minimum_timestep: value: 1e-4 unit: s maximum_timestep: value: 0.5 unit: s final_time: value: 1.0 unit: s
The second step will add a PVTModel to the project and configure it as the default PVT for the entire project.
PVTModel
The pvt_models field from CaseDescription needs to be configured with the definition provided from PvtModelsDescription.
pvt_models
PvtModelsDescription
The PvtModelsDescription is the root configuration of all PVTs over the application, its possible to add new PVTs and defined one of them to be used automatically on all fields that requires a PVT through the option default_model
For this example a PVT will be created from a .tab file and the path to the file is relative to the .alfacase file. And for this we need to populate the tables field with the PVT name and a file.
.tab
tables
About the tab file path
Considering that a .alfacase file is located at C:\Users\alfasim and the table section is configured with a relative path to my_pvt_file.tab.
C:\Users\alfasim
table
my_pvt_file.tab
In this case, the application will look for the .tab file at C:\Users\alfasim\my_pvt_file.tab
C:\Users\alfasim\my_pvt_file.tab
tables: # PVT name : file path 'Pvt1': my_pvt_file.tab
The PVT name must be unique.
Check the PVTs section for a detailed description of each PVT type option.
[ ... ] pvt_models: default_model: 'Pvt1' tables: 'Pvt1': my_pvt_file.tab [ ... ]
The third step will add two different types of nodes, a mass source node and a pressure node.
All nodes that will be used on the application need to be added over the nodes section of the CaseDescription.
nodes
The NodeDescription is responsible to configure several types of nodes through the node_type field and their respective property fields.
NodeDescription
node_type
For example, when the node_type is mass_source_boundary, besides the fields from NodeDescription only the fields available at mass_source_properties will be considered.
mass_source_boundary
mass_source_properties
And when node_type is pressure_boundary only the fields from pressure_properties will be considered.
pressure_boundary
pressure_properties
Check the Node section for a detailed description of each Node type.
nodes: - name: Inlet node_type: mass_source_boundary mass_source_properties: mass_flow_rates: gas: value: 0.0 unit: kg/s oil: value: 0.0 unit: kg/s - name: Outlet node_type: pressure_boundary pressure_properties: volume_fractions: gas: value: 1.0 unit: '-' oil: value: 0.0 unit: '-' pressure: value: 50.0 unit: bar
The nodes field accepts a list of definitions, and each definition must begin with a dash (-).
So whenever dash (-) character appears, ALFAcase will consider that a new definition is being created.
ALFAcase
nodes: # First Node. - name: Node 1 node_type: mass_source_boundary # Second Node, because it has a dash character. - node_type: pressure_boundary name: Node 2
The fourth step will add a Pipe to the application through the pipes fields.
pipes
The pipes accepts a list of PipeDescription definitions which connects two nodes.
PipeDescription
The connection occurs with the fields source and target and to configure these fields, it is only necessary to inform the name of the NodeDescription that will be used.
source
target
Check the Pipe section for a detailed description of the attributes available.
pipes: - name: pipe source: Inlet target: Outlet profile: length_and_elevation: length: values: [ 0.0, 15.0, 30.0, 30.0, 15.0 ] unit: m elevation: values: [ 0.0, 15.0, 30.0, 30.0, 15.0 ] unit: m segments: start_positions: values: [ 0.0 ] unit: m diameters: values: [ 0.1 ] unit: m roughnesses: values: [ 5e-05 ] unit: m
The final step for our example will add a trend and a profile for our project.
As indicate on CaseDescription, the outputs field must be filled with the definition of CaseOutputDescription which allows the configuration of trends and profiles.
outputs
CaseOutputDescription
trends
profiles
Check the Outputs section for a detailed description about each output type, that shows all the available curves that can be used.
outputs: trends: - element_name: pipe location: main position: value: 100.0 unit: m curve_names: - oil mass flow rate trend_frequency: value: 0.1 unit: s profiles: - element_name: pipe location: main curve_names: - pressure profile_frequency: value: 0.1 unit: s
This section brings together all the previous sections, showing the full example that can be now used and imported by the application.
name: basic_case physics: correlations_package: correlation_package_alfasim hydrodynamic_model: hydrodynamic_model_4_fields numerical_options: tolerance: 1e-4 time_options: minimum_timestep: value: 0.0001 unit: s maximum_timestep: value: 0.5 unit: s final_time: value: 1.0 unit: s pvt_models: default_model: 'Pvt1' tables: 'Pvt1': my_pvt_file.tab outputs: trends: - element_name: pipe location: main position: value: 100.0 unit: m curve_names: - oil mass flow rate trend_frequency: value: 0.1 unit: s profiles: - element_name: pipe location: main curve_names: - pressure profile_frequency: value: 0.1 unit: s pipes: - name: pipe source: Inlet target: Outlet profile: length_and_elevation: length: values: [ 0.0, 15.0, 30.0, 30.0, 15.0 ] unit: m elevation: values: [ 0.0, 15.0, 30.0, 30.0, 15.0 ] unit: m segments: start_positions: values: [ 0.0 ] unit: m diameters: values: [ 0.1 ] unit: m roughnesses: values: [ 5e-05 ] unit: m nodes: - name: Inlet node_type: mass_source_boundary mass_source_properties: mass_flow_rates: gas: value: 0.0 unit: kg/s oil: value: 0.0 unit: kg/s - name: Outlet node_type: pressure_boundary pressure_properties: volume_fractions: gas: value: 1.0 unit: '-' oil: value: 0.0 unit: '-' pressure: value: 50.0 unit: bar
After reading the quick start section and the ALFAcase by example section, check out these additional resources to help better understand all the elements and options available to configure a project:
In progress
This page is a detailed reference guide to ALFAsim-SDK API. It includes a catalog of all supported CaseDescription and ALFAcase capabilities.
Definitions
class CaseDescription name: Optional[str] physics: PhysicsDescription⠀ time_options: TimeOptionsDescription⠀ numerical_options: NumericalOptionsDescription⠀ ipr_models: IPRModelsDescription⠀ pvt_models: PvtModelsDescription⠀ tracers: TracersDescription⠀ outputs: CaseOutputDescription⠀ pipes: List[PipeDescription] nodes: List[NodeDescription] wells: List[WellDescription] materials: List[MaterialDescription] walls: List[WallDescription]
Optional
TimeOptionsDescription
NumericalOptionsDescription
IPRModelsDescription
TracersDescription
List
WellDescription
MaterialDescription
WallDescription
name: string # optional physics: physics_description_schema⠀ time_options: time_options_description_schema⠀ numerical_options: numerical_options_description_schema⠀ ipr_models: ipr_models_description_schema⠀ pvt_models: pvt_models_description_schema⠀ tracers: tracers_description_schema⠀ outputs: case_output_description_schema⠀ pipes: - pipe_description_schema⠀ nodes: - node_description_schema⠀ wells: - well_description_schema⠀ materials: - material_description_schema⠀ walls: - wall_description_schema⠀
physics_description_schema
time_options_description_schema
numerical_options_description_schema
ipr_models_description_schema
pvt_models_description_schema
tracers_description_schema
case_output_description_schema
pipe_description_schema
node_description_schema
well_description_schema
material_description_schema
wall_description_schema
class PhysicsDescription hydrodynamic_model: HydrodynamicModelType⠀ simulation_regime: SimulationRegimeType⠀ energy_model: EnergyModel⠀ solids_model: SolidsModelType⠀ initial_condition_strategy: InitialConditionStrategyType⠀ restart_filepath: Optional[Path] keep_former_results: bool keep_former_results: bool emulsion_model: EmulsionModelType⠀ flash_model: FlashModel⠀ correlations_package: CorrelationPackageType⠀
HydrodynamicModelType
SimulationRegimeType
EnergyModel
SolidsModelType
InitialConditionStrategyType
EmulsionModelType
FlashModel
CorrelationPackageType
hydrodynamic_model: HydrodynamicModelType⠀ simulation_regime: SimulationRegimeType⠀ energy_model: EnergyModel⠀ solids_model: SolidsModelType⠀ initial_condition_strategy: InitialConditionStrategyType⠀ restart_filepath: string # optional keep_former_results: boolean keep_former_results: number emulsion_model: EmulsionModelType⠀ flash_model: FlashModel⠀ correlations_package: CorrelationPackageType⠀
class TimeOptionsDescription stop_on_steady_state: bool stop_on_steady_state: bool initial_time: Scalar⠀ final_time: Scalar⠀ initial_timestep: Scalar⠀ minimum_timestep: Scalar⠀ maximum_timestep: Scalar⠀ restart_autosave_frequency: Scalar⠀ minimum_time_for_steady_state_stop: Scalar⠀
stop_on_steady_state: boolean stop_on_steady_state: number initial_time: value: number unit: string final_time: value: number unit: string initial_timestep: value: number unit: string minimum_timestep: value: number unit: string maximum_timestep: value: number unit: string restart_autosave_frequency: value: number unit: string minimum_time_for_steady_state_stop: value: number unit: string
class NumericalOptionsDescription nonlinear_solver_type: NonlinearSolverType⠀ tolerance: float maximum_iterations: int maximum_timestep_change_factor: float maximum_cfl_value: float relaxed_tolerance: float divergence_tolerance: float friction_factor_evaluation_strategy: EvaluationStrategyType⠀ simulation_mode: SimulationModeType⠀ enable_solver_caching: bool enable_solver_caching: bool caching_rtol: float caching_atol: float always_repeat_timestep: bool always_repeat_timestep: bool
NonlinearSolverType
EvaluationStrategyType
SimulationModeType
nonlinear_solver_type: NonlinearSolverType⠀ tolerance: number maximum_iterations: number maximum_timestep_change_factor: number maximum_cfl_value: number relaxed_tolerance: number divergence_tolerance: number friction_factor_evaluation_strategy: EvaluationStrategyType⠀ simulation_mode: SimulationModeType⠀ enable_solver_caching: boolean enable_solver_caching: number caching_rtol: number caching_atol: number always_repeat_timestep: boolean always_repeat_timestep: number
class CaseOutputDescription trends: List[TrendOutputDescription] trend_frequency: Scalar⠀ profiles: List[ProfileOutputDescription] profile_frequency: Scalar⠀
TrendOutputDescription
ProfileOutputDescription
trends: - trend_output_description_schema⠀ trend_frequency: value: number unit: string profiles: - profile_output_description_schema⠀ profile_frequency: value: number unit: string
trend_output_description_schema
profile_output_description_schema
class ProfileOutputDescription curve_names: List[str] element_name: str location: OutputAttachmentLocation⠀
OutputAttachmentLocation
curve_names: - str element_name: string location: OutputAttachmentLocation⠀
class TrendOutputDescription curve_names: List[str] element_name: str position: Scalar⠀ location: OutputAttachmentLocation⠀
curve_names: - str element_name: string position: value: number unit: string location: OutputAttachmentLocation⠀
Holds a PVT which is used by the simulator to obtain fluid characteristics, such as density and viscosity, given a certain pressure and temperature.
This class is a holder for the different ways the user can enter PVT information in the application.
PvtModelCorrelationDescription] correlations (Dict[str,) – Standard black-oil correlations found in the literature. The user can tune the parameters used by the correlations.
compositions (Dict[str, PvtModelCompositionalDescription]) – Molar fluid compositions with molecular weights and densities for each component. It be light components and/or heavy fractions to be lumped into pseudo-components.
tables (Dict[str, Union[str, Path]]) –
Load a complete PVT table obtained (usually) from lab results and generated by various software. Currently the user can import the table directly from a .tab file or a .alfatable file.
The table parameter must be filled with a dictionary where the keys informs the name of the PVT and the values informs Path to a file with the Pvt model.
The value which holds the Path can be either relative or absolute. The name of the pvt model from the Path can contains a ‘pipe’ character in order to select one of the multiples PVT tables in the same .tab file. Example Absolute Path, using MyPvtModel >>> Path("/home/user/my_file.tab|MyPvtModel") Relative Path, using MyPvtModel >>> Path("./my_file.tab|MyPvtModel")
The value which holds the Path can be either relative or absolute.
The name of the pvt model from the Path can contains a ‘pipe’ character in order to select one of the multiples PVT tables in the same .tab file.
Absolute Path, using MyPvtModel
>>> Path("/home/user/my_file.tab|MyPvtModel")
Relative Path, using MyPvtModel
>>> Path("./my_file.tab|MyPvtModel")
table_parameters (Dict[str, PvtModelTableParametersDescription]) –
INTERNAL USE ONLY
This attribute is populated when exporting a Study to a CaseDescription, and it holds a model representation of a PVT originated from a (.tab / .alfatable) file.
Their usage is directly related to the export of a CaseDescription to a .alfacase/.alfatable file, where the original PVT file cannot be guaranteed to exist therefore the only reproducible way to recreate the PVT is trough the PvtModelTableParametersDescription.
class PvtModelsDescription default_model: Optional[str] tables: Dict[str, Union[str, pathlib.Path]] correlations: Dict[str, PvtModelCorrelationDescription] compositions: Dict[str, PvtModelCompositionalDescription]
Dict
PvtModelCorrelationDescription
PvtModelCompositionalDescription
default_model: string # optional tables: string: string | Path correlations: string: pvt_model_correlation_description_schema⠀ compositions: string: pvt_model_compositional_description_schema⠀
pvt_model_correlation_description_schema
pvt_model_compositional_description_schema
Examples
PvtModelsDescription( default_model="PVT1", tables={ 'PVT1': Path('./my_tab_file.tab') }, )
pvt_models: default_model: PVT1 tables: PVT1: ./my_tab_file.tab
default: Scalar(850.0, “kg/m3”)
default: Scalar(0.9, “kg/m3”)
default: Scalar(150.0, “sm3/sm3”)
default: CorrelationPackage.Standing
class PvtModelCorrelationDescription oil_density_std: Scalar⠀ gas_density_std: Scalar⠀ rs_sat: Scalar⠀ pvt_correlation_package: CorrelationPackage⠀
CorrelationPackage
oil_density_std: value: number unit: string gas_density_std: value: number unit: string rs_sat: value: number unit: string pvt_correlation_package: CorrelationPackage⠀
PvtModelCorrelationDescription( default_model="PVT1", )
some_value: some_other_value: fooo
PvtModelTableParametersDescription
pressure_values (ndarray(shape=(M,1))) – Array like of sorted pressure values (m number of entries). [Pa]
temperature_values (ndarray(shape=(N,1))) – Array like of sorted temperature values (n number of entries). [K]
table_variables (List[ndarray(shape=(MxN,1))]) – List of array like values for each property such as densities, specific heats, enthalpies, etc.
variable_names (List[str]) – List of property names
equation_of_state_type (Scalar) – default: Scalar(850.0, “kg/m3”)
surface_tension_model_type (Scalar) – default: Scalar(0.9, “kg/m3”)
viscosity_model (Scalar) – default: Scalar(150.0, “sm3/sm3”)
heavy_components (List[HeavyComponentDescription]) – default: []
light_components (List[LightComponentDescription]) – default: []
FluidDescription] fluids (Dict[str,) – default: {}
class PvtModelCompositionalDescription equation_of_state_type: EquationOfStateType⠀ surface_tension_model_type: SurfaceTensionType⠀ viscosity_model: PVTCompositionalViscosityModel⠀ heavy_components: List[HeavyComponentDescription] light_components: List[LightComponentDescription] fluids: Dict[str, FluidDescription]
EquationOfStateType
SurfaceTensionType
PVTCompositionalViscosityModel
HeavyComponentDescription
LightComponentDescription
FluidDescription
equation_of_state_type: EquationOfStateType⠀ surface_tension_model_type: SurfaceTensionType⠀ viscosity_model: PVTCompositionalViscosityModel⠀ heavy_components: - heavy_component_description_schema⠀ light_components: - light_component_description_schema⠀ fluids: string: fluid_description_schema⠀
heavy_component_description_schema
light_component_description_schema
fluid_description_schema
class HeavyComponentDescription name: str scn: int MW: Scalar⠀ rho: Scalar⠀
name: string scn: number MW: value: number unit: string rho: value: number unit: string
class LightComponentDescription name: str Pc: Scalar⠀ Tc: Scalar⠀ Vc: Scalar⠀ omega: Scalar⠀ MW: Scalar⠀ Tb: Scalar⠀ Parachor: Scalar⠀ B_parameter: Scalar⠀ Cp_0: Scalar⠀ Cp_1: Scalar⠀ Cp_2: Scalar⠀ Cp_3: Scalar⠀ Cp_4: Scalar⠀
name: string Pc: value: number unit: string Tc: value: number unit: string Vc: value: number unit: string omega: value: number unit: string MW: value: number unit: string Tb: value: number unit: string Parachor: value: number unit: string B_parameter: value: number unit: string Cp_0: value: number unit: string Cp_1: value: number unit: string Cp_2: value: number unit: string Cp_3: value: number unit: string Cp_4: value: number unit: string
class FluidDescription composition: List[CompositionDescription] fraction_pairs: List[BipDescription]
CompositionDescription
BipDescription
composition: - composition_description_schema⠀ fraction_pairs: - bip_description_schema⠀
composition_description_schema
bip_description_schema
Component (str) –
PvtModelCompositionalDescription.light_components PvtModelCompositionalDescription.heavy_components
..note:: CompositionDescription can only refer to components created from the same PvtModelCompositionalDescription
class CompositionDescription component: str molar_fraction: Scalar⠀ reference_enthalpy: Scalar⠀
component: string molar_fraction: value: number unit: string reference_enthalpy: value: number unit: string
class BipDescription component_1: str component_2: str value: float
component_1: string component_2: string value: number
Union[str, IPRDescription]] tables (Dict[str,) – A dictionary with the name of the IPR and the instance of the IPR Model.
class IPRModelsDescription linear_models: Dict[str, LinearIPRDescription] table_models: Dict[str, TableIPRDescription]
LinearIPRDescription
TableIPRDescription
linear_models: string: linear_ipr_description_schema⠀ table_models: string: table_ipr_description_schema⠀
linear_ipr_description_schema
table_ipr_description_schema
class LinearIPRDescription well_index_phase: WellIndexPhaseType⠀ min_pressure_difference: Scalar⠀ well_index: Scalar⠀
WellIndexPhaseType
well_index_phase: WellIndexPhaseType⠀ min_pressure_difference: value: number unit: string well_index: value: number unit: string
class TableIPRDescription well_index_phase: WellIndexPhaseType⠀ table: IPRCurveDescription⠀
IPRCurveDescription
well_index_phase: WellIndexPhaseType⠀ table: ipr_curve_description_schema⠀
ipr_curve_description_schema
class IPRCurveDescription pressure_difference: Array⠀ flow_rate: Array⠀
Array
pressure_difference: values: [number] unit: string flow_rate: values: [number] unit: string
class TracersDescription constant_coefficients: Dict[str, TracerModelConstantCoefficientsDescription]
TracerModelConstantCoefficientsDescription
constant_coefficients: string: tracer_model_constant_coefficients_description_schema⠀
tracer_model_constant_coefficients_description_schema
class TracerModelConstantCoefficientsDescription partition_coefficients: Dict[str, Scalar]
partition_coefficients: string: value: number unit: string
InitialConditionsDescription
class InitialConditionsDescription pressures: InitialPressuresDescription⠀ volume_fractions: InitialVolumeFractionsDescription⠀ tracers_mass_fractions: InitialTracersMassFractionsDescription⠀ velocities: InitialVelocitiesDescription⠀ temperatures: InitialTemperaturesDescription⠀ fluid: Optional[str]
InitialPressuresDescription
InitialVolumeFractionsDescription
InitialTracersMassFractionsDescription
InitialVelocitiesDescription
InitialTemperaturesDescription
pressures: initial_pressures_description_schema⠀ volume_fractions: initial_volume_fractions_description_schema⠀ tracers_mass_fractions: initial_tracers_mass_fractions_description_schema⠀ velocities: initial_velocities_description_schema⠀ temperatures: initial_temperatures_description_schema⠀ fluid: string # optional
initial_pressures_description_schema
initial_volume_fractions_description_schema
initial_tracers_mass_fractions_description_schema
initial_velocities_description_schema
initial_temperatures_description_schema
class InitialPressuresDescription position_input_type: TableInputType⠀ table_x: ReferencedPressureContainerDescription⠀ table_y: ReferencedPressureContainerDescription⠀ table_length: PressureContainerDescription⠀
TableInputType
ReferencedPressureContainerDescription
PressureContainerDescription
position_input_type: TableInputType⠀ table_x: referenced_pressure_container_description_schema⠀ table_y: referenced_pressure_container_description_schema⠀ table_length: pressure_container_description_schema⠀
referenced_pressure_container_description_schema
pressure_container_description_schema
class ReferencedPressureContainerDescription reference_coordinate: Scalar⠀ positions: Array⠀ pressures: Array⠀
reference_coordinate: value: number unit: string positions: values: [number] unit: string pressures: values: [number] unit: string
class PressureContainerDescription positions: Array⠀ pressures: Array⠀
positions: values: [number] unit: string pressures: values: [number] unit: string
class InitialVolumeFractionsDescription position_input_type: TableInputType⠀ table_x: ReferencedVolumeFractionsContainerDescription⠀ table_y: ReferencedVolumeFractionsContainerDescription⠀ table_length: VolumeFractionsContainerDescription⠀
ReferencedVolumeFractionsContainerDescription
VolumeFractionsContainerDescription
position_input_type: TableInputType⠀ table_x: referenced_volume_fractions_container_description_schema⠀ table_y: referenced_volume_fractions_container_description_schema⠀ table_length: volume_fractions_container_description_schema⠀
referenced_volume_fractions_container_description_schema
volume_fractions_container_description_schema
class ReferencedVolumeFractionsContainerDescription reference_coordinate: Scalar⠀ positions: Array⠀ fractions: Dict[str, Array]
reference_coordinate: value: number unit: string positions: values: [number] unit: string fractions: string: values: [number] unit: string
class VolumeFractionsContainerDescription positions: Array⠀ fractions: Dict[str, Array]
positions: values: [number] unit: string fractions: string: values: [number] unit: string
class InitialTracersMassFractionsDescription position_input_type: TableInputType⠀ table_x: ReferencedTracersMassFractionsContainerDescription⠀ table_y: ReferencedTracersMassFractionsContainerDescription⠀ table_length: TracersMassFractionsContainerDescription⠀
ReferencedTracersMassFractionsContainerDescription
TracersMassFractionsContainerDescription
position_input_type: TableInputType⠀ table_x: referenced_tracers_mass_fractions_container_description_schema⠀ table_y: referenced_tracers_mass_fractions_container_description_schema⠀ table_length: tracers_mass_fractions_container_description_schema⠀
referenced_tracers_mass_fractions_container_description_schema
tracers_mass_fractions_container_description_schema
class ReferencedTracersMassFractionsContainerDescription reference_coordinate: Scalar⠀ positions: Array⠀ tracers_mass_fractions: List[Array]
reference_coordinate: value: number unit: string positions: values: [number] unit: string tracers_mass_fractions: - Array
class TracersMassFractionsContainerDescription positions: Array⠀ tracers_mass_fractions: List[Array]
positions: values: [number] unit: string tracers_mass_fractions: - Array
class InitialVelocitiesDescription position_input_type: TableInputType⠀ table_x: ReferencedVelocitiesContainerDescription⠀ table_y: ReferencedVelocitiesContainerDescription⠀ table_length: VelocitiesContainerDescription⠀
ReferencedVelocitiesContainerDescription
VelocitiesContainerDescription
position_input_type: TableInputType⠀ table_x: referenced_velocities_container_description_schema⠀ table_y: referenced_velocities_container_description_schema⠀ table_length: velocities_container_description_schema⠀
referenced_velocities_container_description_schema
velocities_container_description_schema
class ReferencedVelocitiesContainerDescription reference_coordinate: Scalar⠀ positions: Array⠀ velocities: Dict[str, Array]
reference_coordinate: value: number unit: string positions: values: [number] unit: string velocities: string: values: [number] unit: string
class VelocitiesContainerDescription positions: Array⠀ velocities: Dict[str, Array]
positions: values: [number] unit: string velocities: string: values: [number] unit: string
class InitialTemperaturesDescription position_input_type: TableInputType⠀ table_x: ReferencedTemperaturesContainerDescription⠀ table_y: ReferencedTemperaturesContainerDescription⠀ table_length: TemperaturesContainerDescription⠀
ReferencedTemperaturesContainerDescription
TemperaturesContainerDescription
position_input_type: TableInputType⠀ table_x: referenced_temperatures_container_description_schema⠀ table_y: referenced_temperatures_container_description_schema⠀ table_length: temperatures_container_description_schema⠀
referenced_temperatures_container_description_schema
temperatures_container_description_schema
class ReferencedTemperaturesContainerDescription reference_coordinate: Scalar⠀ positions: Array⠀ temperatures: Array⠀
reference_coordinate: value: number unit: string positions: values: [number] unit: string temperatures: values: [number] unit: string
class TemperaturesContainerDescription positions: Array⠀ temperatures: Array⠀
positions: values: [number] unit: string temperatures: values: [number] unit: string
class PipeDescription name: str source: str target: str source_port: Optional[WellConnectionPort⠀] target_port: Optional[WellConnectionPort⠀] pvt_model: Optional[str] profile: ProfileDescription⠀ equipment: EquipmentDescription⠀ environment: EnvironmentDescription⠀ segments: PipeSegmentsDescription⠀ initial_conditions: InitialConditionsDescription⠀
WellConnectionPort
ProfileDescription
EquipmentDescription
EnvironmentDescription
PipeSegmentsDescription
name: string source: string target: string source_port: well_connection_port_schema⠀ # optional target_port: well_connection_port_schema⠀ # optional pvt_model: string # optional profile: profile_description_schema⠀ equipment: equipment_description_schema⠀ environment: environment_description_schema⠀ segments: pipe_segments_description_schema⠀ initial_conditions: initial_conditions_description_schema⠀
well_connection_port_schema
profile_description_schema
equipment_description_schema
environment_description_schema
pipe_segments_description_schema
initial_conditions_description_schema
class PipeSegmentsDescription start_positions: Array⠀ diameters: Array⠀ roughnesses: Array⠀ wall_names: Optional[List[str]]
start_positions: values: [number] unit: string diameters: values: [number] unit: string roughnesses: values: [number] unit: string wall_names: # optional - str
class NodeDescription name: str node_type: NodeCellType⠀ pvt_model: Optional[str] pressure_properties: PressureNodePropertiesDescription⠀ mass_source_properties: MassSourceNodePropertiesDescription⠀ internal_properties: InternalNodePropertiesDescription⠀ separator_properties: SeparatorNodePropertiesDescription⠀
PressureNodePropertiesDescription
MassSourceNodePropertiesDescription
InternalNodePropertiesDescription
SeparatorNodePropertiesDescription
name: string node_type: NodeCellType⠀ pvt_model: string # optional pressure_properties: pressure_node_properties_description_schema⠀ mass_source_properties: mass_source_node_properties_description_schema⠀ internal_properties: internal_node_properties_description_schema⠀ separator_properties: separator_node_properties_description_schema⠀
pressure_node_properties_description_schema
mass_source_node_properties_description_schema
internal_node_properties_description_schema
separator_node_properties_description_schema
class PressureNodePropertiesDescription pressure: Scalar⠀ temperature: Scalar⠀ fluid: Optional[str] tracer_mass_fraction: Array⠀ split_type: MassInflowSplitType⠀ mass_fractions: Dict[str, Scalar] volume_fractions: Dict[str, Scalar] gas_liquid_ratio: Scalar⠀ gas_oil_ratio: Scalar⠀ water_cut: Scalar⠀
MassInflowSplitType
pressure: value: number unit: string temperature: value: number unit: string fluid: string # optional tracer_mass_fraction: values: [number] unit: string split_type: MassInflowSplitType⠀ mass_fractions: string: value: number unit: string volume_fractions: string: value: number unit: string gas_liquid_ratio: value: number unit: string gas_oil_ratio: value: number unit: string water_cut: value: number unit: string
class MassSourceNodePropertiesDescription fluid: Optional[str] tracer_mass_fraction: Array⠀ temperature: Scalar⠀ source_type: MassSourceType⠀ volumetric_flow_rates_std: Dict[str, Scalar] mass_flow_rates: Dict[str, Scalar] total_mass_flow_rate: Scalar⠀ water_cut: Scalar⠀ gas_oil_ratio: Scalar⠀
MassSourceType
fluid: string # optional tracer_mass_fraction: values: [number] unit: string temperature: value: number unit: string source_type: MassSourceType⠀ volumetric_flow_rates_std: string: value: number unit: string mass_flow_rates: string: value: number unit: string total_mass_flow_rate: value: number unit: string water_cut: value: number unit: string gas_oil_ratio: value: number unit: string
class InternalNodePropertiesDescription fluid: Optional[str]
fluid: string # optional
overall_heat_transfer_coefficient –
Q = η A (T_amb - T_sep)
class SeparatorNodePropertiesDescription environment_temperature: Scalar⠀ geometry: SeparatorGeometryType⠀ length: Scalar⠀ overall_heat_transfer_coefficient: Scalar⠀ radius: Scalar⠀ nozzles: Dict[str, Scalar] initial_phase_volume_fractions: Dict[str, Scalar]
SeparatorGeometryType
environment_temperature: value: number unit: string geometry: SeparatorGeometryType⠀ length: value: number unit: string overall_heat_transfer_coefficient: value: number unit: string radius: value: number unit: string nozzles: string: value: number unit: string initial_phase_volume_fractions: string: value: number unit: string
class WellDescription name: str pvt_model: Optional[str] stagnant_fluid: Optional[str] profile: ProfileDescription⠀ casing: CasingDescription⠀ annulus: AnnulusDescription⠀ formation: FormationDescription⠀ top_node: str bottom_node: str environment: EnvironmentDescription⠀ initial_conditions: InitialConditionsDescription⠀ equipment: EquipmentDescription⠀
CasingDescription
AnnulusDescription
FormationDescription
name: string pvt_model: string # optional stagnant_fluid: string # optional profile: profile_description_schema⠀ casing: casing_description_schema⠀ annulus: annulus_description_schema⠀ formation: formation_description_schema⠀ top_node: string bottom_node: string environment: environment_description_schema⠀ initial_conditions: initial_conditions_description_schema⠀ equipment: equipment_description_schema⠀
casing_description_schema
annulus_description_schema
formation_description_schema
class CasingDescription casing_sections: List[CasingSectionDescription] tubings: List[TubingDescription] packers: List[PackerDescription] open_holes: List[OpenHoleDescription]
CasingSectionDescription
TubingDescription
PackerDescription
OpenHoleDescription
casing_sections: - casing_section_description_schema⠀ tubings: - tubing_description_schema⠀ packers: - packer_description_schema⠀ open_holes: - open_hole_description_schema⠀
casing_section_description_schema
tubing_description_schema
packer_description_schema
open_hole_description_schema
class CasingSectionDescription name: str hanger_depth: Scalar⠀ settings_depth: Scalar⠀ hole_diameter: Scalar⠀ outer_diameter: Scalar⠀ inner_diameter: Scalar⠀ inner_roughness: Scalar⠀ material: Optional[str] top_of_filler: Scalar⠀ filler_material: Optional[str] material_above_filler: Optional[str]
name: string hanger_depth: value: number unit: string settings_depth: value: number unit: string hole_diameter: value: number unit: string outer_diameter: value: number unit: string inner_diameter: value: number unit: string inner_roughness: value: number unit: string material: string # optional top_of_filler: value: number unit: string filler_material: string # optional material_above_filler: string # optional
class TubingDescription name: str length: Scalar⠀ outer_diameter: Scalar⠀ inner_diameter: Scalar⠀ inner_roughness: Scalar⠀ material: Optional[str]
name: string length: value: number unit: string outer_diameter: value: number unit: string inner_diameter: value: number unit: string inner_roughness: value: number unit: string material: string # optional
class PackerDescription name: str position: Scalar⠀ material_above: Optional[str]
name: string position: value: number unit: string material_above: string # optional
class OpenHoleDescription name: str length: Scalar⠀ diameter: Scalar⠀ inner_roughness: Scalar⠀
name: string length: value: number unit: string diameter: value: number unit: string inner_roughness: value: number unit: string
class AnnulusDescription has_annulus_flow: bool has_annulus_flow: bool pvt_model: Optional[str] initial_conditions: InitialConditionsDescription⠀ gas_lift_valve_equipment: Dict[str, GasLiftValveEquipmentDescription] top_node: str
GasLiftValveEquipmentDescription
has_annulus_flow: boolean has_annulus_flow: number pvt_model: string # optional initial_conditions: initial_conditions_description_schema⠀ gas_lift_valve_equipment: string: gas_lift_valve_equipment_description_schema⠀ top_node: string
gas_lift_valve_equipment_description_schema
class GasLiftValveEquipmentDescription position: Scalar⠀ diameter: Scalar⠀ valve_type: ValveType⠀ delta_p_min: Scalar⠀ discharge_coeff: Scalar⠀
ValveType
position: value: number unit: string diameter: value: number unit: string valve_type: ValveType⠀ delta_p_min: value: number unit: string discharge_coeff: value: number unit: string
class FormationDescription reference_y_coordinate: Scalar⠀ layers: List[FormationLayerDescription]
FormationLayerDescription
reference_y_coordinate: value: number unit: string layers: - formation_layer_description_schema⠀
formation_layer_description_schema
class FormationLayerDescription name: str start: Scalar⠀ material: Optional[str]
name: string start: value: number unit: string material: string # optional
class MaterialDescription name: str material_type: MaterialType⠀ density: Scalar⠀ thermal_conductivity: Scalar⠀ heat_capacity: Scalar⠀ inner_emissivity: Scalar⠀ outer_emissivity: Scalar⠀ expansion: Scalar⠀ viscosity: Scalar⠀
MaterialType
name: string material_type: MaterialType⠀ density: value: number unit: string thermal_conductivity: value: number unit: string heat_capacity: value: number unit: string inner_emissivity: value: number unit: string outer_emissivity: value: number unit: string expansion: value: number unit: string viscosity: value: number unit: string
class WallDescription name: str inner_roughness: Scalar⠀ wall_layer_container: List[WallLayerDescription]
WallLayerDescription
name: string inner_roughness: value: number unit: string wall_layer_container: - wall_layer_description_schema⠀
wall_layer_description_schema
Used for defining the default walls.
thickness (Scalar) –
material_name (str) –
has_annulus_flow (bool) –
class WallLayerDescription thickness: Scalar⠀ material_name: str has_annulus_flow: bool has_annulus_flow: bool
thickness: value: number unit: string material_name: string has_annulus_flow: boolean has_annulus_flow: number
Describe a pipe by either length and inclination or by X and Y coordinates.
LengthAndElevation (Optional[XAndYDescription]) – A list of points with the length and elevation. The first item MUST always be (0, 0), otherwise a ValueError is raised.
XAndY (Optional[LengthAndElevationDescription]) – A list of points (X, Y), describing the coordinates.
x_and_y and length_and_elevation are mutually exclusive.
class ProfileDescription x_and_y: Optional[XAndYDescription] length_and_elevation: Optional[LengthAndElevationDescription]
x_and_y: x_and_y_description_schema⠀ # optional length_and_elevation: length_and_elevation_description_schema⠀ # optional
x_and_y_description_schema
length_and_elevation_description_schema
XAndYDescription
Describe a pipe with a sequence of coordinates.
class XAndYDescription x: Optional[Array] y: Optional[Array]
x: # optional values: [number] unit: string y: # optional values: [number] unit: string
LengthAndElevationDescription
Describe a pipe with length and elevation.
class LengthAndElevationDescription length: Optional[Array] elevation: Optional[Array]
length: # optional values: [number] unit: string elevation: # optional values: [number] unit: string
class EnvironmentDescription thermal_model: PipeThermalModelType⠀ position_input_mode: PipeThermalPositionInput⠀ reference_y_coordinate: Scalar⠀ md_properties_table: List[EnvironmentPropertyDescription] tvd_properties_table: List[EnvironmentPropertyDescription]
PipeThermalModelType
PipeThermalPositionInput
EnvironmentPropertyDescription
thermal_model: PipeThermalModelType⠀ position_input_mode: PipeThermalPositionInput⠀ reference_y_coordinate: value: number unit: string md_properties_table: - environment_property_description_schema⠀ tvd_properties_table: - environment_property_description_schema⠀
environment_property_description_schema
class EnvironmentPropertyDescription position: Scalar⠀ temperature: Scalar⠀ type: PipeEnvironmentHeatTransferCoefficientModelType⠀ heat_transfer_coefficient: Scalar⠀ overall_heat_transfer_coefficient: Scalar⠀ fluid_velocity: Scalar⠀
PipeEnvironmentHeatTransferCoefficientModelType
position: value: number unit: string temperature: value: number unit: string type: PipeEnvironmentHeatTransferCoefficientModelType⠀ heat_transfer_coefficient: value: number unit: string overall_heat_transfer_coefficient: value: number unit: string fluid_velocity: value: number unit: string
class EquipmentDescription mass_sources: Dict[str, MassSourceEquipmentDescription] pumps: Dict[str, PumpEquipmentDescription] valves: Dict[str, ValveEquipmentDescription] reservoir_inflows: Dict[str, ReservoirInflowEquipmentDescription] heat_sources: Dict[str, HeatSourceEquipmentDescription] compressors: Dict[str, CompressorEquipmentDescription]
MassSourceEquipmentDescription
PumpEquipmentDescription
ValveEquipmentDescription
ReservoirInflowEquipmentDescription
HeatSourceEquipmentDescription
CompressorEquipmentDescription
mass_sources: string: mass_source_equipment_description_schema⠀ pumps: string: pump_equipment_description_schema⠀ valves: string: valve_equipment_description_schema⠀ reservoir_inflows: string: reservoir_inflow_equipment_description_schema⠀ heat_sources: string: heat_source_equipment_description_schema⠀ compressors: string: compressor_equipment_description_schema⠀
mass_source_equipment_description_schema
pump_equipment_description_schema
valve_equipment_description_schema
reservoir_inflow_equipment_description_schema
heat_source_equipment_description_schema
compressor_equipment_description_schema
class MassSourceEquipmentDescription fluid: Optional[str] tracer_mass_fraction: Array⠀ temperature: Scalar⠀ source_type: MassSourceType⠀ volumetric_flow_rates_std: Dict[str, Scalar] mass_flow_rates: Dict[str, Scalar] total_mass_flow_rate: Scalar⠀ water_cut: Scalar⠀ gas_oil_ratio: Scalar⠀ position: Scalar⠀
fluid: string # optional tracer_mass_fraction: values: [number] unit: string temperature: value: number unit: string source_type: MassSourceType⠀ volumetric_flow_rates_std: string: value: number unit: string mass_flow_rates: string: value: number unit: string total_mass_flow_rate: value: number unit: string water_cut: value: number unit: string gas_oil_ratio: value: number unit: string position: value: number unit: string
class PumpEquipmentDescription position: Scalar⠀ type: PumpType⠀ pressure_boost: Scalar⠀ thermal_efficiency: Scalar⠀ table: TablePumpDescription⠀ speed_curve: SpeedCurveDescription⠀ speed_curve_interpolation_type: InterpolationType⠀ flow_direction: FlowDirection⠀
PumpType
TablePumpDescription
SpeedCurveDescription
InterpolationType
FlowDirection
position: value: number unit: string type: PumpType⠀ pressure_boost: value: number unit: string thermal_efficiency: value: number unit: string table: table_pump_description_schema⠀ speed_curve: speed_curve_description_schema⠀ speed_curve_interpolation_type: InterpolationType⠀ flow_direction: FlowDirection⠀
table_pump_description_schema
speed_curve_description_schema
class ValveEquipmentDescription position: Scalar⠀ type: ValveType⠀ diameter: Scalar⠀ flow_direction: FlowDirection⠀ opening_type: ValveOpeningType⠀ opening: Scalar⠀ opening_curve_interpolation_type: InterpolationType⠀ opening_curve: OpeningCurveDescription⠀ cv_table: CvTableDescription⠀
ValveOpeningType
OpeningCurveDescription
CvTableDescription
position: value: number unit: string type: ValveType⠀ diameter: value: number unit: string flow_direction: FlowDirection⠀ opening_type: ValveOpeningType⠀ opening: value: number unit: string opening_curve_interpolation_type: InterpolationType⠀ opening_curve: opening_curve_description_schema⠀ cv_table: cv_table_description_schema⠀
opening_curve_description_schema
cv_table_description_schema
class ReservoirInflowEquipmentDescription pressure: Scalar⠀ temperature: Scalar⠀ fluid: Optional[str] tracer_mass_fraction: Array⠀ split_type: MassInflowSplitType⠀ mass_fractions: Dict[str, Scalar] volume_fractions: Dict[str, Scalar] gas_liquid_ratio: Scalar⠀ gas_oil_ratio: Scalar⠀ water_cut: Scalar⠀ start: Scalar⠀ length: Scalar⠀ productivity_ipr: Optional[str] injectivity_ipr: Optional[str]
pressure: value: number unit: string temperature: value: number unit: string fluid: string # optional tracer_mass_fraction: values: [number] unit: string split_type: MassInflowSplitType⠀ mass_fractions: string: value: number unit: string volume_fractions: string: value: number unit: string gas_liquid_ratio: value: number unit: string gas_oil_ratio: value: number unit: string water_cut: value: number unit: string start: value: number unit: string length: value: number unit: string productivity_ipr: string # optional injectivity_ipr: string # optional
class HeatSourceEquipmentDescription start: Scalar⠀ length: Scalar⠀ power: Scalar⠀
start: value: number unit: string length: value: number unit: string power: value: number unit: string
class CompressorEquipmentDescription position: Scalar⠀ speed_curve: SpeedCurveDescription⠀ reference_pressure: Scalar⠀ reference_temperature: Scalar⠀ constant_speed: Scalar⠀ compressor_type: CompressorSpeedType⠀ speed_curve_interpolation_type: InterpolationType⠀ flow_direction: FlowDirection⠀ table: CompressorPressureTableDescription⠀
CompressorSpeedType
CompressorPressureTableDescription
position: value: number unit: string speed_curve: speed_curve_description_schema⠀ reference_pressure: value: number unit: string reference_temperature: value: number unit: string constant_speed: value: number unit: string compressor_type: CompressorSpeedType⠀ speed_curve_interpolation_type: InterpolationType⠀ flow_direction: FlowDirection⠀ table: compressor_pressure_table_description_schema⠀
compressor_pressure_table_description_schema
class SpeedCurveDescription time: Array⠀ speed: Array⠀
time: values: [number] unit: string speed: values: [number] unit: string
corrected_mass_flow_rate_entries – Equivalent to m * (T/T_ref)**0.5 / (P/P_ref)
class CompressorPressureTableDescription speed_entries: Array⠀ corrected_mass_flow_rate_entries: Array⠀ pressure_ratio_table: Array⠀ isentropic_efficiency_table: Array⠀
speed_entries: values: [number] unit: string corrected_mass_flow_rate_entries: values: [number] unit: string pressure_ratio_table: values: [number] unit: string isentropic_efficiency_table: values: [number] unit: string
class TablePumpDescription speeds: Array⠀ void_fractions: Array⠀ flow_rates: Array⠀ pressure_boosts: Array⠀
speeds: values: [number] unit: string void_fractions: values: [number] unit: string flow_rates: values: [number] unit: string pressure_boosts: values: [number] unit: string
class CvTableDescription opening: Array⠀ flow_coefficient: Array⠀
opening: values: [number] unit: string flow_coefficient: values: [number] unit: string
class OpeningCurveDescription time: Array⠀ opening: Array⠀
time: values: [number] unit: string opening: values: [number] unit: string
This page contains the full reference to constants available for ALFAsim-SDK API.
ConstantSpeed
SpeedCurve
Glaso
Lasater
Standing
VazquezBeggs
Alfasim
Classical
ISDBTests
Options for emulsion properties calculation.
Boxall2012
Brauner2001
Brinkman1952
Brinkman1952AndYeh1964
Hinze1955
ModelDefault
Mooney1951a
Mooney1951b
NoModel
Sleicher1962
Taylor1932
Do not rely on the value of this enum, it is used exclusively for backward compatibility
GlobalModel
LayersModel
EnergyModelPrimaryVariable
Temperature
PengRobinson
SoaveRedlichKwong
Implicit
NewtonExplicit
TimeExplicit
HydrocarbonAndWater
HydrocarbonOnly
Backward
Forward
Informs which base Hydrodynamic model is being used, without any modification from plugins:
TwoFields is valid only for the slug/regime capturing
Two phase (gas and oil) with two fields (continuous gas and continuous oil) using Regime Capturing strategy.
Two phase (gas and oil) with four fields (continuous gas, continuous oil, dispersed gas bubble, and dispersed oil droplet).
Three phase (gas, oil, and water) with five fields (continuous gas, continuous oil, continuous water, dispersed gas bubble, and dispersed liquid droplet). Water does not disperse in any other phase
Three phase (gas, oil, and water) with seven fields (continuous gas, continuous oil, continuous water, gas in oil, gas in water, oil in gas, and water in gas. There is no dispersion of oil in water and water in oil.
Full three phase gas oil water model. Three continuous fields and six dispersed fields.
FiveFieldsCO2
FiveFieldsSolid
FiveFieldsWater
FourFields
ThreeLayersGasOilWater
ThreeLayersNineFieldsGasOilWater
ThreeLayersNoBubbleGasOilWater
ThreeLayersSevenFieldsGasOilWater
ThreeLayersWaterWithCO2
TwoFields
Constant
Restart
SteadyState
Linear
Quadratic
PvtUserGorWc is currently only used for GenKey
ConstantMassFraction
ConstantVolumeFraction
Pvt
PvtUserGlrWc
PvtUserGorWc
AllVolumetricFlowRates
FlowRateGasGorWc
FlowRateOilGorWc
FlowRateWaterGorWc
MassFlowRates
TotalMassFlowRatePvtSplit
Fluid
Solid
MassSource
Pressure
Separator
AlfasimQuasiNewton
NewtonBacktracking
NewtonBasic
Output Attachment Location will tell the location in which this attachment’s data should be retrieved from.
Annulus
Main
CorrespondingStatesPrinciple
LohrenzBrayClark
Overall
WallsAndAir
WallsAndEnvironment
WallsAndWater
AdiabaticWalls
Transient
Md
Tvd
ConstantPressure
TableInterpolation
HorizontalCylinder
Sphere
VerticalCylinder
Default
Robust
Informs which solid model should be used:
Without slip velocity and slurry viscosity
Employs the equilibrium slip velocity model and the Mills (1985) effective dynamic viscosity expression.
This model is more appropriate to use when the solid phase has properties similar to or equal to hydrate. It was fitted by Qin et al. (2018) for hydrates.
Employs the equilibrium slip velocity model and the Thomas (1965) effective dynamic viscosity expression.
Mills1985Equilibrium
Santamaria2010Equilibrium
Thomas1965Equilibrium
Leechien
Schechterguo
Weinaugkatz
Indicates the semantics of a position field
vertical_position: Interpolation will be calculated in relation to the y-axis horizontal_position: Interpolation will be calculated in relation to the x-axis length: Interpolation will be calculated in relation to the pipeline trajectory
horizontal_position
length
vertical_position
TracerModelType
Compositional
ConstantOpening
CheckValve
ChokeValveWithFlowCoefficient
PerkinsValve
Available ports for connecting to a Well node.
LeftAnnulus
RightAnnulus
Top
Gas
Liquid
Oil
Water
EXTRAS_REQUIRED_VERSION_KEY
The dict key which identifies the required version of alfasim-sdk for a given plugin
Constant to identify the gas layer
Constant to identify the gas phase
Constant to identify the oil layer
Constant to identify the oil phase
Constant to identify the water layer
Constant to identify the water phase