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.

digraph { nodesep = 0.6; newrank=true node [fillcolor="#FAAC2C" style="rounded, filled" color="#FAAC2C" fontcolor="#ffffff"] edge [color="#8699A3" fontcolor="#2c3e50"] init [label="Initialize Simulation"] end [label="End of Simulation"] node [shape=point, width=0] invisible_point hook_initialize_point [peripheries="2"] hook_finalize_point [peripheries="2"] time [fixedsize=true, label="Time Step", width="1.0", shape="circle"]; decision [label="Final \n Time?", shape="diamond", fixedsize=true, width=2.0, height=1.0, labelcolor="#8699A3", style="filled"] node[shape="rectangular", target="_top"] config [label="Solver Configuration"] hyd_solver [label="Hydrodynamic Solver", URL="../07_workflow.html#hydrodynamic-solver"] tracer_solver [label="Tracer Solver" URL="../07_workflow.html#tracer-solver"] output [label="Output Variables"] node[peripheries="0" shape="cds", color="#DA5961", fontcolor="#DA5961", style=""] hook_initialize [ label="HOOK_INITIALIZE", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.initialize"] hook_finalize [label="HOOK_FINALIZE", URL="../06_solver_hooks.html#_alfasim_sdk.hook_specs.finalize"] {rank = same; hook_initialize_point; hook_initialize} {rank = same; hook_finalize_point; hook_finalize; } {rank=same; time;tracer_solver} {rank=same; invisible_point;hyd_solver} init -> config; config -> hook_initialize_point [arrowhead= none]; hook_initialize_point -> invisible_point [arrowhead=none]; hook_initialize_point -> hook_initialize [style=dotted, color="#DA5961"]; subgraph cluster_a{ label="Transient Solver" style="dashed, rounded" shape="reactangular" color="#8699A3" fontcolor="#2c3e50" labeljust="l" invisible_point -> time; time:ne -> hyd_solver:w [style=dashed]; hyd_solver -> tracer_solver [weight=1000]; tracer_solver -> output [weight=1000]; output:nw -> time:se [style=dashed]; time:s -> decision:n [weight=10]; decision:w -> time:sw [label="No"]; } decision -> hook_finalize_point [arrowhead= none, label="Yes"]; hook_finalize_point -> hook_finalize [style=dotted, color="#DA5961"]; hook_finalize_point -> end; }

Initial configuration and plugin internal data

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ALFAsimSDK_API alfasim_sdk_api;

HOOK_INITIALIZE(ctx) {
    const char* plugin_id = get_plugin_id()
    // Loading ALFAsim-SDK API
    int load_error_code = alfasim_sdk_open(alfasim_sdk_api)
    if (load_error_code != 0){
        return load_error_code;
    }
    return OK;
}

Where OK is an error_code value and get_plugin_id() function is created automatically to each plugin template and accessible from hook_specs.h file. As can be seen in the example above at least the ALFAsim-SDK API should be loaded.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
ALFAsimSDK_API alfasim_sdk_api;

HOOK_INITIALIZE(ctx)
{
    const char* plugin_id = get_plugin_id()
    // Loading ALFAsim-SDK API
    int load_error_code = alfasim_sdk_open(alfasim_sdk_api)
    if (load_error_code != 0){
        return load_error_code;
    }
    // Threads Information
    int n_threads = -1;
    int errcode = alfasim_sdk_api.get_number_of_threads(
        ctx, &n_threads);
    if (errcode != 0){
        return errcode;
    }
    // Setting internal data to each thread
    for (int thread_id = 0; thread_id < n_threads; ++thread_id){
        double value;
        alfasim_sdk_api.get_plugin_input_data_quantity(
            ctx, &value, plugin_id, thread_id);
        void* data = new double(value);
        alfasim_sdk_api.set_plugin_data(
            ctx, plugin_id, data, thread_id);
    }
    return OK;
}

It is important to note that void* data at line 22 could be a more complex data structure, like a class object for example.

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
HOOK_FINALIZE(ctx)
{
    // Threads information
    int n_threads = -1;
    int errcode = alfasim.get_number_of_threads(ctx, &n_threads);
    f (errcode != 0){ // or errcode != OK
        return errcode;
    }
    const char* plugin_id = get_plugin_id();
    // Plugin internal data
    for (int thread_id = 0; thread_id < n_threads; ++thread_id) {
        void* data = nullptr;
        errcode = alfasim.get_plugin_data(
            ctx, &data, plugin_id, thread_id);
        delete data;
    }
    // Unloading ALFAsim-SDK API
    int load_error_code = alfasim_sdk_close(alfasim_sdk_api)
    if (load_error_code != 0){
        return load_error_code;
    }
    return OK;
}

Where OK is an error_code value.

As can be seen in the example above the function get_plugin_data() is used to retrieved the plugin internal data for each thread identified as thread_id.

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES(ctx)
{
    int errcode = -1;
    int size_U = -1;
    int size_E = -1;
    int liq_id = -1;
    errcode = alfasim_sdk_api.get_field_id(
        ctx, &oil_id, "oil");
    double* vel;
    VariableScope Fields_OnFaces = {
        GridScope::FACE,
        MultiFieldDescriptionScope::FIELD,
        TimestepScope::CURRENT
    }
    errcode = alfasim_sdk_api.get_simulation_array(
        ctx, &vel, (char*) "U", Fields_OnFaces, liq_id, &size_U);
    double* kinetic_energy;
    char* name = "kinetic_energy_of_oil";
    int global_idx = 0;
    errcode = alfasim_sdk_api.get_plugin_variable(
        ctx,
        (void**) (&kinetic_energy),
        name,
        global_idx,
        TimestepScope::CURRENT,
        &size_E);
    if (size_U != size_E){
        return OUT_OF_BOUNDS;
    }
    for (int i =0; i < size_U; ++i){
        kinetic_energy[i] = vel[i] * vel[i] / 2.;
    }
    return OK;
}

In the example above the variable kinetic_energy_of_oil was registered as a global variable, but its value is obtained for oil field. If this variable would be calculated to all fields then the global_idx would be substituted by field_idx and it would be performed to each field.

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_FIRST_TIMESTEP(ctx)
{
    int errcode = -1;
    int size_E = -1;
    double* kinetic_energy;
    char* name = "kinetic_energy_of_oil";
    int global_idx = 0;
    errcode = alfasim_sdk_api.get_plugin_variable(
        ctx,
        (void**) (&kinetic_energy),
        name,
        global_idx,
        TimestepScope::CURRENT,
        &size_E);
    for (int i =0; i < size_U; ++i){
        kinetic_energy[i] = 0.0;
    }
    return OK;
}

The ALFAsim’s Solver is divided in two non-linear solvers solvers that will solve different group of equations. The first one is the hydrodynamic solver which solves the Mass Conservation of fields, Momentum Conservation of layers and Energy Conservation equations all together for all elements in the network. The second one is the Tracer Solver which solves the Mass Conservation Equation for each added tracer. Since the tracers mass conservation is a transport equation it is solved after hydrodynamic solver and using its results (such as velocities) as input data in the Tracer Solver. See the ALFAsim’s Technical Report for more information.

To complete the group of hooks related to the plugins secondary variables there is the HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER. This hook is used to update plugin’s variables that depends on Tracer’s mass fractions and has to be updated in the Tracer Solver scope.

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
HOOK_UPDATE_PLUGINS_SECONDARY_VARIABLES_ON_TRACER_SOLVER(ctx)
{
    const char* plugin_id = get_plugin_id()
    int errcode = -1;
    int size_t = -1;
    int size_p_var = -1;
    int liq_id = -1;
    errcode = alfasim_sdk_api.get_field_id(
        ctx, &oil_id, "oil");
    double* tracer_mass_fraction;
    VariableScope global_OnCenters = {
        GridScope::FACE,
        MultiFieldDescriptionScope::FIELD,
        TimestepScope::CURRENT
    }
    // Tracer information
    void* tracer_ref;
    errcode = alfasim_sdk_api.get_tracer_ref_by_name(
        ctx,
        &tracer_ref,
        "my_tracer", // Added by User interface
        plugin_id);
    int tracer_id = -1;
    errcode = alfasim_sdk_api.get_tracer_id(
        ctx, &tracer_id, tracer_ref);
    double *tracer_mass_fraction
    errcode = alfasim_sdk_api.get_simulation_tracer_array(
        ctx,
        &tracer_mass_fraction,
        (char*) "phi",
        global_OnCenters,
        tracer_id,
        0,  // GLOBAL
        &size_t);
    // Plugin secondary variable array
    double* plugin_var;
    errcode = alfasim_sdk_api.get_plugin_variable(
        ctx,
        (void**) (&plugin_var),
        name,
        0,  // GLOBAL
        TimestepScope::CURRENT,
        &size_p_var);
    if (size_t != size_p_var){
        return OUT_OF_BOUNDS;
    }
    for (int i =0; i < size_t; ++i){
        // Do some calculations with plugin_var
        // using tracer_mass_fraction values
    }
    return OK;
}

Note that functions like get_tracer_ref_by_name(), get_tracer_id() and get_simulation_tracer_array() were used to obtain information related to tracers.

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
HOOK_CALCULATE_MASS_SOURCE_TERM(
    ctx, mass_source, n_fields, n_control_volumes)
{
    int liq_id = -1;
    errcode = alfasim_sdk_api.get_field_id(
        ctx, &oil_id, "oil");
    // Convertion from void* to double* and getting the
    // array range related to oil field
    double* oil_mass_source =
        (double*) mass_source + n_control_volumes * liq_id;
    // Make some calculations and add it to oil_mass_source.
    // In this example, we add a mass source of 3.1415 kg/s to all control volumes.
    for (int i = 0; i < n_control_volumes; ++i) {
        oil_mass_source[i] = 3.1415; // [kg/s]
    }
    return OK;
}

In the example above is shown how to manage the mass_source array to get the mass source term array related to a specific field (oil field in this case). Note that oil_mass_source has size equal to n_control_volumes.

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
HOOK_CALCULATE_MOMENTUM_SOURCE_TERM(
    ctx, momentum_source, n_layers, n_faces)
{
    int gas_id = -1;
    errcode = alfasim_sdk_api.get_layer_id(
        ctx, &gas_id, "gas");
    // Convertion from void* to double* and getting the
    // array range related to gas layer
    double* gas_momentum_source =
        (double*) momentum_source + n_faces * gas_id;
    // Make some calculations and add it to gas_momentum_source
    return OK;
}

In the example above is shown how to manage the momentum_source array to get the momentum source term array related to a specific layer (gas layer in this case). Note that gas_momentum_source has size equal to n_faces.

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
HOOK_CALCULATE_ENERGY_SOURCE_TERM(
    ctx, energy_source, n_energy_equation, n_control_volumes)
{
    double* gas_energy_source;
    if (n_energy_equation > 1){
        // Layers Energy model
        // One energy equation for each layer
        int gas_id = -1;
        errcode = alfasim_sdk_api.get_layer_id(
            ctx, &gas_id, "gas");
        // Convertion from void* to double* and getting the
        // array range related to gas layer
        gas_energy_source =
            (double*) energy_source + n_faces * gas_id;
    } else {
        // Global energy model
        // Only one global energy equation

        // Convertion from void* to double*
        gas_energy_source = (double*) energy_source;
    }
    // Make some calculations and add it to gas_energy_source
    return OK;
}

In the example above is shown how to manage the energy_source array to get the energy source term array related to a specific layer (gas layer in this case). Note that gas_energy_source has size equal to n_control_volumes.

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
HOOK_CALCULATE_TRACER_SOURCE_TERM(
    ctx, phi_source, n_tracers, n_control_volumes)
{
   // Tracer information
    void* tracer_ref;
    errcode = alfasim_sdk_api.get_tracer_ref_by_name(
        ctx,
        &tracer_ref,
        "my_tracer", // Added by User interface
        plugin_id);
    int tracer_id = -1;
    errcode = alfasim_sdk_api.get_tracer_id(
        ctx, &tracer_id, tracer_ref);
    // Convertion from void* to double* and getting the
    // array range related to gas layer
    double* my_tracer_phi_source =
        (double*) phi_source + n_control_volumes * tracer_id;
    // Make some calculations and add
    // it to my_tracer_phi_source
    return OK;
}

In the example above is shown how to manage the phi_source array to get the tracer source term array related to a specific tracer (my_tracer in this case). Note that gas_energy_source has size equal to n_control_volumes.

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, n_control_volumes, n_layers)

c++ signature : HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR(void* ctx, void* P, void* T, void* T_mix, int n_control_volumes, int n_layers)

Hook for the state variables calculator initialization (internal ALFAsim structure).

At this point, it is possible to pre-calculate and cache any relevant information. Then, for each state variable of the phases in the python configuration file, the hook HOOK_CALCULATE_STATE_VARIABLE is called and return the pre-calculated values.

Parameters
  • ctx – ALFAsim’s plugins context

  • P – Pressure values array

  • T – Temperature values array

  • T_mix – Mixture temperature values array

  • n_control_volumes – Number of control volumes

  • n_layers – Number of layers

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

Example of usage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
HOOK_INITIALIZE_STATE_VARIABLES_CALCULATOR(
    void* ctx, void* P, void* T, void* T_mix,
    int n_control_volumes, int n_layers)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    // MyStruct is a developer defined struct to hold
    // all important information for plugin hooks.
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    // MyFunction is a function implemented by
    // plugin developer that computes de density
    data.density = MyFunction(P, T_mix, n_control_volumes);
    return OK;
}
// Then, to use the cached value:
HOOK_CALCULATE_STATE_VARIABLE(
    void* ctx, void* P, void* T, int n_control_volumes, i
    nt n_layers, int phase_id, int property_id, void* output)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    if (phase_id != data.my_added_phase_id) {
        return OK;
    }
    if (property_id == StateVariable::RHO) {
        for (int i = 0; i < n_control_volumes; ++i) {
            output[i] = data.density[i];
        }
    }
    return OK;
}

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, property_id, output)

