# Solver Hooks#

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.

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 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.

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()
9    }
10    return OK;
11}


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.

However, if the plugin has internal data the minimal HOOK_INITIALIZE implementation would be

 1ALFAsimSDK_API alfasim_sdk_api;
2
3HOOK_INITIALIZE(ctx)
4{
5    const char* plugin_id = get_plugin_id()
10    }
15    if (errcode != 0){
16        return errcode;
17    }
18    // Setting internal data to each thread
20        double value;
21        alfasim_sdk_api.get_plugin_input_data_quantity(
23        void* data = new double(value);
24        alfasim_sdk_api.set_plugin_data(
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{
6    if (errcode != 0){ // or errcode != OK
7        return errcode;
8    }
9    const char* plugin_id = get_plugin_id();
10    // Plugin internal data
12        void* data = nullptr;
13        errcode = alfasim_sdk_api.get_plugin_data(
15        delete data;
16    }
21    }
22    return OK;
23}


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.

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, 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.

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 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(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 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. 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.

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}


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.

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() and get_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 by n_fields and n_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 that oil_mass_source has size equal to n_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 by n_layers and n_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 that gas_momentum_source has size equal to n_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 by n_energy_equation and n_control_volumes. It has unit equal to [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.

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 that gas_energy_source has size equal to n_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 by n_tracers and n_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 that gas_energy_source has size equal to n_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 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. Finally, phi dimensions are given by n_tracers and n_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;
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;
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 the get_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 calculated

• output – 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 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.

In case of calculating all properties and caching them in the HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR (depending on the model used inside the plugin) the field_id can be used to retrieve the cached properties for a specific field associated to the phase in which phase_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;
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 is n_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 the get_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 calculated

• output – 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 temperature T_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 called phase1_id and phase2_id. To identify which phase_pair_id are being passed it is possible to retrieve the phase pair IDs by using get_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;
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 ((
20        && (phase1_id == gas_phase_id)
21        ) || (
22        (phase1_id == gas_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 is n_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}


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(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;
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;
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 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:

$$$\mu_r = \frac{\mu_{eff}}{\mu_c}$$$

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 to n_faces and it is dimensionless. The solid_field_index is the index of the dispersed solid field. The layer_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 using get_simulation_array() must be use value FACE in the GridScope 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()
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 to n_faces and it is dimensionless. The solid_field_index is the index of the dispersed solid field. The layer_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 using get_simulation_array() must be use value FACE in the GridScope 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()
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. 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(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 by n_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, &current_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 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.

## 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 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 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 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.

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 transforms 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 non 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) system of Mechanistic Model can be used for both two and three-phase flows, in which is done in case of a liquid-liquid system is not available via plugin.

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 and water_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
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
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 to 2 (for Oil and Water phases) and it has unit equal to [N/m^3]. The output variable shear_i is the Interfacial Shear Force per unit Volume between Oil and Water phases it has unit equal to [N/m^3]. The output variable u_fields is the field velocities with size 4 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 variable vol_frac_fields is the field volume fractions also with size 4, just like u_fields and it has unit equal to [kg of field/ kg of liquid-liquid mixture].

Note

The outputs u_fields and vol_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:

$$$\mu_r = \frac{\mu_m}{\mu_c}$$$

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 and alpha_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 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(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;
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 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.

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;
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 variable phi_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 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.

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;
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 variable phi_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 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.

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;
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 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.

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;
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 variable phi_presc.