Exemple #1
0
def test_error_bips_setup():
    """
    The goal of this test is to check a BIP input with incompatible dimensions.
    The BIPs compose a symmetric matrix of size (n_species, n_species). This test checks
    for the case where the k BIPs matrix is not symmetric.
    """
    db = reaktoro.Database(str(get_test_data_dir() / 'hydrocarbons.xml'))

    editor_bips = reaktoro.ChemicalEditor(db)

    gaseous_species = ["C1(g)", "C4(g)", "C10(g)"]

    def calculate_bips(T):
        one = 1.0
        # Wrong BIP matrix
        k = [
            [one, one, one],
            [one, one, one],
            [-one, one, one],
        ]
        bips = reaktoro.BinaryInteractionParams(k)
        return bips

    eos_params_bips = reaktoro.CubicEOSParams(
        model=reaktoro.CubicEOSModel.PengRobinson,
        phase_identification_method=reaktoro.PhaseIdentificationMethod.
        GibbsEnergyAndEquationOfStateMethod,
        binary_interaction_values=calculate_bips)
    with pytest.raises(RuntimeError, match='k is not symmetric'):
        editor_bips.addGaseousPhase(gaseous_species).setChemicalModelCubicEOS(
            eos_params_bips)
def test_chemicaltransport_step(num_regression):

    nx, ny, nz = 5, 5, 5  # number of cells along x, y, and z
    nsteps = 10  # number of time steps

    velocity = fire.Constant([1.0e-2, 0.0,
                              0.0])  # the velocity (in units of m/s)
    diffusion = fire.Constant(
        1.0e-4)  # the diffusion coefficient (in units of m2/s)
    dt = 1.0  # the time step (in units of s)
    T = 60.0 + 273.15  # the temperature (in units of K)
    P = 100 * 1e5  # the pressure (in units of Pa)

    mesh = fire.UnitCubeMesh(nx, ny, nz)
    V = fire.FunctionSpace(mesh, "CG", 1)

    # Initialise the database
    database = rkt.Database("supcrt98.xml")

    # Initialise the chemical editor
    editor = rkt.ChemicalEditor(database)
    editor.addAqueousPhase(
        "H2O(l) H+ OH- Na+ Cl- Ca++ Mg++ HCO3- CO2(aq) CO3--")
    editor.addMineralPhase("Quartz")
    editor.addMineralPhase("Calcite")
    editor.addMineralPhase("Dolomite")

    # Initialise the chemical system
    system = rkt.ChemicalSystem(editor)

    # Define the initial condition of the reactive transport modeling problem
    problem_ic = rkt.EquilibriumProblem(system)
    problem_ic.setTemperature(T)
    problem_ic.setPressure(P)
    problem_ic.add("H2O", 1.0, "kg")
    problem_ic.add("NaCl", 0.7, "mol")
    problem_ic.add("CaCO3", 10, "mol")
    problem_ic.add("SiO2", 10, "mol")

    # Define the boundary condition of the reactive transport modeling problem
    problem_bc = rkt.EquilibriumProblem(system)
    problem_bc.setTemperature(T)
    problem_bc.setPressure(P)
    problem_bc.add("H2O", 1.0, "kg")
    problem_bc.add("NaCl", 0.90, "mol")
    problem_bc.add("MgCl2", 0.05, "mol")
    problem_bc.add("CaCl2", 0.01, "mol")
    problem_bc.add("CO2", 0.75, "mol")

    # Calculate the equilibrium states for the initial and boundary conditions
    state_ic = rkt.equilibrate(problem_ic)
    state_bc = rkt.equilibrate(problem_bc)

    # Scale the volumes of the phases in the initial condition such that their sum is 1 m3
    state_ic.scalePhaseVolume("Aqueous", 0.1, "m3")
    state_ic.scalePhaseVolume("Quartz", 0.882, "m3")
    state_ic.scalePhaseVolume("Calcite", 0.018, "m3")

    # Scale the volume of the boundary equilibrium state to 1 m3
    state_bc.scaleVolume(1.0)

    # Initialise the chemical field
    field = rok.ChemicalField(system, V)
    field.fill(state_ic)

    # Initialize the chemical transport solver
    transport = rok.ChemicalTransportSolver(field)
    transport.addBoundaryCondition(state_bc, 1)  # 1 means left side
    transport.setVelocity([velocity])
    transport.setDiffusion([diffusion])

    species_names_for_output = [
        "Ca++",
        "Mg++",
        "Calcite",
        "Dolomite",
        "CO2(aq)",
        "HCO3-",
        "Cl-",
        "H2O(l)",
    ]
    element_names_for_output = ["H", "O", "C", "Ca", "Mg", "Na", "Cl"]

    species_amount_functions = [
        fire.Function(V, name=name) for name in species_names_for_output
    ]
    element_amount_functions = [
        fire.Function(V, name=name) for name in element_names_for_output
    ]

    step = 0

    species_data = []
    element_data = []

    while step <= nsteps:
        transport.step(field, dt)

        # For each selected species, output its molar amounts
        for f in species_amount_functions:
            f.assign(field.speciesAmount(f.name()))
            species_data.append(f.dat.data)

        # For each selected species, output its molar amounts
        for f in element_amount_functions:
            f.assign(field.elementAmountInPhase(f.name(), "Aqueous"))
            element_data.append(f.dat.data)

        step += 1

    species_data = {
        "n({})(step={})".format(name, i): u
        for i, (name,
                u) in enumerate(zip(species_names_for_output, species_data))
    }
    element_data = {
        "b({})(step={})".format(name, i): u
        for i, (name,
                u) in enumerate(zip(element_names_for_output, element_data))
    }
    data = {**species_data, **element_data}

    num_regression.check(data)