c++ signature : HOOK_CALCULATE_STATE_VARIABLE(void* ctx, void* P, void* T, int n_control_volumes, int n_layers, int phase_id, int property_id, void* output)

Hook 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_layers – Number of layers

  • n_phase_id – Id of phase in which the property must be calculated

  • property_id – A StateVariable value. It indicates which property must be calculated

  • output – Output values array

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.

Example of usage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
HOOK_CALCULATE_STATE_VARIABLE(
    void* ctx, void* P, void* T,
    int n_control_volumes, int n_layers,
    int phase_id, int property_id, void* output)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    if (phase_id != data.my_added_phase_id) {
        return OK;
    }
    if (property_id == StateVariable::RHO) {
        for (int i = 0; i < n_control_volumes; ++i) {
            // If the property has a constant value
            output[i] = data.constant_density;
            // If the property must be computed
            // MyStruct has a function called 'compute_density()'
            output[i] = data.compute_density(
                (double *)P[i], (double *)T[i]);
        }
    }
    return OK;
}

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, 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 property_id, void* output)

Hook to calculate the state variable given by the property_id (See :cpp:enum:StateVariable values), for the phase pair (phase1_id, phase2_id) (Note that the phase id is the same as the one retrieved from the get_phase_id() API function - It is not advisable to use hardcoded numbers).

