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.