Exemple #3
0
def test_ternary_c1_c4_c10_bips_setup():
    """
    This is a ternary example from Whitson monograph. Retrieved from Problem 18 in
    Appendix B. This test compares the results defining BIPs as 'zero' matrix with
    the result without BIPs setup. Such results should be the same.

    .. reference:
        Whitson, C. H., & Brulé, M. R. (2000). Phase behavior (Vol. 20).
        Richardson, TX: Henry L. Doherty Memorial Fund of AIME, Society of Petroleum Engineers.
    """
    temperature = 280  # degF
    pressure = 500  # psi

    composition = np.array([0.5, 0.42, 0.08])  # molar fractions

    db = reaktoro.Database(str(get_test_data_dir() / 'hydrocarbons.xml'))

    editor = reaktoro.ChemicalEditor(db)
    editor_bips = reaktoro.ChemicalEditor(db)

    gaseous_species = ["C1(g)", "C4(g)", "C10(g)"]
    oil_species = ["C1(liq)", "C4(liq)", "C10(liq)"]

    eos_params = reaktoro.CubicEOSParams(
        model=reaktoro.CubicEOSModel.PengRobinson,
        phase_identification_method=reaktoro.PhaseIdentificationMethod.
        GibbsEnergyAndEquationOfStateMethod,
    )

    editor.addGaseousPhase(gaseous_species).setChemicalModelCubicEOS(
        eos_params)
    editor.addLiquidPhase(oil_species).setChemicalModelCubicEOS(eos_params)

    def calculate_bips(T):
        zero = 0.0
        k = [[zero, zero, zero], [zero, zero, zero], [zero, zero, zero]]
        bips = reaktoro.BinaryInteractionParams(k)
        return bips

    eos_params_bips = reaktoro.CubicEOSParams(
        model=reaktoro.CubicEOSModel.PengRobinson,
        phase_identification_method=reaktoro.PhaseIdentificationMethod.
        GibbsEnergyAndEquationOfStateMethod,
        binary_interaction_values=calculate_bips)

    editor_bips.addGaseousPhase(gaseous_species).setChemicalModelCubicEOS(
        eos_params_bips)
    editor_bips.addLiquidPhase(oil_species).setChemicalModelCubicEOS(
        eos_params_bips)

    system = reaktoro.ChemicalSystem(editor)
    system_bips = reaktoro.ChemicalSystem(editor_bips)

    problem = reaktoro.EquilibriumProblem(system)
    problem_bips = reaktoro.EquilibriumProblem(system_bips)

    problem.setTemperature(temperature, 'degF')
    problem.setPressure(pressure, 'psi')
    problem.setElementAmount('C1', composition[0])
    problem.setElementAmount('C4', composition[1])
    problem.setElementAmount('C10', composition[2])

    problem_bips.setTemperature(temperature, 'degF')
    problem_bips.setPressure(pressure, 'psi')
    problem_bips.setElementAmount('C1', composition[0])
    problem_bips.setElementAmount('C4', composition[1])
    problem_bips.setElementAmount('C10', composition[2])

    # Custom initial guess below. This is necessary for hydrocarbon mixtures.
    state = reaktoro.ChemicalState(system)
    state.setSpeciesAmounts(0.001)  # start will all having 0.001 moles
    state.setSpeciesAmount(
        "C1(g)", composition[0])  # overwrite amount of C1(g) (same below)
    state.setSpeciesAmount("C4(g)", composition[1])
    state.setSpeciesAmount("C10(g)", composition[2])

    state_bips = reaktoro.ChemicalState(system_bips)
    state_bips.setSpeciesAmounts(0.001)
    state_bips.setSpeciesAmount("C1(g)", composition[0])
    state_bips.setSpeciesAmount("C4(g)", composition[1])
    state_bips.setSpeciesAmount("C10(g)", composition[2])

    options = reaktoro.EquilibriumOptions()
    options.hessian = reaktoro.GibbsHessian.Exact

    solver = reaktoro.EquilibriumSolver(system)
    solver.setOptions(options)
    result = solver.solve(state, problem)

    solver_bips = reaktoro.EquilibriumSolver(system_bips)
    solver_bips.setOptions(options)
    result_bips = solver_bips.solve(state_bips, problem_bips)

    assert result.optimum.succeeded
    assert result_bips.optimum.succeeded

    # Compare results with and without setting BIPs
    molar_base = state.phaseAmount('Gaseous') + state.phaseAmount('Liquid')
    gas_phase_molar_fraction = state.phaseAmount('Gaseous') / molar_base
    liquid_phase_molar_fraction = state.phaseAmount('Liquid') / molar_base
    phase_fractions = np.array(
        [gas_phase_molar_fraction, liquid_phase_molar_fraction])

    molar_base_bips = state_bips.phaseAmount(
        'Gaseous') + state_bips.phaseAmount('Liquid')
    gas_phase_molar_fraction_bips = state_bips.phaseAmount(
        'Gaseous') / molar_base_bips
    liquid_phase_molar_fraction_bips = state_bips.phaseAmount(
        'Liquid') / molar_base_bips
    phase_fractions_bips = np.array(
        [gas_phase_molar_fraction_bips, liquid_phase_molar_fraction_bips])
    assert phase_fractions == pytest.approx(phase_fractions_bips)