List of affected variables:
- Interfacial Tension

Parameters
  • ctx – ALFAsim’s plugins context

  • P – Pressure values array

  • T_mix – Mixture temperature values array

  • n_control_volumes – Number of control volumes

  • n_phase1_id – Id of phase one in which the property must be calculated

  • n_phase2_id – Id of phase two in which the property must be calculated

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

Example of usage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
HOOK_CALCULATE_PHASE_PAIR_STATE_VARIABLE(
    void* ctx, void* P, void* T_mix, int n_control_volumes,
    int phase1_id, int phase2_id, int property_id, void* output)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    int gas_phase_id = -1;
    errcode = alfasim_sdk_api.get_phase_id(
        ctx, &gas_phase_id, "gas");

    if ((
        (phase1_id == data.my_added_phase_id)
        && (phase1_id == gas_phase_id)
        ) || (
        (phase1_id == gas_phase_id)
        && (phase1_id == data.my_added_phase_id)
        ))
    {
        for (int i = 0; i < n_control_volumes; ++i) {
            // If the property has a constant value
            output[i] = data.constant_surface_tension;
            // If the property must be computed
            // MyStruct has a function
            // called 'compute_surface_tension()'
            output[i] = data.compute_surface_tension(
                (double *)P[i], (double *)T_mix[i]);
        }
    }
    return OK;
}

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:

