================ Inverse modeling ================ The inverse kernel in **PETGEM** recovers a subsurface conductivity model from observed CSEM data. It is built on the same high-order vector finite element core as the forward kernel: each iteration solves forward and adjoint problems on the unstructured tetrahedral mesh and assembles a gradient of the data misfit with respect to the per-cell conductivity. The model is updated with a limited-memory BFGS (L-BFGS) scheme, with Tikhonov regularization and an optional neighbor-smoothing term to stabilize the recovered model. Workflow -------- The typical workflow for CSEM inversion in **PETGEM** mirrors the forward one (the shared stages are described in :doc:`overview`), with inverse-specific inputs: 1. Generate or import a mesh using `Gmsh `_. 2. Define the starting/background conductivity model in ``sigmas.txt``, marking any materials to be held fixed with the ``fixed`` column. 3. Run ``utils/preprocess.py -mode inverse`` to assemble the input bundle. In addition to the model and receivers, the bundle embeds the multi-frequency sources, the observed data, the noise level, and the fixed-material list. 4. Execute the inverse kernel (``im.csem``) to recover the model. 5. Inspect the recovered model and convergence (optionally via VTU snapshots). Inverse inputs ************** Inverse preprocessing requires two inputs not used by forward modeling, both embedded into the bundle: - ``-inv_source_filename``: a **multi-frequency** sources text file. Unlike the forward source file (one frequency, many dipoles), each row carries 8 fields - ``freq x y z current length dip azimuth`` - one per (frequency, dipole) pair. Stored in the bundle under ``/sources/*``. - ``-observed_filename``: the observed field, as either an HDF5 file with ``/Ex [N_freq, N_recv]`` (``complex128``, {r,i} compound) **or** a raw MATLAB-style ``invEx.dat`` text file (parsed inline - no separate conversion step). Stored in the bundle under ``/observed/Ex``. See :doc:`formats` for both layouts. Two further inversion inputs are derived during preprocessing and embedded into the bundle, each overridable on the kernel command line: - **Noise level** (``/observed`` ``@error_level``): the relative data error used to weight the misfit. Set at preprocessing time with ``-error_level`` (or read from an HDF5 observed file's attribute); override at run time with ``-inv_error_level``. - **Fixed materials** (``/inv_meta/fixed_materials``): the 0-based material ids flagged in the ``fixed`` column of ``sigmas.txt``; their gradient is zeroed and the smoother treats them as self-referencing. Override with ``-inv_fixed_materials``. Parameter files *************** The inverse parameter file (emitted by ``utils/preprocess.py``) carries the bundle path plus solver and L-BFGS tuning knobs. Because the inverse kernel re-solves the system at every iteration, the default solver is a direct factorization (MUMPS). A representative inverse parameter file is: .. code-block:: -input_filename /input.h5 -ksp_type preonly -pc_type lu -pc_factor_mat_solver_type mumps -mat_mumps_icntl_14 80 -mat_mumps_icntl_28 1 -inv_max_iter 150 -inv_lbfgs_memory 2 -inv_lambda 0.1 -inv_diag_weight 0.0 -inv_gtol 1.0e-5 -inv_rms_tol 1.05 -inv_snapshot_interval 1 -output_dir / -output_filename responses The inversion knobs are: - ``-inv_max_iter``: Maximum number of L-BFGS iterations. - ``-inv_lbfgs_memory``: Number of correction pairs kept by L-BFGS. - ``-inv_lambda``: Tikhonov regularization factor. - ``-inv_diag_weight``: Self-weight in the neighbor smoother (``0`` disables it). - ``-inv_gtol``: Gradient-norm convergence tolerance. - ``-inv_rms_tol``: RMS misfit early-stop threshold. - ``-inv_snapshot_interval``: Write a conductivity VTU snapshot every N accepted steps (``0`` disables snapshots; output goes to ``-output_dir``). Each snapshot carries a single cell field, ``rho_ohm_m`` (the recovered resistivity model). - ``-inv_observed_mode``: Source of the observed data. ``external`` (default) reads the bundle's ``/observed/Ex`` dataset prepared by the preprocess; ``fm_native`` reads an ``fm.csem`` responses file directly through its native ``/sources/src{k}/fields/Ex`` layout (source ``k`` → frequency row ``k``), letting a forward run feed the inverse kernel without the Python reshape step. - ``-inv_observed_file``: Path to the observed-data file. Optional in ``external`` mode (defaults to ``-input_filename``); **required** in ``fm_native`` mode (the forward responses HDF5). Any measurement noise must already be present in that file. These may be set in the parameter file or overridden on the command line. The data-derived overrides ``-inv_error_level`` and ``-inv_fixed_materials`` are accepted but absent from the default template, since their values come from the bundle. Running PETGEM ************** A typical command for a parallel inverse execution is: .. code-block:: bash mpirun -n 4 build/im.csem -options_file path_to_params_file.txt or, equivalently, through the unified dispatcher: .. code-block:: bash mpirun -n 4 build/petgem inverse -options_file path_to_params_file.txt A complete, runnable walkthrough is given in :doc:`examples_inverse`.