Tutorial 3: Regions and Property Specifications

Context

In this tutorial, we set up a simple field case for single-phase flow simulation (see Singlephase Flow Solver). We demonstrate how to run a basic flow simulation in the reservoir layer. We do not consider any coupling with wells. Injection and production will be specified by imposing a high pressure in the cells close to the injection area and a low pressure in the cells close to the production area.

Objectives

At the end of this tutorial you will know:

  • how to import external mesh information and properties,

  • how to run a specific solver (here, flow) in a specific region only,

  • the basic method of using boxes to set up boundary conditions,

  • how to use TableFunction to import fields varying in time and/or space,

  • how to control output frequency and export results for visualization.

Input file

The XML input file for this test case is located at:

inputFiles/singlePhaseFlow/FieldCaseTutorial3_base.xml
inputFiles/singlePhaseFlow/FieldCaseTutorial3_smoke.xml

We consider the following mesh as a numerical support to the simulations in this tutorial:

../../../../_images/full_mesh.png

This mesh contains three continuous regions:

  • a Bottom region (underburden, elementary tag = Underburden, attribute = 1)

  • a Middle region (reservoir layer, elementary tag = Reservoir, attribute = 2)

  • a Top region (overburden, elementary tag = Overburden, attribute = 3)

../../../../_images/reservoir_transparent.png

The mesh is defined using the VTK file format (see Meshes for more information on the supported mesh file format). Each tetrahedron is associated to a unique tag.

The XML file considered here follows the typical structure of the GEOS input files:

Single-phase solver

Let us inspect the Solver XML tags.

  <Solvers>
    <SinglePhaseFVM
      name="SinglePhaseFlow"
      discretization="singlePhaseTPFA"
      targetRegions="{ Reservoir }">
      <NonlinearSolverParameters
        newtonTol="1.0e-6"
        newtonMaxIter="8"/>
      <LinearSolverParameters
        solverType="gmres"
        preconditionerType="amg"
        amgSmootherType="l1jacobi"
        krylovTol="1.0e-10"/>
    </SinglePhaseFVM>
  </Solvers>

This node gathers all the information previously defined. We use a classical SinglePhaseFVM Finite Volume Method, with the two-point flux approximation as will be defined in the NumericalMethods tag. The targetRegions refers only to the Reservoir region because we only solve for flow in this region.

The NonlinearSolverParameters and LinearSolverParameters are used to set usual numerical solver parameters such as the linear and nonlinear tolerances, the preconditioner and solver types or the maximum number of nonlinear iterations.

Mesh

Here, we use the VTKMesh to load the mesh (see Importing the Mesh). The syntax to import external meshes is simple : in the XML file, the mesh file is included with its relative or absolute path to the location of the GEOS XML file and a user-specified name label for the mesh object.

  <Mesh>
    <VTKMesh name="SyntheticMesh"
                file="synthetic.vtu" />
  </Mesh>

Geometry

Here, we are using definition of source and sink boxes in addition to the all box in order to flag sets of nodes or cells which will act as injection or production.

  <Geometry>
    <Box
      name="all"
      xMin="{ -1e9, -1e9, -1e9 }"
      xMax="{ 1e9, 1e9, 1e9 }"/>

    <Box
      name="source"
      xMin="{ 15500, 7000, -5000 }"
      xMax="{ 16000, 7500, 0 }"/>

    <Box
      name="sink"
      xMin="{ 6500, 1500, -5000 }"
      xMax="{ 7000, 2000, 0 }"/>
  </Geometry>

In order to define a box, the user defines xMax and xMin, two diagonally opposite nodes of the box.

../../../../_images/reservoir_structure.png

Events

The events are used here to guide the simulation through time, and specify when outputs must be triggered.

  <Events maxTime="100.0e6">
    <PeriodicEvent name="solverApplications"
                   forceDt="10.0e6"
                   target="/Solvers/SinglePhaseFlow" />

    <PeriodicEvent name="outputs"
                   timeFrequency="10.0e6"
                   target="/Outputs/reservoir_with_properties" />
  </Events>

The Events tag is associated with the maxTime keyword defining the maximum time. If this time is ever reached or exceeded, the simulation ends.

Two PeriodicEvent are defined. - The first one, solverApplications, is associated with the solver. The forceDt keyword means that there will always be time-steps of 10e6 seconds. - The second, outputs, is associated with the output. The timeFrequency keyword means that it will be executed every 10e6 seconds.