Exemple #4
0
def test_equilibrium_CH4_CO2_pedersen():
    """
    This case is gathered from Pedersen book [1]. It is a C1-CO2 mixture using
    SRK as Cubic EOS. In P = 20 bar and T = -42 degC, it results in a LV equilibrium.
    This test compare the results from the book with Reaktoro's outcomes. The main
    goal is to check if BIPs setup is working properly. The case is given in Table 6.3
    in the Chapter 6 of [1]. The BIP value is given in the Chapter 4, Table 4.2.

    .. reference:
        [1] Pedersen, K. S., Christensen, P. L., & Shaikh, J. A. (2014). Phase behavior 
            of petroleum reservoir fluids. CRC press.
    """

    db = reaktoro.Database("supcrt98.xml")

    editor = reaktoro.ChemicalEditor(db)

    def calculate_bips(T):
        k_00 = k_11 = 0.0
        k_01 = k_10 = 0.12
        k = [
            [k_00, k_01],
            [k_10, k_11],
        ]
        bips = reaktoro.BinaryInteractionParams(k)
        return bips

    eos_params = reaktoro.CubicEOSParams(
        model=reaktoro.CubicEOSModel.SoaveRedlichKwong,
        phase_identification_method=reaktoro.PhaseIdentificationMethod.
        GibbsEnergyAndEquationOfStateMethod,
        binary_interaction_values=calculate_bips)

    editor.addGaseousPhase(["CH4(g)",
                            "CO2(g)"]).setChemicalModelCubicEOS(eos_params)
    editor.addLiquidPhase(["CH4(liq)",
                           "CO2(liq)"]).setChemicalModelCubicEOS(eos_params)

    system = reaktoro.ChemicalSystem(editor)

    problem = reaktoro.EquilibriumProblem(system)

    temperature = -42.0  # degC
    pressure = 20.0  # bar
    problem.setTemperature(temperature, "degC")
    problem.setPressure(pressure, "bar")
    problem.add("CH4(g)", 0.4, "mol")
    problem.add("CO2(g)", 0.6, "mol")

    state = reaktoro.ChemicalState(system)
    state.setSpeciesAmounts(0.001)  # start will all having 0.001 moles
    state.setSpeciesAmount("CH4(g)",
                           0.4)  # overwrite amount of C1(g) (same below)
    state.setSpeciesAmount("CO2(g)", 0.6)

    solver = reaktoro.EquilibriumSolver(problem.system())

    options = reaktoro.EquilibriumOptions()
    options.hessian = reaktoro.GibbsHessian.Exact
    solver.setOptions(options)

    result = solver.solve(state, problem)

    assert result.optimum.succeeded

    # Compare phases molar fractions
    molar_base = state.phaseAmount('Gaseous') + state.phaseAmount('Liquid')
    gas_phase_molar_fraction = state.phaseAmount('Gaseous') / molar_base
    liquid_phase_molar_fraction = state.phaseAmount('Liquid') / molar_base
    phase_fractions = np.array(
        [liquid_phase_molar_fraction, gas_phase_molar_fraction])
    F_expected = np.array([0.197, 0.803])
    assert phase_fractions == pytest.approx(F_expected, rel=2e-2)

    ch4_gas_fraction = state.speciesAmount('CH4(g)') / phase_fractions[1]
    co2_gas_fraction = state.speciesAmount('CO2(g)') / phase_fractions[1]
    equilibrium_gas_composition = np.array(
        [ch4_gas_fraction, co2_gas_fraction])
    expected_gas_composition = np.array([0.488, 0.512])
    assert equilibrium_gas_composition == pytest.approx(
        expected_gas_composition,
        rel=1e-2  # 1% rel error
    )

    ch4_liq_fraction = state.speciesAmount('CH4(liq)') / phase_fractions[0]
    co2_liq_fraction = state.speciesAmount('CO2(liq)') / phase_fractions[0]
    equilibrium_liq_composition = np.array(
        [ch4_liq_fraction, co2_liq_fraction])
    expected_liq_composition = np.array([0.042, 0.958])
    assert equilibrium_liq_composition == pytest.approx(
        expected_liq_composition,
        rel=1e-2  # 1% rel error
    )
