Example#

In this section, we will walk trough the creation of a simple network, with two nodes and one pipe, to illustrate how to create a project and how to interpret the definitions available on Full API Reference.

The root level of a Description is always the class CaseDescription which has the following attributes:

Note

This guide assumes the reader is familiar with Python 3.

class CaseDescription:
    name: Optional[str] = None
    physics: PhysicsDescription = PhysicsDescription()
    time_options: TimeOptionsDescription = TimeOptionsDescription()
    numerical_options: NumericalOptionsDescription = NumericalOptionsDescription()
    ipr_models: IPRModelsDescription = IPRModelsDescription()
    pvt_models: PvtModelsDescription = PvtModelsDescription()
    tracers: TracersDescription = TracersDescription()
    outputs: CaseOutputDescription = CaseOutputDescription()
    pipes: List[PipeDescription] = []
    nodes: List[NodeDescription] = []
    wells: List[WellDescription] = []
    materials: List[MaterialDescription] = []
    walls: List[WallDescription] = []

In the following section, these steps will be covered:

  • How to configure the project options.

  • How to add a PVtModel.

  • How to add Nodes.

  • How to add Pipes.

  • How to add output curves.

Note

For the full reference check the Full API Reference

Project Options#

We will start the example by configuring the project options, as discussed in the previous section, the root level of an ALFacase file is the CaseDescription and it has the following options:

class CaseDescription:
    physics: PhysicsDescription = PhysicsDescription()
    time_options: TimeOptionsDescription = TimeOptionsDescription()
    numerical_options: NumericalOptionsDescription = NumericalOptionsDescription()

For this example, the application will be configured with the ALFAsim correlation package using a hydrodynamic model with two-phase and four fields, the time steps will be changed as well and the tolerance will be set to 1e-4

Example

from alfasim_sdk import (
    CaseDescription,
    PhysicsDescription,
    NumericalOptionsDescription,
    TimeOptionsDescription,
)
from barril.units import Scalar

CaseDescription(
    name="basic_case",
    physics=PhysicsDescription(
        correlations_package=CorrelationPackageType.Alfasim,
        hydrodynamic_model=HydrodynamicModelType.FourFields,
    ),
    numerical_options=NumericalOptionsDescription(tolerance=1e-4),
    time_options=TimeOptionsDescription(
        minimum_timestep=Scalar(1e-4, "s"),
        maximum_timestep=Scalar(0.5, "s"),
        final_time=Scalar(1.0, "s"),
    ),
)

PVT Model#

The second step will add a PVT model to the project and configure it as the default PVT for the entire project.

The PvtModelsDescription class configures PVT models used in the project.

Each element in the project can have a PVT model assigned, however it is possible to configure a default model that will be used when an element doesn’t have an assigned PVT model. That default model is the model assigned to the default_model attribute.

For this example, a PVT model will be created from a .tab file. Path definitions inside the .alfacase file are always relative for portability. And for this, we need to populate the tables field with the PVT name and a file.

Note

Each PVT model name must be unique.

Check the PVTs section for a detailed description of each PVT type option.

Example

from alfasim_sdk import (
    CaseDescription,
    PvtModelsDescription,
)

CaseDescription(
    # Omitting fields that configure option
    pvt_models=PvtModelsDescription(
        default_model="Pvt1",
        tables={"Pvt1": "my_pvt_file.tab"},
    ),
)

Nodes#

The third step will add two different types of nodes: a mass source node and a pressure node.

Nodes are added over the nodes section of the CaseDescription.

The NodeDescription class configures several types of nodes through the node_type field and their respective property fields.

For example:

The other properties not related to the node_type are read by the application, but are not considered for the solution.

Note

Check the Node section for a detailed description of each Node type.

Example

from alfasim_sdk import (
    CaseDescription,
    NodeDescription,
    MassSourceNodePropertiesDescription,
    PressureNodePropertiesDescription,
)

CaseDescription(
    # Omitting fields that configure Options and Pvt
    nodes=[
        NodeDescription(
            name="Inlet",
            node_type=NodeCellType.MassSource,
            mass_source_properties=MassSourceNodePropertiesDescription(
                mass_flow_rates={
                    "gas": Scalar(0.0, "kg/s"),
                    "oil": Scalar(0.0, "kg/s"),
                },
            ),
        ),
        NodeDescription(
            name="Outlet",
            node_type=NodeCellType.Pressure,
            pressure_properties=PressureNodePropertiesDescription(
                pressure=Scalar(50.0, "bar"),
                volume_fractions={
                    "gas": Scalar(1.0, "-"),
                    "oil": Scalar(1.0, "-"),
                },
            ),
        ),
    ],
)

Pipes#

Let’s add a Pipe to the application through the pipes fields.

The pipes attribute accepts a list of PipeDescription definitions that connects two nodes.

The connection is defined by the source and target fields, and to configure them it is only necessary to inform the name of the NodeDescription that will be used.

Note

Check the Pipe section for a detailed description of the attributes available.

Example

from alfasim_sdk import (
    CaseDescription,
    PipeDescription,
    ProfileDescription,
    LengthAndElevationDescription,
    PipeSegmentsDescription,
)

CaseDescription(
    # Omitting fields that configure Options, Pvt and Node
    pipes=[
        PipeDescription(
            name="pipe",
            source="Inlet",
            target="Outlet",
            profile=ProfileDescription(
                length_and_elevation=LengthAndElevationDescription(
                    length=Array([0.0, 15.0, 30.0, 30.0, 15.0], "m"),
                    elevation=Array([0.0, 15.0, 30.0, 30.0, 15.0], "m"),
                ),
            ),
            segments=PipeSegmentsDescription(
                start_positions=Array([0.0], "m"),
                diameters=Array([0.1], "m"),
                roughnesses=Array([5e-05], "m"),
            ),
        ),
    ],
)