Numerical methods

Defining the numerical method used in the solver, we will provide information on how to discretize our equations. Here a classical two-point flux approximation (TPFA) scheme is used to discretize water fluxes over faces.

  <NumericalMethods>
    <FiniteVolume>
      <TwoPointFluxApproximation
        name="singlePhaseTPFA"
      />
    </FiniteVolume>
  </NumericalMethods>

Regions

Assuming that the overburden and the underburden are impermeable, and flow only takes place in the reservoir, we need to define regions.

We need to define all the CellElementRegions according to the attribute values of the VTK file (which are respectively 1, 2 and 3 for each region). As mentioned above, the solvers is only applied on the reservoir layer, (on region 2). In this case, the ElementRegions tag is :

  <ElementRegions>
    <CellElementRegion
      name="Reservoir"
      cellBlocks="{ 2 }"
      materialList="{ water, rock }"/>

    <CellElementRegion
      name="Burden"
      cellBlocks="{ 1, 3 }"
      materialList="{ water, rock }"/>
  </ElementRegions>

Note

This material list here is subject to change if the problem is not a single-phase flow problem.

Constitutive models

We simulate a single-phase flow in the reservoir layer, hence with multiple types of materials, a fluid (water) and solid (rock permeability and porosity).

  <Constitutive>
    <CompressibleSinglePhaseFluid
      name="water"
      defaultDensity="1000"
      defaultViscosity="0.001"
      referencePressure="0.0"
      compressibility="1e-9"
      viscosibility="0.0"/>

    <CompressibleSolidConstantPermeability
      name="rock"
      solidModelName="nullSolid"
      porosityModelName="rockPorosity"
      permeabilityModelName="rockPerm"/>

    <NullModel
      name="nullSolid"/>

    <PressurePorosity
      name="rockPorosity"
      defaultReferencePorosity="0.05"
      referencePressure="10e7"
      compressibility="1.0e-9"/>

    <ConstantPermeability
      name="rockPerm"
      permeabilityComponents="{ 1.0e-13, 1.0e-13, 1.0e-16 }"/>
  </Constitutive>

The constitutive parameters such as the density, the viscosity, and the compressibility are specified in the International System of Units.

Note

To consider an incompressible fluid, the user has to set the compressibility to 0.

Note

Currently GEOS handles permeability as a diagonal matrix, so the three values of the permeability tensor are set individually using the component field. The ability for a full tensor permeability is planned for future releases.

Defining properties

The next step is to specify fields, including:

  • The initial value (here, the pressure has to be initialized)

  • The static properties (here, we have to define the permeability tensor and the porosity)

  • The boundary conditions (here, the injection and production pressure have to be set)

  <FieldSpecifications>

    <FieldSpecification
       name="permx"
       initialCondition="1"
       component="0"
       setNames="{ all }"
       objectPath="ElementRegions/Reservoir"
       fieldName="rockPerm_permeability"
       scale="1e-15"
       functionName="permxFunc"/>

     <FieldSpecification
       name="permy"
       initialCondition="1"
       component="1"
       setNames="{ all }"
       objectPath="ElementRegions/Reservoir"
       fieldName="rockPerm_permeability"
       scale="1e-15"
       functionName="permyFunc"/>

     <FieldSpecification
       name="permz"
       initialCondition="1"
       component="2"
       setNames="{ all }"
       objectPath="ElementRegions/Reservoir"
       fieldName="rockPerm_permeability"
       scale="3e-15"
       functionName="permzFunc"/>

    <FieldSpecification
      name="initialPressure"
      initialCondition="1"
      setNames="{ all }"
      objectPath="ElementRegions/Reservoir/2_tetrahedra"
      fieldName="pressure"
      scale="1e7"
      />

    <FieldSpecification
      name="sourceTerm"
      objectPath="ElementRegions/Reservoir/2_tetrahedra"
      fieldName="pressure"
      scale="15e7"
      setNames="{ source }"
      />

    <FieldSpecification
      name="sinkTerm"
      objectPath="ElementRegions/Reservoir/2_tetrahedra"
      fieldName="pressure"
      scale="5e7"
      setNames="{ sink }"/>
  </FieldSpecifications>

You may note :

  • All static parameters and initial value fields must have initialCondition field set to 1.

  • The objectPath refers to the ElementRegion in which the field has its value,

  • The setName field points to the box previously defined to apply the fields,

  • name and fieldName have a different meaning: name is used to give a name to the XML block. This name must be unique. fieldName is the name of the field registered in GEOS. This value has to be set according to the expected input fields of each solver.