Exemple #5
0
def test_ternary_c1_c4_c10_mixture(P, T, F_expected, x_expected, y_expected):
    """
    This is a ternary example from Whitson monograph. Retrieved from Problem 18 in
    Appendix B.

    .. reference:
        Whitson, C. H., & Brulé, M. R. (2000). Phase behavior (Vol. 20).
        Richardson, TX: Henry L. Doherty Memorial Fund of AIME, Society of Petroleum Engineers.
    """
    temperature = T  # degF
    pressure = P  # psi

    composition = np.array([0.5, 0.42, 0.08])  # molar fractions

    db = reaktoro.Database('supcrt07.xml')
    _add_hydrocarbons_to_database(db)

    editor = reaktoro.ChemicalEditor(db)

    gaseous_species = ["C1(g)", "C4(g)", "C10(g)"]
    oil_species = ["C1(liq)", "C4(liq)", "C10(liq)"]

    eos_params = reaktoro.CubicEOSParams(
        model=reaktoro.CubicEOSModel.PengRobinson,
        phase_identification_method=reaktoro.PhaseIdentificationMethod.
        GibbsEnergyAndEquationOfStateMethod,
    )

    editor.addGaseousPhase(gaseous_species).setChemicalModelCubicEOS(
        eos_params)
    editor.addLiquidPhase(oil_species).setChemicalModelCubicEOS(eos_params)

    system = reaktoro.ChemicalSystem(editor)

    problem = reaktoro.EquilibriumProblem(system)

    problem.setTemperature(temperature, 'degF')
    problem.setPressure(pressure, 'psi')
    problem.setElementAmount('C1', composition[0])
    problem.setElementAmount('C4', composition[1])
    problem.setElementAmount('C10', composition[2])

    # Custom initial guess below. This is necessary for hydrocarbon mixtures.
    state = reaktoro.ChemicalState(system)
    state.setSpeciesAmounts(0.001)  # start will all having 0.001 moles
    state.setSpeciesAmount(
        "C1(g)", composition[0])  # overwrite amount of C1(g) (same below)
    state.setSpeciesAmount("C4(g)", composition[1])
    state.setSpeciesAmount("C10(g)", composition[2])

    options = reaktoro.EquilibriumOptions()
    options.hessian = reaktoro.GibbsHessian.Exact

    solver = reaktoro.EquilibriumSolver(system)
    solver.setOptions(options)
    result = solver.solve(state, problem)

    assert result.optimum.succeeded

    molar_base = state.phaseAmount('Gaseous') + state.phaseAmount('Liquid')
    gas_phase_molar_fraction = state.phaseAmount('Gaseous') / molar_base
    liquid_molar_fraction = state.phaseAmount('Liquid') / molar_base
    phase_fractions = np.array(
        [gas_phase_molar_fraction, liquid_molar_fraction])
    assert phase_fractions == pytest.approx(F_expected, rel=5e-3)

    c1_gas_fraction = state.speciesAmount('C1(g)') / phase_fractions[0]
    c4_gas_fraction = state.speciesAmount('C4(g)') / phase_fractions[0]
    c10_gas_fraction = state.speciesAmount('C10(g)') / phase_fractions[0]
    equilibrium_gas_composition = np.array(
        [c1_gas_fraction, c4_gas_fraction, c10_gas_fraction])
    assert equilibrium_gas_composition == pytest.approx(y_expected, rel=2e-2)

    c1_liq_fraction = state.speciesAmount('C1(liq)') / phase_fractions[1]
    c4_liq_fraction = state.speciesAmount('C4(liq)') / phase_fractions[1]
    c10_liq_fraction = state.speciesAmount('C10(liq)') / phase_fractions[1]
    equilibrium_liq_composition = np.array(
        [c1_liq_fraction, c4_liq_fraction, c10_liq_fraction])
    assert equilibrium_liq_composition == pytest.approx(x_expected, rel=2e-2)