Output#

The final step for our example will configure a trend and a profile for our project.

As indicated on CaseDescription, the outputs field must be filled with a CaseOutputDescription instance which configures trends and profiles.

Note

Check the Outputs section for a detailed description of each output type, that shows all the available curves that can be used.

Example

from alfasim_sdk import (
    CaseDescription,
    CaseOutputDescription,
    TrendsOutputDescription,
    PositionalPipeTrendDescription,
    OutputAttachmentLocation,
    ProfileOutputDescription,
)

CaseDescription(
    # Omitting fields that configure Options, Pvt, Node and Pipes
    outputs=CaseOutputDescription(
        trends=TrendsOutputDescription(
            positional_pipe_trends=[
                PositionalPipeTrendDescription(
                    element_name="pipe",
                    curve_names=["oil mass flow rate"],
                    position=Scalar(100.0, "m"),
                    location=OutputAttachmentLocation.Main,
                )
            ]
        ),
        automatic_trend_frequency=True,
        trend_frequency=Scalar(0.1, "s"),
        profiles=[
            ProfileOutputDescription(
                curve_names=["pressure"],
                element_name="pipe",
                location=OutputAttachmentLocation.Main,
            )
        ],
        automatic_profile_frequency=True,
        profile_frequency=Scalar(0.1, "s"),
    ),
)

Full Case#

This section brings together all the previous sections, showing the full example of a Description with a project configuration and being converted to a .alfacase file, using convert_description_to_alfacase making this project ready to be imported by the application.

from alfasim_sdk import (
    CaseDescription,
    PhysicsDescription,
    NumericalOptionsDescription,
    TimeOptionsDescription,
    PvtModelsDescription,
    NodeDescription,
    MassSourceNodePropertiesDescription,
    PressureNodePropertiesDescription,
    PipeDescription,
    ProfileDescription,
    LengthAndElevationDescription,
    PipeSegmentsDescription,
    CaseOutputDescription,
    TrendsOutputDescription,
    PositionalPipeTrendDescription,
    OutputAttachmentLocation,
    ProfileOutputDescription,
    CaseOutputDescription,
)

case_description = CaseDescription(
    name="basic_case",
    physics=PhysicsDescription(
        correlations_package=CorrelationPackageType.Alfasim,
        hydrodynamic_model=HydrodynamicModelType.FourFields,
    ),
    numerical_options=NumericalOptionsDescription(tolerance=1e-4),
    time_options=TimeOptionsDescription(
        minimum_timestep=Scalar(1e-4, "s"),
        maximum_timestep=Scalar(0.5, "s"),
        final_time=Scalar(1.0, "s"),
    ),
    pvt_models=PvtModelsDescription(
        default_model="Pvt1",
        tables={"Pvt1": "my_pvt_file.tab"},
    ),
    nodes=[
        NodeDescription(
            name="Inlet",
            node_type=NodeCellType.MassSource,
            mass_source_properties=MassSourceNodePropertiesDescription(
                mass_flow_rates={
                    "gas": Scalar(0.0, "kg/s"),
                    "oil": Scalar(0.0, "kg/s"),
                },
            ),
        ),
        NodeDescription(
            name="Outlet",
            node_type=NodeCellType.Pressure,
            pressure_properties=PressureNodePropertiesDescription(
                pressure=Scalar(50.0, "bar"),
                volume_fractions={
                    "gas": Scalar(1.0, "-"),
                    "oil": Scalar(1.0, "-"),
                },
            ),
        ),
    ],
    pipes=[
        PipeDescription(
            name="pipe",
            source="Inlet",
            target="Outlet",
            profile=ProfileDescription(
                length_and_elevation=LengthAndElevationDescription(
                    length=Array([0.0, 15.0, 30.0, 30.0, 15.0], "m"),
                    elevation=Array([0.0, 15.0, 30.0, 30.0, 15.0], "m"),
                ),
            ),
            segments=PipeSegmentsDescription(
                start_positions=Array([0.0], "m"),
                diameters=Array([0.1], "m"),
                roughnesses=Array([5e-05], "m"),
            ),
        ),
    ],
    outputs=CaseOutputDescription(
        trends=TrendsOutputDescription(
            positional_pipe_trends=[
                PositionalPipeTrendDescription(
                    element_name="pipe",
                    curve_names=["oil mass flow rate"],
                    position=Scalar(100.0, "m"),
                    location=OutputAttachmentLocation.Main,
                )
            ]
        ),
        automatic_trend_frequency=True,
        trend_frequency=Scalar(0.1, "s"),
        profiles=[
            ProfileOutputDescription(
                curve_names=["pressure"],
                element_name="pipe",
                location=OutputAttachmentLocation.Main,
            )
        ],
        automatic_profile_frequency=True,
        profile_frequency=Scalar(0.1, "s"),
    ),
)

And the case_description above can be converted to a .alfacase file using convert_description_to_alfacase.

from pathlib import Path
from alfasim_sdk import convert_description_to_alfacase

case_description = CaseDescription(  [...] )
alfacase_content = convert_description_to_alfacase(case_description)

# Dump the content to a file
alfacase_file = Path("c:\\user\\") / 'my_project.alfacase'
alfacase_file.write_text(data=alfacase_content, encoding='UTF-8')