===============
Mesh generation
===============
**PETGEM** operates on unstructured tetrahedral meshes. The canonical workflow
generates them with `Gmsh `_ (``.msh``), but the preprocess
stage also accepts **VTK** meshes (``.vtk``/``.vtu``); the format is
auto-detected from the file. This page covers the meshing conventions that
connect a geometry to a **PETGEM** case: how regions map to material ids, and
how element sizing is chosen per polynomial order.
Physical groups and material ids
---------------------------------
Each volumetric region of the model is tagged with a Gmsh **physical volume**.
**PETGEM** maps each physical tag to a **0-based material id** as
``material_id = gmsh:physical - 1``, and that id is the row index into
``sigmas.txt`` (see :doc:`formats`).
For example, the canonical case declares two regions:
.. code-block::
Physical Volume("Resistive_block", 1) = {1}; // -> material id 0
Physical Volume("Homogeneous_half_space", 2) = {2}; // -> material id 1
so ``sigmas.txt`` row 0 is the resistive block and row 1 the half-space.
Number physical volumes consecutively from 1, and provide one ``sigmas.txt``
row per material.
For a **VTK** mesh there are no Gmsh physical tags; the per-cell region is read
from an integer **cell-data array** (auto-detected, commonly ``cell_scalars`` -
also ``materials_id``, ``material_id``, ``MaterialID``, ``material`` or
``CellEntityIds``). Its distinct codes need not be contiguous or 0-based: the
preprocess stage maps them to 0-based ids in **ascending order**, so
``sigmas.txt`` row ``i`` corresponds to the ``i``-th smallest code. For example
codes ``{10, 20, 30, 40}`` map to rows ``{0, 1, 2, 3}``. The preprocess run
prints the resulting ``code -> row`` table (with per-region cell counts), and
errors if the number of codes does not match the ``sigmas.txt`` row count.
Element sizing
--------------
The shipped ``.geo`` files parameterize the characteristic length with three
constants, applied to different parts of the geometry:
- ``lc_max``: far-field / domain-boundary element size (coarsest).
- ``lc_min``: element size along the source/receiver line (finest).
- ``lc_block``: element size inside the resistive target.
.. code-block::
lc_max = 250.;
lc_min = 5.;
lc_block = 50.;
Resolving the conductivity contrast (the target block) is what controls
accuracy; ``lc_block`` is therefore the most important knob. Refining the
source line (``lc_min``) or the far field (``lc_max``) beyond what is needed
adds elements without improving the misfit.
Per-order meshes
----------------
Because accuracy scales with both element size and polynomial order, the mesh
can be coarsened as the order rises (see the h-p tradeoff in :doc:`solver`).
The canonical case ships a separate ``mesh_p${NORD}.geo`` for each order
``1..6``, progressively coarser at higher order, so every order runs at a
comparable accuracy without over-refining.
Generating a mesh
-----------------
Generate the 3D mesh from a ``.geo`` file with Gmsh:
.. code-block:: bash
gmsh ${CSEM_TEST_DIR}/mesh_p${NORD}.geo -3 -o ${CSEM_TEST_DIR}/mesh_p${NORD}.msh
The resulting ``.msh`` is passed to ``utils/preprocess.py`` via
``-mesh_filename``, which embeds the mesh and the per-cell conductivity (looked
up from ``sigmas.txt`` by material id) into the input bundle. A pre-generated
``.msh`` can be used directly when a ``.geo`` is not shipped (as in the inverse
case, which ships ``mesh_p1.msh``).
VTK input
---------
A tetrahedral **VTK** mesh (legacy ``.vtk`` or XML ``.vtu``) can be passed to
the same ``-mesh_filename`` argument - no separate script or flag is needed, and
the rest of the command is unchanged:
.. code-block:: bash
python3 utils/preprocess.py \
-mode forward -nord 1 \
-case_dir ${CASE_DIR} \
-mesh_filename model.vtk \
-receiver_filename receivers.txt \
-source_filename sources.txt \
-sigma_file sigmas.txt
Requirements and behaviour:
- The file must contain a **tetrahedral** cell block (any accompanying
triangle/line blocks are ignored). Mixed-element meshes are not supported.
- The per-cell material id comes from a cell-data array, mapped to 0-based rows
as described under *Physical groups and material ids* above. Provide one
``sigmas.txt`` row per distinct region code, ordered by ascending code.
- Reading is handled by `meshio `_ (already a
preprocess dependency), so any tetrahedral format meshio supports works in
principle; ``.vtk``/``.vtu`` are the tested paths.