Output

The Outputs XML tag is used to trigger the writing of visualization files. Here, we write files in a format natively readable by Paraview under the tag VTK:

  <Outputs>
    <VTK
      name="reservoir_with_properties"/>
  </Outputs>

Note

The name keyword defines the name of the output directory.

Using functions to specify properties

Eventually, one can define varying properties using TableFunction (Functions) under the Functions tag:

  <Functions>
    <TableFunction
      name="timeInj"
      inputVarNames="{ time }"
      coordinates="{ 1e6, 10e6, 50e6 }"
      values="{ 1, 0.01, 0.00001 }"/>

    <TableFunction
      name="initialPressureFunc"
      inputVarNames="{ elementCenter }"
      coordinateFiles="{ tables_FieldCaseTuto/xlin.geos, tables_FieldCaseTuto/ylin.geos, tables_FieldCaseTuto/zlin.geos }"
      voxelFile="tables_FieldCaseTuto/pressure.geos"/>

    <TableFunction
      name="permxFunc"
      inputVarNames="{ elementCenter }"
      coordinateFiles="{ tables_FieldCaseTuto/xlin.geos, tables_FieldCaseTuto/ylin.geos, tables_FieldCaseTuto/zlin.geos }"
      voxelFile="tables_FieldCaseTuto/permx.geos"
      interpolation="nearest"/>

    <TableFunction
      name="permyFunc"
      inputVarNames="{ elementCenter }"
      coordinateFiles="{ tables_FieldCaseTuto/xlin.geos, tables_FieldCaseTuto/ylin.geos, tables_FieldCaseTuto/zlin.geos }"
      voxelFile="tables_FieldCaseTuto/permy.geos"
      interpolation="nearest"/>

    <TableFunction
      name="permzFunc"
      inputVarNames="{ elementCenter }"
      coordinateFiles="{ tables_FieldCaseTuto/xlin.geos, tables_FieldCaseTuto/ylin.geos, tables_FieldCaseTuto/zlin.geos }"
      voxelFile="tables_FieldCaseTuto/permz.geos"
      interpolation="nearest"/>
  </Functions>

Here, the injection pressure is set to vary with time. Attentive reader might have noticed that sourceTerm was bound to a TableFunction named timeInj under FieldSpecifications tag definition. The initial pressure is set based on the values contained in the table formed by the files which are specified. In particular, the files xlin.geos, ylin.geos and zlin.geos define a regular meshing of the bounding box containing the reservoir. The pressure.geos file then defines the values of the pressure at those points.

We proceed in a similar manner as for pressure.geos to map a heterogeneous permeability field (here the 5th layer of the SPE 10 test case) onto our unstructured grid. This mapping will use a nearest point interpolation rule.

../../../../_images/mapping_perm.png

Note

The varying values imposed in values or passed through voxelFile are premultiplied by the scale attribute from FieldSpecifications.

Running GEOS

The simulation can be launched with:

geosx -i FieldCaseTutorial3_smoke.xml

One can notice the correct load of the field function among the starting output messages

Adding Mesh: VTKMesh, SyntheticMesh
Adding Event: PeriodicEvent, solverApplications
Adding Event: PeriodicEvent, outputs
Adding Solver of type SinglePhaseFVM, named SinglePhaseFlow
Adding Geometric Object: Box, all
Adding Geometric Object: Box, source
Adding Geometric Object: Box, sink
Adding Output: VTK, reservoir_with_properties
   TableFunction: timeInj
   TableFunction: initialPressureFunc
   TableFunction: permxFunc
   TableFunction: permyFunc
   TableFunction: permzFunc
Adding Object CellElementRegion named Reservoir from ObjectManager::Catalog.
Adding Object CellElementRegion named Burden from ObjectManager::Catalog.

Visualization of results

We can open the file syntheticReservoirVizFile.pvd with Paraview to visualize the simulation results. In the event block, we have asked for the output to be generated at regular intervals throughout the simulation, we can thus visualize the pressure distribution at different simulation times, showing the variation in the injection control.

../../../../_images/pressure_1e7.png ../../../../_images/pressure_1e8.png

To go further

Feedback on this tutorial

This concludes this tutorial. For any feedback, please submit a GitHub issue on the project’s GitHub page.

For more details