1
2
3
4
HOOK_FINALIZE_STATE_VARIABLES_CALCULATOR(void* ctx)
{
    return OK;
}

Additional solid phase

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
HOOK_INITIALIZE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS(
    void* ctx, void* particle_diameter,
    int n_control_volumes, int solids_field_id)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    if (solids_field_id != data.my_added_solid_field_id) {
        return OK;
    } else {
        for (int i = 0; i < n_control_volumes; ++i) {
            // If the particle size is constant
            output[i] = data.constant_particle_size;
            // The value is calculated
            // MyStruct has a function
            // called 'initial_particle_size()'
            output[i] = data.initial_particle_size(
                     // List of params that can be
                     // retrieved by get_simulation_array()
                     );
        }
    }
    return OK;
}
update_particle_diameter_of_solids_fields(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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
HOOK_UPDATE_PARTICLE_DIAMETER_OF_SOLIDS_FIELDS(
    void* ctx, void* particle_diameter,
    int n_control_volumes, int solids_field_id)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    if (solids_field_id != data.my_added_solid_field_id) {
        return OK;
    } else {
        for (int i = 0; i < n_control_volumes; ++i) {
            // If the particle size is constant
            output[i] = data.constant_particle_size;
            // The value is calculated
            // MyStruct has a function
            // called 'compute_particle_size()'
            output[i] = data.compute_particle_size(
                     // List of params that can be
                     // retrieved by get_simulation_array()
                     );
        }
    }
    return OK;
}

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, thickness, density, heat_capacity, thermal_conductivity, n_control_volumes)