dt = 30 * minute  # the time step (in units of s)
T = 60.0 + 273.15  # the temperature (in units of K)
P = 100 * 1e5  # the pressure (in units of Pa)

# Initialise the mesh
# mesh = fire.UnitIntervalMesh(nx)
# mesh = fire.UnitCubeMesh(nx, ny, nz)
mesh = fire.UnitSquareMesh(nx, ny, quadrilateral=True)

V = fire.FunctionSpace(mesh, "CG", 1)

# Initialise the database
database = rkt.Database("supcrt98.xml")

# Initialise the chemical editor
editor = rkt.ChemicalEditor(database)
editor.addAqueousPhase("H2O(l) H+ OH- Na+ Cl- Ca++ Mg++ HCO3- CO2(aq) CO3--")
editor.addMineralPhase("Quartz")
editor.addMineralPhase("Calcite")
editor.addMineralPhase("Dolomite")

# Initialise the chemical system
system = rkt.ChemicalSystem(editor)

# Define the initial condition of the reactive transport modeling problem
problem_ic = rkt.EquilibriumProblem(system)
problem_ic.setTemperature(T)
problem_ic.setPressure(P)
problem_ic.add("H2O", 1.0, "kg")
problem_ic.add("NaCl", 0.7, "mol")
problem_ic.add("CaCO3", 10, "mol")
Exemple #7
0
def test_convergence_with_liquid_phase(num_regression):
    temperature = 343.15
    pressure = 1323.9767e5

    db = reaktoro.Database('supcrt07.xml')
    _add_lumped_oil_to_database(db)

    editor = reaktoro.ChemicalEditor(db)

    aqueous_species = [
        "H2O(l)",
        "CO2(aq)",
        "HCO3-",
        "CO3--",
        "H2S(aq)",
        "HS-",
        "SO4--",
        "Ca++",
        "Na+",
        "Cl-",
        "Fe++",
        "Ba++",
        "Sr++",
    ]
    gaseous_species = ["CO2(g)", "H2S(g)", "CH4(g)"]
    oil_species = ["H2S(liq)", "CO2(liq)", "LumpedOil(liq)"]
    minerals = [
        "Anhydrite", "Barite", "Calcite", "Celestite", "Siderite", "Pyrrhotite"
    ]

    editor.addAqueousPhase(aqueous_species)
    editor.addGaseousPhase(gaseous_species)
    editor.addLiquidPhase(oil_species)
    for mineral in minerals:
        editor.addMineralPhase(mineral)

    system = reaktoro.ChemicalSystem(editor)

    problem = reaktoro.EquilibriumProblem(system)

    problem.setTemperature(temperature)
    problem.setPressure(pressure)

    state = reaktoro.ChemicalState(system)
    state.setTemperature(temperature)
    state.setPressure(pressure)

    # AQUEOUS
    state.setSpeciesAmount("H2O(l)", 1047530951.9776191)
    state.setSpeciesAmount("CO2(aq)", 20774.560623553392)
    state.setSpeciesAmount("HCO3-", 282912.10935910186)
    state.setSpeciesAmount("CO3--", 1483.0702563458142)
    state.setSpeciesAmount("H2S(aq)", 12166.740676127629)
    state.setSpeciesAmount("HS-", 41503.521359359736)
    state.setSpeciesAmount("SO4--", 0.00000000000000000)
    state.setSpeciesAmount("Ca++", 182556.98986975398)
    state.setSpeciesAmount("Na+", 8919454.7940101717)
    state.setSpeciesAmount("Cl-", 8955756.8340308685)
    state.setSpeciesAmount("Fe++", 0.00000000000000000)
    state.setSpeciesAmount("Ba++", 13319.520269138628)
    state.setSpeciesAmount("Sr++", 20875.710568363389)

    # MINERAL
    state.setSpeciesAmount("Calcite", 999131754.50533485)
    state.setSpeciesAmount("Anhydrite", 0.00000000000000000)
    state.setSpeciesAmount("Barite", 0.00000000000000000)
    state.setSpeciesAmount("Celestite", 0.00000000000000000)
    state.setSpeciesAmount("Siderite", 6732617546.7550077)
    state.setSpeciesAmount("Pyrrhotite", 0.00000000000000000)

    # GASEOUS
    state.setSpeciesAmount("CO2(g)", 574511.37111462699)
    state.setSpeciesAmount("H2S(g)", 13303.310614909715)
    state.setSpeciesAmount("CH4(g)", 700402204.48213911)

    # LIQUID
    state.setSpeciesAmount("CO2(liq)", 821887.77968393208)
    state.setSpeciesAmount("H2S(liq)", 240596.16100715694)
    state.setSpeciesAmount("LumpedOil(liq)", 12676647027.415014)

    problem.addState(state)

    solver = reaktoro.EquilibriumSolver(system)

    state = reaktoro.ChemicalState(system)

    converged = solver.solve(state, problem).optimum.succeeded

    n = state.speciesAmounts()

    b = state.elementAmounts()

    output = {}
    output["Element amounts [mol]"] = np.asarray(b)
    output["Species amounts [mol]"] = n

    num_regression.check(output)

    assert converged