Solver Hooks#
The present section describes all solver Hooks available in ALFAsim plugin infrastructure.
Solver Hooks are ALFAsim’s pre-defined functions that allow plugin developer to modify or extend ALFAsim’s Solver.
As already informed in Quick Start section, once created a plugin using new
option
in ALFAsim-SDK’s CLI a new file named plugin.cpp
will be available to implement those hooks.
Note
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.
Initial configuration and plugin internal data#
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 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, plugins internal data can hold the information that will be used during the simulation, which will be available for the other hooks.
Warning
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(ctx)#
c++ signature :
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.
- Parameters:
ctx – ALFAsim’s plugins context
- Returns:
Return OK if successful or anything different if failed
Examples of usage:
A minimal
HOOK_INITIALIZE
needed could be:1ALFAsimSDK_API alfasim_sdk_api; 2 3HOOK_INITIALIZE(ctx) { 4 const char* plugin_id = get_plugin_id() 5 // Loading ALFAsim-SDK API 6 int load_error_code = alfasim_sdk_open(alfasim_sdk_api) 7 if (load_error_code != 0){ 8 return load_error_code; 9 } 10 return OK; 11}
Where
OK
is anerror_code
value andget_plugin_id()
function is created automatically to each plugin template and accessible fromhook_specs.h
file. As can be seen in the example above at least theALFAsim-SDK
API should be loaded.However, if the plugin has internal data the minimal
HOOK_INITIALIZE
implementation would be1ALFAsimSDK_API alfasim_sdk_api; 2 3HOOK_INITIALIZE(ctx) 4{ 5 const char* plugin_id = get_plugin_id() 6 // Loading ALFAsim-SDK API 7 int load_error_code = alfasim_sdk_open(alfasim_sdk_api) 8 if (load_error_code != 0){ 9 return load_error_code; 10 } 11 // Threads Information 12 int n_threads = -1; 13 int errcode = alfasim_sdk_api.get_number_of_threads( 14 ctx, &n_threads); 15 if (errcode != 0){ 16 return errcode; 17 } 18 // Setting internal data to each thread 19 for (int thread_id = 0; thread_id < n_threads; ++thread_id){ 20 double value; 21 alfasim_sdk_api.get_plugin_input_data_quantity( 22 ctx, &value, plugin_id, thread_id); 23 void* data = new double(value); 24 alfasim_sdk_api.set_plugin_data( 25 ctx, plugin_id, data, thread_id); 26 } 27 return OK; 28}
It is important to note that
void* data
at line 22 could be a more complex data structure, like a class object for example.
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.
Note
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.
- finalize(ctx)#
c++ signature :
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.
- Parameters:
ctx – ALFAsim’s plugins context
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_FINALIZE(ctx) 2{ 3 // Threads information 4 int n_threads = -1; 5 int errcode = alfasim_sdk_api.get_number_of_threads(ctx, &n_threads); 6 if (errcode != 0){ // or errcode != OK 7 return errcode; 8 } 9 const char* plugin_id = get_plugin_id(); 10 // Plugin internal data 11 for (int thread_id = 0; thread_id < n_threads; ++thread_id) { 12 void* data = nullptr; 13 errcode = alfasim_sdk_api.get_plugin_data( 14 ctx, &data, plugin_id, thread_id); 15 delete data; 16 } 17 // Unloading ALFAsim-SDK API 18 int load_error_code = alfasim_sdk_close(alfasim_sdk_api) 19 if (load_error_code != 0){ 20 return load_error_code; 21 } 22 return OK; 23}
Where
OK
is anerror_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
.
Note
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.
Update plugin variables#
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 like the pressure, temperature, volume fractions and velocities, called primary variables instead.
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 at the first time step
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP
should be called before because usually during the first time step some initialization tasks are needed. Then,
if any plugin variable needs to be initialized with some value different from the initial nan
value, this hook is the place to do that.
Another possibility is to update secondary variables explicitly on timestep. For that HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_TIME_EXPLICIT
can be used and it will be called once at the end of the timestep. This hook is important in situations where the secondary variable doesn’t affect the solution or when secondary variable computations are extremely heavy,
making computational time prohibitive.
Note
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 depend on network with its discretization and on hydrodynamic model, which defines the fluid flow’s phases, fields and layers.
- update_plugins_secondary_variables(ctx)#
c++ signature :
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.
- Parameters:
ctx – ALFAsim’s plugins context
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES(ctx) 2{ 3 int errcode = -1; 4 int size_U = -1; 5 int size_E = -1; 6 int oil_id = -1; 7 errcode = alfasim_sdk_api.get_field_id( 8 ctx, &oil_id, "oil"); 9 double* vel; 10 VariableScope Fields_OnFaces = { 11 GridScope::FACE, 12 MultiFieldDescriptionScope::FIELD, 13 TimestepScope::CURRENT 14 } 15 errcode = alfasim_sdk_api.get_simulation_array( 16 ctx, &vel, (char*) "U", Fields_OnFaces, oil_id, &size_U); 17 double* kinetic_energy; 18 char* name = "kinetic_energy_of_oil"; 19 int global_idx = 0; 20 errcode = alfasim_sdk_api.get_plugin_variable( 21 ctx, 22 (void**) (&kinetic_energy), 23 name, 24 global_idx, 25 TimestepScope::CURRENT, 26 &size_E); 27 if (size_U != size_E){ 28 return OUT_OF_BOUNDS; 29 } 30 for (int i =0; i < size_U; ++i){ 31 kinetic_energy[i] = vel[i] * vel[i] / 2.; 32 } 33 return OK; 34}
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 theglobal_idx
would be substituted byfield_idx
and it would be performed to each field.
- update_plugins_secondary_variables_on_first_timestep(ctx)#
c++ signature :
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.
- Parameters:
ctx – ALFAsim’s plugins context
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP(ctx) 2{ 3 int errcode = -1; 4 int size_E = -1; 5 double* kinetic_energy; 6 char* name = "kinetic_energy_of_oil"; 7 int global_idx = 0; 8 errcode = alfasim_sdk_api.get_plugin_variable( 9 ctx, 10 (void**) (&kinetic_energy), 11 name, 12 global_idx, 13 TimestepScope::CURRENT, 14 &size_E); 15 for (int i =0; i < size_U; ++i){ 16 kinetic_energy[i] = 0.0; 17 } 18 return OK; 19}
- update_plugins_secondary_variables_time_explicit(ctx)#
c++ signature :
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_TIME_EXPLICIT(void* ctx)
Internal simulator hook to update plugin’s secondary variables time explicit. This is called only once at the end of ALFAsim’s update internal secondary variables workflow.
- Parameters:
ctx – ALFAsim’s plugins context
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_TIME_EXPLICIT(ctx) 2{ 3 int errcode = -1; 4 int size_U = -1; 5 int size_E = -1; 6 int liq_id = -1; 7 errcode = alfasim_sdk_api.get_field_id( 8 ctx, &oil_id, "oil"); 9 double* vel; 10 VariableScope Fields_OnFaces = { 11 GridScope::FACE, 12 MultiFieldDescriptionScope::FIELD, 13 TimestepScope::CURRENT 14 } 15 errcode = alfasim_sdk_api.get_simulation_array( 16 ctx, &vel, (char*) "U", Fields_OnFaces, liq_id, &size_U); 17 double* kinetic_energy; 18 char* name = "kinetic_energy_of_oil"; 19 int global_idx = 0; 20 errcode = alfasim_sdk_api.get_plugin_variable( 21 ctx, 22 (void**) (&kinetic_energy), 23 name, 24 global_idx, 25 TimestepScope::CURRENT, 26 &size_E); 27 if (size_U != size_E){ 28 return OUT_OF_BOUNDS; 29 } 30 for (int i =0; i < size_U; ++i){ 31 kinetic_energy[i] = vel[i] * vel[i] / 2.; 32 } 33 return OK; 34}
In the example above the variable
kinetic_energy_of_oil
was registered as a global variable, but its value is obtained for oil field and only at the end of the time steps’ linear solver (explicit approach). If this variable would be calculated to all fields then theglobal_idx
would be substituted byfield_idx
and it would be performed to each field.
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.
The hook HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER
completes the group of hooks related to the plugins secondary variables.
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.
- update_plugins_secondary_variables_on_tracer_solver(ctx)#
c++ signature :
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.
- Parameters:
ctx – ALFAsim’s plugins context
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER(ctx) 2{ 3 const char* plugin_id = get_plugin_id() 4 int errcode = -1; 5 int size_t = -1; 6 int size_p_var = -1; 7 int liq_id = -1; 8 errcode = alfasim_sdk_api.get_field_id( 9 ctx, &oil_id, "oil"); 10 double* tracer_mass_fraction; 11 VariableScope global_OnCenters = { 12 GridScope::FACE, 13 MultiFieldDescriptionScope::FIELD, 14 TimestepScope::CURRENT 15 } 16 // Tracer information 17 void* tracer_ref; 18 errcode = alfasim_sdk_api.get_tracer_ref_by_name( 19 ctx, 20 &tracer_ref, 21 "my_tracer", // Added by User interface 22 plugin_id); 23 int tracer_id = -1; 24 errcode = alfasim_sdk_api.get_tracer_id( 25 ctx, &tracer_id, tracer_ref); 26 double *tracer_mass_fraction 27 errcode = alfasim_sdk_api.get_simulation_tracer_array( 28 ctx, 29 &tracer_mass_fraction, 30 (char*) "phi", 31 global_OnCenters, 32 tracer_id, 33 0, // GLOBAL 34 &size_t); 35 // Plugin secondary variable array 36 double* plugin_var; 37 errcode = alfasim_sdk_api.get_plugin_variable( 38 ctx, 39 (void**) (&plugin_var), 40 name, 41 0, // GLOBAL 42 TimestepScope::CURRENT, 43 &size_p_var); 44 if (size_t != size_p_var){ 45 return OUT_OF_BOUNDS; 46 } 47 for (int i =0; i < size_t; ++i){ 48 // Do some calculations with plugin_var 49 // using tracer_mass_fraction values 50 } 51 return OK; 52}
Note that functions like
get_tracer_ref_by_name()
,get_tracer_id()
andget_simulation_tracer_array()
were used to obtain information related to tracers.
Warning
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.
Source Terms#
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(ctx, mass_source, n_fields, n_control_volumes)#
c++ signature :
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 byn_fields
andn_control_volumes
. It has unit equal to[kg/s]
.- Parameters:
ctx – ALFAsim’s plugins context
mass_source – Source term of mass equation
n_fields – Number of fields
n_control_volumes – Number of control volumes
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_MASS_SOURCE_TERM( 2 ctx, mass_source, n_fields, n_control_volumes) 3{ 4 int oil_id = -1; 5 errcode = alfasim_sdk_api.get_field_id( 6 ctx, &oil_id, "oil"); 7 // Convertion from void* to double* and getting the 8 // array range related to oil field 9 double* oil_mass_source = 10 (double*) mass_source + n_control_volumes * oil_id; 11 // Make some calculations and add it to oil_mass_source. 12 // In this example, we add a mass source of 3.1415 kg/s to all control volumes. 13 for (int i = 0; i < n_control_volumes; ++i) { 14 oil_mass_source[i] = 3.1415; // [kg/s] 15 } 16 return OK; 17}
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 thatoil_mass_source
has size equal ton_control_volumes
.
- calculate_momentum_source_term(ctx, momentum_source, n_layers, n_faces)#
c++ signature :
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 byn_layers
andn_faces
. It has unit equal to[N]
.- Parameters:
ctx – ALFAsim’s plugins context
momentum_source – Source term of momentum equation
n_layers – Number of layers
n_faces – Number of faces (equal to n_control_volumes minus 1)
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_MOMENTUM_SOURCE_TERM( 2 ctx, momentum_source, n_layers, n_faces) 3{ 4 int gas_id = -1; 5 errcode = alfasim_sdk_api.get_layer_id( 6 ctx, &gas_id, "gas"); 7 // Convertion from void* to double* and getting the 8 // array range related to gas layer 9 double* gas_momentum_source = 10 (double*) momentum_source + n_faces * gas_id; 11 // Make some calculations and add it to gas_momentum_source 12 return OK; 13}
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 thatgas_momentum_source
has size equal ton_faces
.
- calculate_energy_source_term(ctx, energy_source, n_energy_equation, n_control_volumes)#
c++ signature :
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 byn_energy_equation
andn_control_volumes
. It has unit equal to[J/s]
.Since
ALFAsim
considers two energy models, ifn_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 theALFAsim
’s Technical Report for more information about the equations system.- Parameters:
ctx – ALFAsim’s plugins context
energy_source – Source term of energy equation
n_energy_equation – Number of Energy Equation being solved
n_control_volumes – Number of control volumes
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_ENERGY_SOURCE_TERM( 2 ctx, energy_source, n_energy_equation, n_control_volumes) 3{ 4 double* gas_energy_source; 5 if (n_energy_equation > 1){ 6 // Layers Energy model 7 // One energy equation for each layer 8 int gas_id = -1; 9 errcode = alfasim_sdk_api.get_layer_id( 10 ctx, &gas_id, "gas"); 11 // Convertion from void* to double* and getting the 12 // array range related to gas layer 13 gas_energy_source = 14 (double*) energy_source + n_faces * gas_id; 15 } else { 16 // Global energy model 17 // Only one global energy equation 18 19 // Convertion from void* to double* 20 gas_energy_source = (double*) energy_source; 21 } 22 // Make some calculations and add it to gas_energy_source 23 return OK; 24}
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 thatgas_energy_source
has size equal ton_control_volumes
.
- calculate_tracer_source_term(ctx, phi_source, n_tracers, n_control_volumes)#
c++ signature :
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 byn_tracers
andn_control_volumes
. It has unit equal to[kg/s]
.- Parameters:
ctx – ALFAsim’s plugins context
phi_source – Source term of tracers mass equation
n_tracers – Number of tracers
n_control_volumes – Number of control volumes
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_TRACER_SOURCE_TERM( 2 ctx, phi_source, n_tracers, n_control_volumes) 3{ 4 // Tracer information 5 void* tracer_ref; 6 errcode = alfasim_sdk_api.get_tracer_ref_by_name( 7 ctx, 8 &tracer_ref, 9 "my_tracer", // Added by User interface 10 plugin_id); 11 int tracer_id = -1; 12 errcode = alfasim_sdk_api.get_tracer_id( 13 ctx, &tracer_id, tracer_ref); 14 // Convertion from void* to double* and getting the 15 // array range related to gas layer 16 double* my_tracer_phi_source = 17 (double*) phi_source + n_control_volumes * tracer_id; 18 // Make some calculations and add 19 // it to my_tracer_phi_source 20 return OK; 21}
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 thatgas_energy_source
has size equal ton_control_volumes
.
State Variables for additional phases#
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()
.
- initialize_state_variables_calculator(ctx, P, T, T_mix, phi, n_control_volumes, n_layers, n_tracers)#
c++ signature :
HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR(void* ctx, void* P, void* T, void* T_mix, void* phi, int n_control_volumes, int n_layers, int n_tracers)
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.- Parameters:
ctx – ALFAsim’s plugins context
P – Pressure values array
T – Temperature values array
T_mix – Mixture temperature values array
phi – Tracer mass fraction values array
n_control_volumes – Number of control volumes
n_layers – Number of layers
n_tracers – Number of tracers in the system
- Returns:
Return OK if successful or anything different if failed
The
P
andT_mix
have size equal ton_control_volumes
. However,T
has values contiguous in memory and its dimensions are given byn_layers
andn_control_volumes
. Finally,phi
dimensions are given byn_tracers
andn_control_volumes
.Example of usage:
1HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR( 2 ctx, P, T, T_mix, phi, n_control_volumes, n_layers, n_tracers) 3{ 4 // getting plugin internal data 5 int errcode = -1; 6 int thread_id = -1; 7 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 8 if (errcode != OK) { 9 return errcode; 10 } 11 // MyStruct is a developer defined struct to hold 12 // all important information for plugin hooks. 13 MyStruct* data = nullptr; 14 errcode = alfasim_sdk_api.get_plugin_data( 15 ctx, (void**) &data, plugin_id, thread_id); 16 // MyFunction is a function implemented by 17 // plugin developer that computes de density 18 data.density = MyFunction(P, T_mix, n_control_volumes); 19 return OK; 20} 21// Then, to use the cached value: 22HOOK_CALCULATE_STATE_VARIABLE( 23 ctx, P, T, n_control_volumes, phase_id, field_id, property_id, output) 24{ 25 // getting plugin internal data 26 int errcode = -1; 27 int thread_id = -1; 28 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 29 if (errcode != OK) { 30 return errcode; 31 } 32 MyStruct* data = nullptr; 33 errcode = alfasim_sdk_api.get_plugin_data( 34 ctx, (void**) &data, plugin_id, thread_id); 35 if (phase_id != data.my_added_phase_id) { 36 return OK; 37 } 38 if (property_id == StateVariable::RHO) { 39 for (int i = 0; i < n_control_volumes; ++i) { 40 output[i] = data.density[i]; 41 } 42 } 43 return OK; 44}
Note
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(ctx, P, T, n_control_volumes, phase_id, field_id, property_id, output)#
c++ signature :
HOOK_CALCULATE_STATE_VARIABLE(void* ctx, void* P, void* T, int n_control_volumes, int phase_id, int field_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 theget_phase_id()
API function - It is not advisable to use hardcoded numbers).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
- Parameters:
ctx – ALFAsim’s plugins context
P – Pressure values array
T – Temperature values array
n_control_volumes – Number of control volumes
n_phase_id – Id of phase in which the property must be calculated
n_field_id – Id of field in which the property must be calculated (Associated to the phase)
property_id – A
StateVariable
value. It indicates which property must be calculatedoutput – Output values array
- Returns:
Return OK if successful or anything different if failed
The
output
parameter must be filled with the calculated property for each control volume. The pressureP
and layer or mixture temperatureT
(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.In case of calculating all properties and caching them in the
HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR
(depending on the model used inside the plugin) thefield_id
can be used to retrieve the cached properties for a specific field associated to the phase in whichphase_id
is informed. For example, when the energy model for layers is used in a simulation, fields of a phase may be in others layers (“oil in water” is located in the “water” layer) in which the temperature are different.Example of usage:
1HOOK_CALCULATE_STATE_VARIABLE( 2 ctx, P, T, n_control_volumes, phase_id, field_id, property_id, output) 3{ 4 // getting plugin internal data 5 int errcode = -1; 6 int thread_id = -1; 7 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 8 if (errcode != OK) { 9 return errcode; 10 } 11 MyStruct* data = nullptr; 12 errcode = alfasim_sdk_api.get_plugin_data( 13 ctx, (void**) &data, plugin_id, thread_id); 14 if (phase_id != data.my_added_phase_id) { 15 return OK; 16 } 17 if (property_id == StateVariable::RHO) { 18 for (int i = 0; i < n_control_volumes; ++i) { 19 // If the property has a constant value 20 output[i] = data.constant_density; 21 // If the property must be computed 22 // MyStruct has a function called 'compute_density()' 23 output[i] = data.compute_density( 24 (double *)P[i], (double *)T[i]); 25 } 26 } 27 return OK; 28}
Warning
The plugin developer must NOT change any variable other than the output. The
output
size isn_control_volumes
.
- calculate_phase_pair_state_variable(ctx, P, T_mix, n_control_volumes, phase1_id, phase2_id, phase_pair_id, property_id, output)#
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 phase_pair_id, int property_id, void* output)
Hook to calculate the state variable given by the property_id (See
StateVariable
values), for the phase pair (phase1_id, phase2_id) (Note that the phase id is the same as the one retrieved from theget_phase_id()
API function - It is not advisable to use hardcoded numbers).List of affected variables:
-Interfacial Tension
- Parameters:
ctx – ALFAsim’s plugins context
P – Pressure values array
T_mix – Mixture temperature values array
n_control_volumes – Number of control volumes
phase1_id – Id of phase one in which the property must be calculated
phase2_id – Id of phase two in which the property must be calculated
phase_pair_id – Id of the phase pair in which the property must be calculated
property_id – A
StateVariable
value. It indicates which property must be calculatedoutput – Output values array
- Returns:
Return OK if successful or anything different if failed
The output parameter must be filled with the calculated property for each control volume. The pressure
P
and mixture temperatureT_mix
are given in order to perform the calculation. The number of control volumes is also given for convenience.Since the state properties calculated by this hook is performed for phase pairs, the information of the phases involved is provided by the
phase_pair_id
and also by the single phase IDs calledphase1_id
andphase2_id
. To identify whichphase_pair_id
are being passed it is possible to retrieve the phase pair IDs by usingget_phase_pair_id()
.Example of usage:
1HOOK_CALCULATE_PHASE_PAIR_STATE_VARIABLE( 2 ctx, P, T_mix, n_control_volumes, phase1_id, phase2_id, phase_pair_id, property_id, output) 3{ 4 // getting plugin internal data 5 int errcode = -1; 6 int thread_id = -1; 7 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 8 if (errcode != OK) { 9 return errcode; 10 } 11 MyStruct* data = nullptr; 12 errcode = alfasim_sdk_api.get_plugin_data( 13 ctx, (void**) &data, plugin_id, thread_id); 14 int gas_phase_id = -1; 15 errcode = alfasim_sdk_api.get_phase_id( 16 ctx, &gas_phase_id, "gas"); 17 18 if (( 19 (phase1_id == data.my_added_phase_id) 20 && (phase1_id == gas_phase_id) 21 ) || ( 22 (phase1_id == gas_phase_id) 23 && (phase1_id == data.my_added_phase_id) 24 )) 25 { 26 for (int i = 0; i < n_control_volumes; ++i) { 27 // If the property has a constant value 28 output[i] = data.constant_surface_tension; 29 // If the property must be computed 30 // MyStruct has a function 31 // called 'compute_surface_tension()' 32 output[i] = data.compute_surface_tension( 33 (double *)P[i], (double *)T_mix[i]); 34 } 35 } 36 return OK; 37}
Warning
The plugin developer must NOT change any variable other than the output. The
output
size isn_control_volumes
.
- finalize_state_variables_calculator(ctx)#
c++ signature :
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
.- Parameters:
ctx – ALFAsim’s plugins context
- Returns:
Return OK if successful or anything different if failed
If there is no need memory deallocation a minimal implementation would be:
Example of usage:
1HOOK_FINALIZE_STATE_VARIABLES_CALCULATOR(ctx) 2{ 3 return OK; 4}
Additional solid phase#
When a new phase is added to the hydrodynamic model using the AddPhase
type, it is possible
to set it 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(ctx, particle_diameter, n_control_volumes, solid_field_id)#
c++ signature :
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.- Parameters:
ctx – ALFAsim’s plugins context
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.
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_INITIALIZE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS( 2 ctx, particle_diameter, n_control_volumes, solids_field_id) 3{ 4 // getting plugin internal data 5 int errcode = -1; 6 int thread_id = -1; 7 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 8 if (errcode != OK) { 9 return errcode; 10 } 11 MyStruct* data = nullptr; 12 errcode = alfasim_sdk_api.get_plugin_data( 13 ctx, (void**) &data, plugin_id, thread_id); 14 if (solids_field_id != data.my_added_solid_field_id) { 15 return OK; 16 } else { 17 for (int i = 0; i < n_control_volumes; ++i) { 18 // If the particle size is constant 19 particle_diameter[i] = data.constant_particle_size; 20 // The value is calculated 21 // MyStruct has a function 22 // called 'initial_particle_size()' 23 particle_diameter[i] = data.initial_particle_size( 24 // List of params that can be 25 // retrieved by get_simulation_array() 26 ); 27 } 28 } 29 return OK; 30}
- update_particle_diameter_of_solids_fields(ctx, particle_diameter, n_control_volumes, solid_field_id)#
c++ signature :
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
)- Parameters:
ctx – ALFAsim’s plugins context
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.
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_UPDATE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS( 2 ctx, particle_diameter, n_control_volumes, solids_field_id) 3{ 4 // getting plugin internal data 5 int errcode = -1; 6 int thread_id = -1; 7 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 8 if (errcode != OK) { 9 return errcode; 10 } 11 MyStruct* data = nullptr; 12 errcode = alfasim_sdk_api.get_plugin_data( 13 ctx, (void**) &data, plugin_id, thread_id); 14 if (solids_field_id != data.my_added_solid_field_id) { 15 return OK; 16 } else { 17 for (int i = 0; i < n_control_volumes; ++i) { 18 // If the particle size is constant 19 particle_diameter[i] = data.constant_particle_size; 20 // The value is calculated 21 // MyStruct has a function 22 // called 'compute_particle_size()' 23 particle_diameter[i] = data.compute_particle_size( 24 // List of params that can be 25 // retrieved by get_simulation_array() 26 ); 27 } 28 } 29 return OK; 30}
Solids Model#
When a new solid phase is added to the hydrodynamic model using the AddPhase
type, it is
possible to simulate a case with solid phase dispersed in fluids. In this kind of simulation a solids model can be
chosen by the user through ALFAsim’s GUI. Those models are able to calculate the slurry viscosity of the layer
and the slip velocity of the dispersed solid phase. Currently, there are only three solids model available, however
any plugin can add its own solids model. For that, it is necessary to implement the following hooks.
- calculate_relative_slurry_viscosity(ctx, mu_r, solid_field_index, layer_index, n_faces)#
c++ signature :
HOOK_RELATIVE_SLURRY_VISCOSITY(void* ctx, double* mu_r, int solid_field_index, int layer_index, int n_faces)
Internal hook to calculate the relative slurry viscosity in the Solids Model. This hook will be used in the Solids model to calculate the effective viscosity of the slurry (solid field + continuous field).
The relative slurry viscosity is defined by:
\[\begin{equation} \mu_r = \frac{\mu_{eff}}{\mu_c} \end{equation}\]Where
- 1:
\(\mu_r\) is the relative emulsion viscosity
- 2:
\(\mu_{eff}\) is the effective viscosity
- 3:
\(\mu_c\) is the viscosity of the continuous field
The output variable
mu_r
is the relative slurry viscosity with size equal ton_faces
and it is dimensionless. Thesolid_field_index
is the index of the dispersed solid field. Thelayer_index
is the index of the layer and continuous field in the layer (in which the solid field is dispersed).Note
It is important to know that the calculations for viscosity is performed over the faces (see
n_faces
param). For that, any variable that should be retrieved usingget_simulation_array()
must be use valueFACE
in theGridScope
param.This hook allows the implementation of the relative slurry viscosity correlation. Once the plugin installed it is important to be selected in the solids model configuration inside the Physics data tree in the ALFAsim application in order to be used.
- Parameters:
ctx – ALFAsim’s plugins context
mu_r – Relative slurry viscosity
solid_field_index – Index of the dispersed solid field
layer_index – Index of the Layer or Continuous Field
n_faces – Number of faces.
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_RELATIVE_SLURRY_VISCOSITY(ctx, mu_r, solid_field_index, layer_index, n_faces) 2{ 3 const char* plugin_id = get_plugin_id() 4 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 5 if (errcode != OK) { 6 return errcode; 7 } 8 // MyStruct is a developer defined struct to hold 9 // all important information for plugin hooks. 10 MyStruct* data = nullptr; 11 errcode = alfasim_sdk_api.get_plugin_data(ctx, (void**) &data, plugin_id, thread_id); 12 if (errcode != OK) { 13 return errcode; 14 } 15 16 // compute the relative slurry viscosity using your own correlation 17 for (int i = 0; i < n_faces; ++i){ 18 mu_r[i] = relative_slurry_viscosity[i]; 19 } 20 21 return OK; 22}
- calculate_slip_velocity(ctx, U_slip, solid_field_index, layer_index, n_faces)#
c++ signature :
HOOK_CALCULATE_SLIP_VELOCITY(void* ctx, double* U_slip, int solid_field_index, int layer_index, int n_faces)
Internal hook to calculate slip velocity in the Solids Model. This hook will be used in the solids model to calculate the slip velocity between fluid and solid phase.
The output variable
U_slip
is the slip velocity with size equal ton_faces
and it is dimensionless. Thesolid_field_index
is the index of the dispersed solid field. Thelayer_index
is the index of the layer and continuous field in the layer (in which the solid field is dispersed).Note
It is important to know that the calculations for velocity is performed over the faces (see
n_faces
param). For that, any variable that should be retrieved usingget_simulation_array()
must be use valueFACE
in theGridScope
param.- Parameters:
ctx – ALFAsim’s plugins context
U_slip – Slip velocity between fluid and solid phase
solid_field_index – Index of the dispersed solid field
layer_index – Index of the Layer or Continuous Field
n_faces – Number of faces.
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_SLIP_VELOCITY(ctx, U_slip, disp_field_index, layer_index, n_faces) 2{ 3 const char* plugin_id = get_plugin_id() 4 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 5 if (errcode != OK) { 6 return errcode; 7 } 8 // MyStruct is a developer defined struct to hold 9 // all important information for plugin hooks. 10 MyStruct* data = nullptr; 11 errcode = alfasim_sdk_api.get_plugin_data(ctx, (void**) &data, plugin_id, thread_id); 12 if (errcode != OK) { 13 return errcode; 14 } 15 16 // compute the slip velocity using your own correlation 17 for (int i = 0; i < n_faces; ++i){ 18 U_slip[i] = slip_velocity[i]; 19 } 20 21 return OK; 22}
Internal deposit layer#
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. In this case, the thickness of the deposited layer on a given
phase should be calculated through the usage of update_internal_deposition_layer()
. By default, the layer
thickness will be considered equal to zero meters.
- update_internal_deposition_layer(ctx, phase_id, thickness_variation_rate, density, heat_capacity, thermal_conductivity, n_control_volumes)#
c++ signature :
HOOK_UPDATE_INTERNAL_DEPOSITION_LAYER(void* ctx, int* phase_id, void* thickness_variation_rate, void* density, void* heat_capacity, void* thermal_conductivity, int n_control_volumes)
Internal simulator hook to evaluate the deposition volumetric rate and thermal properties of the deposited layer on pipeline walls. This is called for accounting the inner diameter reduction and wall thermal effects.
The plugin is supposed to change
thickness_variation_rate
,density
,heat_capacity
,thermal_conductivity
array pointers, as well as the integer value phase_id. The array pointers must be contiguous in memory and their dimension is given byn_control_volumes
.- Parameters:
ctx – ALFAsim’s plugins context
phase_id – Id of phase that is being deposited on pipe walls
thickness_variation_rate – Rate of change of deposition layer thickness
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)]
n_control_volumes – Number of control volumes
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_UPDATE_INTERNAL_DEPOSITION_LAYER( 2 ctx, phase_id, thickness_variation_rate, density, heat_capacity, thermal_conductivity, n_control_volumes) 3{ 4 auto errcode = -1; 5 6 double dt = -1.0; 7 errcode = alfasim.get_simulation_quantity( 8 ctx, &dt, TimestepScope::CURRENT, (char*) "dt"); 9 if (errcode != 0) { 10 return errcode; 11 } 12 13 int phase_wax_id = -1; 14 errcode = alfasim.get_phase_id(ctx, &phase_wax_id, "wax"); 15 if (errcode != 0) { 16 return errcode; 17 } 18 *phase_id = phase_wax_id; 19 20 // Handle first time step. At this point there is no data from previous time step. 21 double current_time = -1.0; 22 errcode = alfasim.get_simulation_quantity( 23 ctx, ¤t_time, TimestepScope::CURRENT, (char*) "time"); 24 if (errcode != 0) { 25 return errcode; 26 } 27 28 double wax_density = 900.0 // [kg/m3] 29 double wax_heat_capacity = 2140.0 // [J/(kg.K)] 30 double wax_thermal_conductivity = 0.25 // [W/(m.K)] 31 32 if (current_time == 0.0){ 33 // Set a value for the deposition layer thickness 34 for (int i = 0; i < n_control_volumes; ++i) { 35 (double*) thickness_variation_rate[i] = 0.0; // [m] 36 (double*) density[i] = wax_density; // [kg/m3] 37 (double*) heat_capacity[i] = wax_heat_capacity; // [J/(kg.K)] 38 (double*) thermal_conductivity[i] = wax_thermal_conductivity; // [W/(m.K)] 39 } 40 } else{ 41 // Calculate the variation of the deposition layer in one time step 42 double* d_deposit_layer_dt = 0.0001; // [m/s] 43 44 // Sum this variation with the thickness of the older time step 45 for (int i = 0; i < n_control_volumes; ++i) { 46 (double*) thickness_variation_rate[i] = d_deposit_layer_dt; // [m3/s] 47 (double*) density[i] = wax_density; // [kg/m3] 48 (double*) heat_capacity[i] = wax_heat_capacity; // [J/(kg.K)] 49 (double*) thermal_conductivity[i] = wax_thermal_conductivity; // [W/(m.K)] 50 } 51 } 52 53 return OK; 54}
In the example above is shown how to manage the
thickness
,density
,heat_capacity
andthermal_conductivity
arrays for each control volume. Note that thethickness
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.
Unit Cell Model (UCM) Friction Factor#
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.
Note
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.
- calculate_ucm_friction_factor_stratified(ctx, ff_wG, ff_wL, ff_i)#
c++ signature :
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
andff_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 stratified flow.
- Parameters:
ctx – ALFAsim’s plugins context
ff_wG – Gas-Wall Friction Factor
ff_wL – Liquid-Wall Friction Factor
ff_i – Interfacial Gas-Liquid Friction Factor
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_UCM_FRICTION_FACTOR_STRATIFIED(ctx, ff_wG, ff_wL, ff_i) 2{ 3 int errcode = -1; 4 int G = TwoPhaseSystem::GAS; 5 int L = TwoPhaseSystem::LIQUID; 6 7 // Getting friction factor input data from context 8 double alpha[2]; 9 errcode = alfasim_sdk_api.get_ucm_friction_factor_input_variable( 10 ctx, &alpha[G], "alpha", TwoPhaseSystem::GAS); 11 if (errcode != OK){ return errcode; } 12 errcode = alfasim_sdk_api.get_ucm_friction_factor_input_variable( 13 ctx, &alpha[L], "alpha", TwoPhaseSystem::LIQUID); 14 if (errcode != OK){ return errcode; } 15 // And so on to each friction factor input variable 16 // U(velocities), rho(densities), mu(viscosities) and D(pipe diameter) 17 18 // Getting the fluid geometrical properties 19 double S_w[2]; 20 double S_i; 21 double H[2]; 22 errcode = alfasim_sdk_api.get_ucm_fluid_geometrical_properties( 23 ctx, S_w, &S_i, H, alpha[G], D); 24 if (errcode != OK){ return errcode; } 25 26 // Compute the friction factors using your own correlation. 27 // Also, using the variables: alpha, U, rho, mu, D, S_w, S_i and H 28 29 *ff_wG = gas_wall_ff; 30 *ff_wL = liq_wall_ff; 31 *ff_i = gas_liq_ff; 32 33 return OK; 34}
- calculate_ucm_friction_factor_annular(ctx, ff_wG, ff_wL, ff_i)#
c++ signature :
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
andff_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.
- Parameters:
ctx – ALFAsim’s plugins context
ff_wG – Gas-Wall Friction Factor
ff_wL – Liquid-Wall Friction Factor
ff_i – Interfacial Gas-Liquid Friction Factor
- Returns:
Return OK if successful or anything different if failed
- Example of usage:
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.
Note
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.
Liquid-Liquid Mechanistic Model#
ALFAsim’s resulting multiphase model is a one-dimensional system of nonlinear equations, which is a result of some averaging steps that transform a local instantaneous three-dimensional model into a one-dimensional multiphase (and multi-field) model. The derived variables that form the nonlinear differential equations represent average values at a given point in time and space. It is clear that in this averaging process there are important phenomena that will no longer be naturally captured from the equations and therefore one of the strategies is to incorporate all the physics that have been lost in the averaging process in the shear stress term in order to accurately represent the physical behavior. Hence the shear stress is one of the most important parameters for characterizing the quality of a one-dimensional multiphase model.
The main goal of the mechanistic model is to calculate the friction pressure drop as well as the steady-state volume fractions and velocities. ALFAsim supports two-phase (gas-liquid) and three-phase (gas-oil-water) flows, but for three-phase flow it is required a plugin that handles the oil-water system.
Note
Note that the two-phase (Gas-Liquid) Mechanistic Model can be used for both two and three-phase flows (Fluid FLow Type selected by the user in ALFAsim). When no Liquid-Liquid System is implemented by the plugin, the three-phase flow is adapted to work with the traditional two-phase Mechanistic Model, in which all liquid phases are considered as only one.
In the gas-liquid system the liquid phase is considered as a sum of all liquid phases, and the model take into account only the interaction behavior between these two phases (Gas and Liquid). Of course, this kind of approach brings some limitations, since the behavior of the oil and water in the liquid phase is considered nearly homogeneous (mixture). On the other hand, if the liquid-liquid system considers the interaction between oil and water, it introduces a better modeling and representation of the tree-phase system. In fact, considering the interaction between the oil and water phases, behaviors such as emulsion formation (oil dominated or water dominated) and stratified flow can be taken into account together with the gas-liquid system.
The ALFAsim’s Mechanistic Model of three-phase system is divided into two steps, one for gas-liquid system and one for liquid-liquid system in which the complete representation uses an incremental approach. The two phase systems (Gas-Liquid and Liquid-Liquid) model different behaviors and are coupled in the three-phase system algorithm. First the Mechanistic Model for gas-liquid system is solved, considering a single liquid phase (Oil and Water mixture), after that the Mechanistic Model for liquid-liquid system is solved, considering independent oil and water phases. Finally, the properties of liquid phase are updated taking into account the solution of Mechanistic model for liquid-liquid system.
To make possible the liquid-liquid system modeling via plugin, four Hooks are available in the ALFAsim-SDK, three of them to estimate/compute properties that depends on Oil-Water interaction (Flow Pattern, Viscosity and surface tension) and one to properly compute the shear force of each liquid phase and between them. Other associated variables are required in each Liquid-Liquid system plugin hooks. In the sequence, they are presented
Warning
The hooks described in this section must be implemented all of them or none of them. If just part of four hooks are implemented, the ALFAsim will show an error of configuration.
Note
Note that the all of the hooks related to the liquid-liquid system of Mechanistic Model can use the same emulsion
viscosity model used internally by ALFAsim. It can be obtained by using the helper function get_relative_emulsion_viscosity()
.
Since the liquid-liquid system is an emulsion, this helper function is important to keep the consistency between
ALFAsim and its plugins that implement the following hooks.
- calculate_liq_liq_flow_pattern(ctx, ll_fp, water_vol_frac)#
c++ signature :
HOOK_CALCULATE_LIQ_LIQ_FLOW_PATTERN(void* ctx, int* ll_fp, double* water_vol_frac)
Internal hook to calculate the liquid-liquid flow pattern (Oil-Water) and the water volume fraction in the Liquid-Liquid system. The Liquid-Liquid system is a two phase flow with Oil and Water Phases. It represents the separation of Liquid phase (into oil and water phases) used in the two phase system (Gas-Liquid). The output variables
ll_fp
andwater_vol_frac
are the liquid-liquid flow pattern and volume fraction of water, respectively.Note
The main input variables needed to estimate the flow pattern is available in the API function
get_liq_liq_flow_pattern_input_variable()
. Note that, the variables listed in the documentation of the cited function are related to one control volume, in which the estimation is applied.This hook allows the developer to implement your own flow pattern estimation algorithm for the liquid-liquid system.
The
ll_fp
must be one of the following values:
- 0 - Unknown: Unknown Flow Pattern.
- 1 - Ambivalent: Ambivalent Flow Pattern between Dispersed Oil and Dispersed Water.
- 2 - Dispersed Oil: Dispersed oil in continuous water.
- 3 - Dispersed Water: Dispersed water in continuous Oil.
- 4 - Separated: Separated continuous oil and continuous water.
- 5 - Separated Wavy: Separated with waves.
- 6 - Separated Mixed: Separated with dispersed oil and water droplets.Any value different from these values will be assumed an Unknown flow pattern.
- Parameters:
ctx – ALFAsim’s plugins context
ll_fp – Liquid-Liquid Flow Pattern
water_vol_frac – Volume fraction of water in the Liquid-Liquid System
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_LIQ_LIQ_FLOW_PATTERN(ctx, ll_fp, water_vol_frac) 2{ 3 int errcode = -1; 4 int O = LiquidLiquidSystem::OIL; 5 int W = LiquidLiquidSystem::WATER; 6 7 // Getting liq-liq Flow Pattern input data from context 8 double rho[2]; 9 errcode = alfasim_sdk_api.get_liq_liq_flow_pattern_input_variable( 10 ctx, &rho[O], "rho", LiquidLiquidSystem::OIL); 11 if (errcode != OK){ return errcode; } 12 errcode = alfasim_sdk_api.get_liq_liq_flow_pattern_input_variable( 13 ctx, &rho[W], "rho", LiquidLiquidSystem::WATER); 14 if (errcode != OK){ return errcode; } 15 // And so on to each input variable 16 // U_S(superficial velocities), mu(viscosities) 17 // and D_h(liquid hydraulic diameter) 18 19 // Estimate the liquid-liquid Flow pattern and volume fraction of water 20 // using your own algorithm. 21 22 *ll_fp = flow_pattern; 23 *water_vol_frac = alpha_W; 24 25 return OK; 26}
- calculate_liquid_effective_viscosity(ctx, mu_l_eff, ll_fp)#
c++ signature :
HOOK_CALCULATE_LIQUID_EFFECTIVE_VISCOSITY(void* ctx, double* mu_l_eff, int ll_fp)
Internal hook to calculate the liquid (Oil-Water) effective viscosity in the Liquid-Liquid system. It represents viscosity of a Liquid phase used in the two phase system (Gas-Liquid). The output variable
mu_l_eff
is the Liquid Effective Viscosity. It has unit equal to[Pa.s]
.Note
The main input variables needed to estimate the liquid effective viscosity is available in the API function
get_liquid_effective_viscosity_input_variable()
. Note that, the variables listed in the documentation of the cited function are related to one control volume, in which the estimation is applied.This hook allows the developer to implement your own liquid effective viscosity correlation to represent the viscosity of an unified liquid phase that represents the Oil-Water mixture.
- Parameters:
ctx – ALFAsim’s plugins context
mu_l_eff – Liquid Effective Viscosity
ll_fp – Liquid-Liquid Flow Pattern (see
HOOK_CALCULATE_LIQ_LIQ_FLOW_PATTERN
for possible values)
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_LIQUID_EFFECTIVE_VISCOSITY(ctx, mu_l_eff, ll_fp) 2{ 3 int errcode = -1; 4 int O = LiquidLiquidSystem::OIL; 5 int W = LiquidLiquidSystem::WATER; 6 7 // Getting liquid Effective Viscosity input data from context 8 double rho[2]; 9 errcode = alfasim_sdk_api.get_liquid_effecticve_viscosity_input_variable( 10 ctx, &rho[O], "rho", LiquidLiquidSystem::OIL); 11 if (errcode != OK){ return errcode; } 12 errcode = alfasim_sdk_api.get_liquid_effecticve_viscosity_input_variable( 13 ctx, &rho[W], "rho", LiquidLiquidSystem::WATER); 14 if (errcode != OK){ return errcode; } 15 // And so on to each input variable 16 // U_S(superficial velocities), mu(viscosities for Oil and Water) and 17 // D_h(liquid hydraulic diameter) 18 19 // Estimate the liquid effective viscosity using your own algorithm. 20 // Since the liquid effective viscosity depends on Liquid-Liquid Flow Pattern, 21 // it is provide as an Hook parameter (`ll_fp`). 22 23 *mu_l_eff = liquid_viscosity; 24 25 return OK; 26}
- calculate_gas_liq_surface_tension(ctx, sigma_gl, ll_fp)#
c++ signature :
HOOK_CALCULATE_GAS_LIQ_SURFACE_TENSION(void* ctx, double* sigma_gl, int ll_fp)
Internal hook to calculate the Gas-liquid Surface Tension based in the Liquid-Liquid System. It represents Gas-Liquid surface tension used in the two phase system (Gas-Liquid). The output variable
sigma_gl
is the Gas-Liquid Surface tension. It has unit equal to[N/m]
.Note
The main input variables needed to estimate the Gas-Liquid Surface Tension is available in the API function
get_gas_liq_surface_tension_input_variable()
. Note that, the variables listed in the documentation of the cited function are related to one control volume, in which the estimation is applied.This hook allows the developer to implement your own Gas-liquid Surface Tension correlation for an unified liquid phase that represents the Oil-Water mixture.
Note
It is important to note that the Gas-Liquid Surface tension depends on Gas-Oil and Gas-Water Surface Tensions from Liquid-Liquid system. Since it depends on the Liquid-Liquid Flow pattern, the Gas-Liquid Surface Tension must take it into account.
- Parameters:
ctx – ALFAsim’s plugins context
sigma_gl – Gas-Liquid Surface Tension
ll_fp – Liquid-Liquid Flow Pattern (see
HOOK_CALCULATE_LIQ_LIQ_FLOW_PATTERN
for possible values)
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_GAS_LIQ_SURFACE_TENSION(ctx, sigma_gl, ll_fp) 2{ 3 int errcode = -1; 4 int O = LiquidLiquidSystem::OIL; 5 int W = LiquidLiquidSystem::WATER; 6 7 // Getting liquid Effective Viscosity input data from context 8 double sigma_gll[2]; 9 errcode = alfasim_sdk_api.get_gas_liq_surface_tension_input_variable( 10 ctx, &sigma_gll[O], "sigma_gll", LiquidLiquidSystem::OIL); 11 if (errcode != OK){ return errcode; } 12 // And so on to each input variable 13 // sigma_gw(Surface tension Gas-Water) and alpha_w(Water Volume Fraction) 14 15 // Estimate the Gas-Liquid Surface Tension using your own algorithm. 16 // Since the Gas-Liquid Surface Tension depends on Liquid-Liquid Flow Pattern, 17 // it is provide as an Hook parameter (`ll_fp`). 18 19 *sigma_gl = gas_liq_sigma; 20 21 return OK; 22}
- calculate_liq_liq_shear_force_per_volume(ctx, shear_w, shear_i, u_fields, vol_frac_fields, ll_fp)#
c++ signature :
HOOK_CALCULATE_LIQ_LIQ_SHEAR_FORCE_PER_VOLUME(void* ctx, double* shear_w, double* shear_i, double* u_fields, double* vol_frac_fields, int ll_fp)
Internal hook to calculate the Shear Force per unit volume for the Liquid-Liquid System. Also Field velocities and field volume fraction must be calculated. It is important to compute the shear stress term in the momentum equation for the Liquid-Liquid System.
Note
The main input variables needed to estimate the Shear Force is available in the API function
get_liq_liq_shear_force_per_volume_input_variable()
. Note that, the variables listed in the documentation of the cited function are related to one control volume, in which the estimation is applied.The output variable
shear_w
is the Wall Shear Force per unit Volume with size equal to2
(for Oil and Water phases) and it has unit equal to[N/m^3]
. The output variableshear_i
is the Interfacial Shear Force per unit Volume between Oil and Water phases it has unit equal to[N/m^3]
. The output variableu_fields
is the field velocities with size4
because values for continuous fields (Oil and Water) and for dispersed fields (Oil Droplet in Water and Water Droplet in Oil) must be provided and it has unit equal to[m/s]
. The output variablevol_frac_fields
is the field volume fractions also with size4
, just likeu_fields
and it has unit equal to[kg of field/ kg of liquid-liquid mixture]
.Note
The outputs
u_fields
andvol_frac_fields
are vectors in which the order of the fields are Oil Continuous(O
) for index 0, Water Continuous(W
) for index 1, Oil Droplet in Water(OW
) for index 3 and Water Droplets in Oil(WO
) for index 4. See the example below.This hook allows the implementation of the shear force for the Liquid-Liquid System,an important output of the Unit Cell Model. Since this kind of calculation depends on Liquid-Liquid Flow Pattern, it is provided as an hook parameter.
- Parameters:
ctx – ALFAsim’s plugins context
shear_w – Wall Shear Force per unit Volume
shear_i – Interfacial (Oil-Water) Shear Force per unit Volume
u_fields – Field Velocities
vol_frac_fields – Field Voluem Fraction
ll_fp – Liquid-Liquid Flow Pattern (see
HOOK_CALCULATE_LIQ_LIQ_FLOW_PATTERN
for possible values)
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_LIQ_LIQ_SHEAR_FORCE_PER_VOLUME(ctx, shear_w, 2 shear_i, U_fields, vol_frac_fields, ll_fp) 3{ 4 int errcode = -1; 5 int O = 0; 6 int W = 1; 7 int OW = 2; 8 int WO = 3; 9 10 // Getting shear term input data from context 11 double rho[2]; 12 errcode = alfasim_sdk_api.get_liq_liq_shear_force_per_volume_input_variable( 13 ctx, &rho[O], "rho", LiquidLiquidSystem::OIL); 14 if (errcode != OK){ return errcode; } 15 errcode = alfasim_sdk_api.get_liq_liq_shear_force_per_volume_input_variable( 16 ctx, &rho[W], "rho", LiquidLiquidSystem::WATER); 17 if (errcode != OK){ return errcode; } 18 // And so on to each input variable 19 // U_S(superficial velocities), mu(viscosities for Oil and Water) and 20 // D_h(liquid hydraulic diameter) 21 22 // Calculate the wall and interfacial shear force per unit volume, fields (Liquid-Liquid System) 23 // velocities and fields (Liquid-Liquid System) volume fraction using your own algorithm. 24 25 shear_w[O] = wall_shear_force[O]; 26 shear_w[W] = wall_shear_force[W]; 27 *shear_i = interfacial_shear_force; 28 u_fields[O] = U[O]; 29 u_fields[W] = U[W]; 30 u_fields[OW] = U[OW]; 31 u_fields[WO] = U[WO]; 32 vol_frac_fields[O] = alpha[O]; 33 vol_frac_fields[W] = alpha[W]; 34 vol_frac_fields[OW] = alpha[OW]; 35 vol_frac_fields[WO] = alpha[WO]; 36 37 return OK; 38}
Emulsion Model#
When a simulation case uses a three-phase flow model, ALFAsim allows to select an emulsion model that will update the layer viscosity related to the emulsion. In that case, a relative emulsion viscosity correlation is used to calculate it. In order to allow the emulsion model customization, the plugin structure has a hook that accept the implementation of a relative emulsion viscosity correlation.
- calculate_relative_emulsion_viscosity(ctx, mu_r, mu_disp, mu_cont, alpha_disp_in_layer, T, water_in_oil)#
c++ signature :
HOOK_RELATIVE_EMULSION_VISCOSITY(void* ctx, double* mu_r, double mu_disp, double mu_cont, double alpha_disp_in_layer, double T, bool water_in_oil)
Internal hook to calculate the relative emulsion viscosity of an oil-water dispersion (emulsion)
The relative emulsion viscosity is defined by:
\[\begin{equation} \mu_r = \frac{\mu_m}{\mu_c} \end{equation}\]Where
- 1:
\(\mu_r\) is the relative emulsion viscosity
- 2:
\(\mu_m\) is the apparent viscosity
- 3:
\(\mu_c\) is the viscosity of the continuous field
The output variable
mu_r
is the relative emulsion viscosity,mu_disp
is the dispersed field viscosity,mu_cont
is the continuous field viscosity andalpha_disp_in_layer
is the volume fraction of dispersed field in the layer (dispersed field plus continuous field), T is the fluid temperature, and water_in_oil is true when water is the dispersed phase and false otherwise.This hook allows the implementation of the relative emulsion viscosity correlation. Once the plugin installed it is important to be selected in the emulsion model configuration inside the Physics data tree in the ALFAsim application in order to be used.
- Parameters:
ctx – ALFAsim’s plugins context
mu_r – Relative emulsion viscosity
mu_disp – Dispersed field viscosity
mu_cont – Continuous field viscosity
alpha_disp_in_layer – Volume fraction of dispersed field in layer.
T – Fluid temperature
water_in_oil – True when water is the dispersed phase
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_RELATIVE_EMULSION_VISCOSITY(ctx, mu_r, mu_disp, mu_cont, alpha_disp_in_layer, T, water_in_oil) 2{ 3 // Einstein (1906) relative viscosity model 4 mu_r = 1.0 + 2.5 * alpha_disp_in_layer; 5 6 return OK; 7}
Warning
The relative emulsion viscosity hook has a limited API. Therefore the user-implemented correlations will have
access only to dispersed field viscosity, continuous field viscosity and volume fraction of the dispersed phase.
These variables are passed as arguments of the hook signature. For this hook only the API functions
get_field_id()
, get_phase_id()
and get_layer_id()
are available, any other API
function will return an error code different from OK
(error_code
values) if called from this hook.
User Defined Tracers#
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.
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.
These hooks can modify the tracer transport equation from the initialization to configuration of boundary conditions. The plugin developer has full freedom to modify 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(ctx, phi_initial, tracer_index)#
c++ signature :
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.
- Parameters:
ctx – ALFAsim’s plugins context
phi_initial – Initial mass fraction of tracer in respect to the mass of the mixture
tracer_index – Tracer ID
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_INITIALIZE_MASS_FRACTION_OF_TRACER( 2 ctx, phi_initial, tracer_index) 3{ 4 // getting plugin internal data 5 int errcode = -1; 6 int thread_id = -1; 7 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 8 if (errcode != OK) { 9 return errcode; 10 } 11 MyStruct* data = nullptr; 12 errcode = alfasim_sdk_api.get_plugin_data( 13 ctx, (void**) &data, plugin_id, thread_id); 14 if (tracer_index != data.my_user_defined_tracer_id) { 15 return OK; 16 } else { 17 // Set a initial value to the tracer mass fraction 18 // phi_initial has size equal to 1 19 *static_cast<double*>(phi_initial) = 0.0; 20 } 21 return OK; 22}
- calculate_mass_fraction_of_tracer_in_phase(ctx, phi, phi_phase, tracer_index, phase_index, n_control_volumes)#
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)
Internal tracer model Hook to calculate the mass fraction of tracer, given by
tracer_index
, in phase, given byphase_index
. The input variablephi
is the mass fraction of the given tracer in respect to the mass of the mixture. The output variablephi_phase
is the mass fraction of the given tracer in respect to the mass of the given phase. Bothphi
andphi_phase
have size equal ton_control_volumes
.- Parameters:
ctx – ALFAsim’s plugins context
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
tracer_index – Tracer ID
phase_index – Phase ID
n_control_volumes – Number of control volumes
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_PHASE( 2 ctx, phi, phi_phase, tracer_index, phase_index, n_control_volumes) 3{ 4 // getting plugin internal data 5 int errcode = -1; 6 int thread_id = -1; 7 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 8 if (errcode != OK) { 9 return errcode; 10 } 11 MyStruct* data = nullptr; 12 errcode = alfasim_sdk_api.get_plugin_data( 13 ctx, (void**) &data, plugin_id, thread_id); 14 // Casting to double pointer 15 double* phi_ptr = static_cast<double*>(phi); 16 double* phi_phase_ptr = static_cast<double*>(phi_phase); 17 // Check if the tracer_index was added by this plugin 18 if (tracer_index != data.my_user_defined_tracer_id){ 19 return OK 20 } 21 // Let suppose that this tracer is only in the gas phase 22 if(phase_index != data.gas_id) { 23 for (int i = 0; i < n_control_volumes; ++i) { 24 phi_phase_ptr[i] = 0.0; 25 } 26 } else { 27 // Calculate and set the Phi_phase value 28 for (int i = 0; i < n_control_volumes; ++i) { 29 phi_phase_ptr[i] = 30 data.calculate_mass_fraction_of_tracer_in_gas( 31 phi_ptr[i], 32 // List of params that can be 33 // retrieved by get_simulation_array() 34 ); 35 } 36 } 37 return OK; 38}
Warning
The plugin developer must NOT change
phi
variable, only the output variablephi_phase
.
- calculate_mass_fraction_of_tracer_in_field(ctx, phi_phase, phi_field, tracer_index, field_index, phase_index_of_field, n_control_volumes)#
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)
Internal tracer model Hook to calculate the mass fraction of tracer, given by
tracer_index
, in field, given byfield_index
. The input variablephi_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 variablephi_field
is the mass fraction of the given tracer in respect to the mass of the given field. Bothphi_phase
andphi_field
have size equal ton_control_volumes
.- Parameters:
ctx – ALFAsim’s plugins context
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
tracer_index – Tracer ID
field_index – Field ID
phase_index_of_field – Phase ID of field
n_control_volumes – Number of control volumes
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_FIELD( 2 ctx, phi_phase, phi_field, tracer_index, field_index, 3 phase_index_of_field, n_control_volumes) 4{ 5 // getting plugin internal data 6 int errcode = -1; 7 int thread_id = -1; 8 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 9 if (errcode != OK) { 10 return errcode; 11 } 12 MyStruct* data = nullptr; 13 errcode = alfasim_sdk_api.get_plugin_data( 14 ctx, (void**) &data, plugin_id, thread_id); 15 // Casting to double pointer 16 double* phi_phase_ptr = static_cast<double*>(phi_phase); 17 double* phi_field_ptr = static_cast<double*>(phi_field); 18 // Check if the tracer_index was added by this plugin 19 if (tracer_index != data.my_user_defined_tracer_id){ 20 return OK 21 } 22 // Let suppose that this tracer is only in the gas phase 23 if(phase_index_of_field != data.gas_phase_id) { 24 for (int i = 0; i < n_control_volumes; ++i) { 25 phi_field_ptr[i] = 0.0; 26 } 27 } else { 28 // Calculate and set the Phi_field value 29 for (int i = 0; i < n_control_volumes; ++i) { 30 phi_field_ptr[i] = 31 data.mass_fraction_of_tracer_in_gas_fields( 32 phi_phase_ptr[i], 33 // List of params that can be 34 // retrieved by get_simulation_array() 35 ); 36 } 37 } 38 return OK; 39}
Warning
The plugin developer must NOT change
phi_phase
variable, only the output variablephi_field
.
- set_prescribed_boundary_condition_of_mass_fraction_of_tracer(ctx, phi_presc, tracer_index)#
c++ signature :
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 variablephi_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 withphi_presc
value set by this hook.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.- Parameters:
ctx – ALFAsim’s plugins context
phi_presc – Prescribed mass fraction of tracer
tracer_index – Tracer ID
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_SET_PRESCRIBED_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER( 2 ctx, phi_presc, tracer_index) 3{ 4 // getting plugin internal data 5 int errcode = -1; 6 int thread_id = -1; 7 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 8 if (errcode != OK) { 9 return errcode; 10 } 11 MyStruct* data = nullptr; 12 errcode = alfasim_sdk_api.get_plugin_data( 13 ctx, (void**) &data, plugin_id, thread_id); 14 if (tracer_index != data.my_user_defined_tracer_id) { 15 return OK; 16 } else { 17 // Set a initial boundary condition 18 // to the tracer mass fraction. 19 // phi_presc has size equal to 1. 20 *static_cast<double*>(phi_presc) = 0.0; 21 } 22 return OK; 23}
- update_boundary_condition_of_mass_fraction_of_tracer(ctx, phi_presc, tracer_index, vol_frac_bound, n_fields)#
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)
Internal tracer model hook to update the prescribed mass fraction of tracer, given by
tracer_id
. The output variablephi_presc
is the prescribed mass fraction of the given tracer in respect to the mass of the mixture. Thevol_frac_bound
is the volume fraction of fields at the boundary in which thephi_presc
is being calculated.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.
- Parameters:
ctx – ALFAsim’s plugins context
phi_presc – Prescribed mass fraction of tracer
tracer_index – Tracer ID
vol_frac_bound – Volume fraction of fields in the boundary
n_fields – Number of fields
- Returns:
Return OK if successful or anything different if failed
Example of usage:
1HOOK_UPDATE_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER( 2 ctx, phi_presc, tracer_index) 3{ 4 // getting plugin internal data 5 int errcode = -1; 6 int thread_id = -1; 7 errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id); 8 if (errcode != OK) { 9 return errcode; 10 } 11 MyStruct* data = nullptr; 12 errcode = alfasim_sdk_api.get_plugin_data( 13 ctx, (void**) &data, plugin_id, thread_id); 14 // Casting to double pointer 15 double* phi_presc_ptr = static_cast<double*>(phi_presc); 16 double* vol_frac_bound_ptr = static_cast<double*>(vol_frac_bound); 17 // Let suppose that this tracer is only in the gas field 18 if (tracer_index != data.my_user_defined_tracer_id) { 19 return OK; 20 } else { 21 // Update the boundary condition 22 // to the tracer mass fraction. 23 phi_presc_ptr = 24 data.calc_bc_mass_fraction_of_tracer_in_gas_field( 25 vol_frac_bound_ptr[data.continuous_gas_field_id], 26 // List of params that can be 27 // retrieved by get_simulation_array() 28 ); 29 } 30 return OK; 31}
Warning
The plugin developer must NOT change
vol_frac_bound
variable, only the output variablephi_presc
.