c++ signature : HOOK_UPDATE_INTERNAL_DEPOSITION_LAYER(void* ctx, void* thickness, void* density, void* heat_capacity, void* thermal_conductivity, int n_control_volumes)

Internal simulator hook to evaluate the thickness and thermal properties of the deposited layer at the inside of the pipeline walls. This is called for accounting the diameter reduction and wall thermal effects.

The plugin is supposed to change the given thickness, density, heat_capacity, thermal_conductivity array pointers. Its values are contiguous in memory and the dimension is given by n_control_volumes. It has unit equal to [m].

Parameters
  • ctx – ALFAsim’s plugins context

  • thickness – Thickness of the internal deposit layer

  • density – Density of the internal deposit layer [kg/m3]

  • heat_capacity – Heat capacity of the internal deposit layer [J/(kg.K)]

  • thermal_conductivity – Thermal conductivity of the internal deposit layer [W/(m.K)]

  • n_control_volumes – Number of control volumes

Returns

Return OK if successful or anything different if failed

Example of usage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
HOOK_UPDATE_INTERNAL_DEPOSITION_LAYER(
    ctx, thickness, density, heat_capacity, thermal_conductivity, n_control_volumes)
{
    auto errcode = -1;

    double dt = -1.0;
    errcode = alfasim.get_simulation_quantity(
        ctx, &dt, TimestepScope::CURRENT, (char*) "dt");
    if (errcode != 0) {
        return errcode;
    }

    // Handle first time step, because you won't have the previously information
    double current_time = -1.0;
    errcode = alfasim.get_simulation_quantity(
        ctx, &current_time, TimestepScope::CURRENT, (char*) "time");
    if (errcode != 0) {
        return errcode;
    }

    double wax_density = 900.0 // [kg/m3]
    double wax_heat_capacity = 2140.0 // [J/(kg.K)]
    double wax_thermal_conductivity = 0.25 // [W/(m.K)]

    if (current_time == 0.0){
        // Set a value for the deposition layer thickness
         for (int i = 0; i < n_control_volumes; ++i) {
           (double*) thickness[i] = 0.0; // [m]
           (double*) density[i] = wax_density; // [kg/m3]
           (double*) heat_capacity[i] = wax_heat_capacity; //  [J/(kg.K)]
           (double*) thermal_conductivity[i] = wax_thermal_conductivity; // [W/(m.K)]
        }
    } else{
        // Get previously deposition layer thickness to obtain the current
        void* thickness_old_raw_ptr;
        errcode = alfasim.get_plugin_variable(
            ctx,
            &thickness_old_raw_ptr,
            "thickness",
            0,
            TimestepScope::PREVIOUS,
            &size);
        if (errcode != 0) {
            return errcode;
        }
        auto* thickness_old =
            (double*) (thickness_old_raw_ptr);

        // Calculate the variation of the deposition layer in one time step
        double* d_deposit_layer_dt = 0.0001; // [m/s]

        // Sum this variation with the thickness of the older time step
        for (int i = 0; i < n_control_volumes; ++i) {
            (double*) thickness[i] =
                thickness_old[i] + d_deposit_layer_dt * dt; // [m]
           (double*) density[i] = wax_density; // [kg/m3]
           (double*) heat_capacity[i] = wax_heat_capacity; //  [J/(kg.K)]
           (double*) thermal_conductivity[i] = wax_thermal_conductivity; // [W/(m.K)]
        }
    }

    return OK;
}

In the example above is shown how to manage the thickness, density, heat_capacity and thermal_conductivity arrays for each control volume. Note that the thickness should be always the total value for that time step, so the first time step should be handle in a separately way, since there is no previously information.

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int HOOK_CALCULATE_UCM_FRICTION_FACTOR_STRATIFIED(
    void* ctx, double* ff_wG, double* ff_wL, double* ff_i)
{
    int errcode = -1;
    int G = TwoPhaseSystem::GAS
    int L = TwoPhaseSystem::LIQUID

    // Getting friction factor input data from context
    double alpha[2];
    errcode = alfasim_sdk_api.get_ucm_friction_factor_input_variable(
        ctx, &alpha[G], "alpha", TwoPhaseSystem::GAS);
    if (errcode != OK){ return errcode; }
    errcode = alfasim_plugins_api.get_ucm_friction_factor_input_variable(
        ctx, &alpha[L], "alpha", TwoPhaseSystem::LIQUID);
    if (errcode != OK){ return errcode; }
    // And so on to each friction factor input variable
    // U(velocities), rho(densities), mu(viscosities) and D(pipe diameter)

     // Getting the fluid geometrical properties
    double S_w[2];
    double S_i;
    double H[2];
    errcode = alfasim_sdk_api.get_ucm_fluid_geometrical_properties(
        ctx, S_w, &S_i, H, alpha[G], D);
    if (errcode != OK){ return errcode; }

    // Compute the friction factors using your own correlation.
    // Also, using the variables: alpha, U, rho, mu, D, S_w, S_i and H

    *ff_wG = gas_wall_ff;
    *ff_wL = liq_wall_ff;
    *ff_i = gas_liq_ff;

    return OK;
}
calculate_ucm_friction_factor_annular(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.

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

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
HOOK_INITIALIZE_MASS_FRACTION_OF_TRACER(
    void* ctx, void* phi_initial, int tracer_index)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    if (tracer_index != data.my_user_defined_tracer_id) {
        return OK;
    } else {
        // Set a initial value to the tracer mass fraction
        // phi_initial has size equal to 1
        *static_cast<double*>(phi_initial) = 0.0;
    }
    return OK;
}
calculate_mass_fraction_of_tracer_in_phase(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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_PHASE(
    void* ctx, void* phi, void* phi_phase,
    int tracer_index, int phase_index, int n_control_volumes)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    // Casting to double pointer
    double* phi_ptr = static_cast<double*>(phi);
    double* phi_phase_ptr = static_cast<double*>(phi_phase);
    // Check if the tracer_index was added by this plugin
    if (tracer_index != data.my_user_defined_tracer_id){
        return OK
    }
    // Let suppose that this tracer is only in the gas phase
    if(phase_index != data.gas_id) {
         for (int i = 0; i < n_control_volumes; ++i) {
            phi_phase_ptr[i] = 0.0;
         }
    } else {
        // Calculate and set the Phi_phase value
        for (int i = 0; i < n_control_volumes; ++i) {
            phi_phase_ptr[i] =
                data.calculate_mass_fraction_of_tracer_in_gas(
                    phi_ptr[i],
                    // List of params that can be
                    // retrieved by get_simulation_array()
                    );
        }
    }
    return OK;
}

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
HOOK_CALCULATE_MASS_FRACTION_OF_TRACER_IN_FIELD(
    void* ctx, void* phi_phase, void* phi_field,
    int tracer_index, int field_index,
    int phase_index_of_field, int n_control_volumes)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    // Casting to double pointer
    double* phi_phase_ptr = static_cast<double*>(phi_phase);
    double* phi_field_ptr = static_cast<double*>(phi_field);
    // Check if the tracer_index was added by this plugin
    if (tracer_index != data.my_user_defined_tracer_id){
        return OK
    }
    // Let suppose that this tracer is only in the gas phase
    if(phase_index_of_field != data.gas_phase_id) {
         for (int i = 0; i < n_control_volumes; ++i) {
            phi_field_ptr[i] = 0.0;
         }
    } else {
        // Calculate and set the Phi_field value
        for (int i = 0; i < n_control_volumes; ++i) {
            phi_field_ptr[i] =
                data.mass_fraction_of_tracer_in_gas_fields(
                    phi_phase_ptr[i],
                    // List of params that can be
                    // retrieved by get_simulation_array()
                    );
        }
    }
    return OK;
}

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
HOOK_SET_PRESCRIBED_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER(
    void* ctx, void* phi_presc, int tracer_index)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    if (tracer_index != data.my_user_defined_tracer_id) {
        return OK;
    } else {
        // Set a initial boundary condition
        // to the tracer mass fraction.
        // phi_presc has size equal to 1.
        *static_cast<double*>(phi_presc) = 0.0;
    }
    return OK;
}
update_boundary_condition_of_mass_fraction_of_tracer(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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
HOOK_UPDATE_BOUNDARY_CONDITION_OF_MASS_FRACTION_OF_TRACER(
    void* ctx, void* phi_presc, int tracer_index)
{
    // getting plugin internal data
    int errcode = -1;
    int thread_id = -1;
    errcode = alfasim_sdk_api.get_thread_id(ctx, &thread_id);
    if (errcode != OK) {
        return errcode;
    }
    MyStruct* data = nullptr;
    errcode = alfasim_sdk_api.get_plugin_data(
            ctx, (void**) &data, plugin_id, thread_id);
    // Casting to double pointer
    double* phi_presc_ptr = static_cast<double*>(phi_presc);
    double* vol_frac_bound_ptr = static_cast<double*>(vol_frac_bound);
    // Let suppose that this tracer is only in the gas field
    if (tracer_index != data.my_user_defined_tracer_id) {
        return OK;
    } else {
        // Update the boundary condition
        // to the tracer mass fraction.
        phi_presc_ptr =
                data.calc_bc_mass_fraction_of_tracer_in_gas_field(
                    vol_frac_bound_ptr[data.continuous_gas_field_id],
                    // List of params that can be
                    // retrieved by get_simulation_array()
                    );
    }
    return OK;
}

Warning

The plugin developer must NOT change vol_frac_bound variable, only the output variable phi_presc.