Migrating from SPECFEM2D Fortran to SPECFEM++

This tutorial demonstrates how to migrate a SPECFEM2D Fortran example to the SPECFEM++ format using the anisotropic zinc crystal example. The original SPECFEM2D uses a single Par_file for both meshing and simulation, while SPECFEM++ separates these concerns into multiple configuration files.

Note

Not all physics are yet supported in SPECFEM++. This example focuses on currently working changes (the list may not be complete).

NOT SUPPORTED:
  • General physics
    • Attenuation

    • Axisymmetric simulations

    • Noise tomography

  • Timeschemes
    • Classical 4-th order Runge-Kutta

    • LDDRK

  • Sources
    • Moving sources

    • Bielak conditions

    • Acoustic forcing

  • Seismogram Output formats
    • Seismic Unix

    • Binary

  • Boundary Conditions
    • PML

  • Architecture
    • MPI

    • Simultaneous runs

Original SPECFEM2D Structure

The original example located at /specfem2d/EXAMPLES/applications/anisotropy/anisotropic_zinc_crystal/ in the SPECFEM2D repository contains:

anisotropic_zinc_crystal/
├── DATA/
│   ├── Par_file              # Single configuration file
│   ├── SOURCE               # Fortran-style source definition
│   └── topoaniso.dat        # Topography file
└── run_this_example.sh      # Execution script

You download Anisotropic Crystal ZIP to access the original example.

The specfem fortran execution patter uses a single Par_file for both meshing and simulation:

./bin/xmeshfem2D    # Uses Par_file for meshing
./bin/xspecfem2D    # Uses Par_file for simulation

SPECFEM++ Structure

The SPECFEM++ version separates the configuration into multiple files for clarity and modularity.

anisotropic-crystal/
├── Par_file                 # Updated:   Mesh parameters [and receiver parameters]
├── specfem_config.yaml      # New:       Solver configuration
├── source.yaml              # New:       Source parameters
└── topoaniso.dat            # Unchanged: Topography file

Execution uses a two-step workflow:

xmeshfem2D -p Par_file             # Meshing only [and receiver generation]
specfem2d -p specfem_config.yaml   # Simulation with YAML config

The reason we want to separate the configuration files is to improve clarity and modularity, as well as distinguishing between fortran code and new C++ implementation.

Migration Steps

These steps will follow how we approach updates to the original Par_file and translation to the new SPECFEM++ structure.

Step 1: Split the Par_file

The original Par_file contains both meshing and simulation parameters. In SPECFEM++, we separate these:

Parameters to keep from the Par_file (meshing parameters):

Par_file
# Title and output directory (required in SPECFEM++)
title = Anisotropic Crystal

# Mesh parameters
NPROC = 1
PARTITIONING_TYPE = 3
NGNOD = 4


# Receiver parameters
use_existing_STATIONS           = .false.
nreceiversets                   = 1
anglerec                        = 0.d0           # angle to rotate components at receivers
rec_normal_to_surface           = .false.        # base anglerec normal to surface (external mesh and curve file needed)
nrec                            = 50             # number of receivers
xdeb                            = 0.05           # first receiver x in meters
zdeb                            = 0.2640         # first receiver z in meters
xfin                            = 0.28           # last receiver x in meters (ignored if only one receiver)
zfin                            = 0.2640         # last receiver z in meters (ignored if only one receiver)
record_at_surface_same_vertical = .false.        # receivers inside the medium or at the surface
stations_filename              = ./OUTPUT_FILES/STATIONS


# Boundary conditions
STACEY_ABSORBING_CONDITIONS = .false.
absorbbottom = .false.
absorbright = .false.
absorbtop = .false.
absorbleft = .false.

# Material and mesh geometry
nbmodels = 1
# anisotropic: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 0 0
1 2 7100. 16.5d10 5.d10 0 6.2d10 0 3.96d10 0 0 0 0 0 0

# External files
TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz
read_external_mesh = .false.
interfacesfile = topoaniso.dat

# Domain geometry
xmin = 0.d0
xmax = 0.33
nx = 60

# Regions
nbregions = 1
# format: nxmin nxmax nzmin nzmax material_number
1 60 1 60 1

# Display parameters (for meshing output)
output_grid_Gnuplot = .false.
output_grid_ASCII = .false.

Additional Par_file parameters:

Add these to the Par_file:

OUTPUT_FILES = OUTPUT_FILES
database_filename = ./OUTPUT_FILES/database.bin
stations_filename = ./OUTPUT_FILES/STATIONS

Add new specfem_config.yaml (simulation parameters):

The solver parameters are converted from Fortran format to YAML:

specfem_config.yaml lines with comments are adopting parameters from the original Par_file
parameters:
  header:
    title: Anisotropic Crystal
    description: |
      Wave propagation through anisotropic zinc crystal

  simulation-setup:
    elastic-wave: "P_SV"    # P_SV = .true.
    quadrature:
      quadrature-type: GLL4
    solver:
      time-marching:
        type-of-simulation: forward
        time-scheme:
          type: Newmark.    # time_stepping_scheme = 1 in Par_file
          dt: 55.e-9        # From DT in Par_file
          nstep: 1500       # From NSTEP in Par_file

    simulation-mode:
      forward:
        writer:
          seismogram:       # save_ASCII_seismograms = .true.
            format: ascii
            directory: ./OUTPUT_FILES/seismograms
          display:          # Visualization parameters too different to list here
            format: PNG
            directory: ./OUTPUT_FILES/display
            field: displacement
            simulation-field: forward
            time-interval: 100  # From NTSTEP_BETWEEN_OUTPUT_IMAGES

  receivers:
    stations: "./OUTPUT_FILES/STATIONS"
    angle: 0.0
    seismogram-type:
      - displacement
    nstep_between_samples: 1

  run-setup:
    number-of-processors: 1
    number-of-runs: 1

  databases:
    mesh-database: "./OUTPUT_FILES/database.bin"

  sources: "./source.yaml"

Here, it is easiest to copy the box, where we already added the necessary parameters.

The writer.display is too different to list all the different changes, but we believe the parameters are fairly self-explanatory. See the SPECFEM++ Parameter Documentation for additional details.

Step 2: Convert SOURCE to source.yaml

The original SOURCE file uses Fortran-style parameters:

source_surf = .false.
xs = 0.165
zs = 0.165
source_type = 1
time_function_type = 1
f0 = 170000.
tshift = 0.0
anglesource = 0.0
factor = 1.d10
vx = 0.0
vz = 0.0

This converts to YAML format in source.yaml:

number-of-sources: 1
sources:
  - force:
      x : 0.165
      z : 0.165
      source_surf: false
      angle : 0.0
      vx : 0.0
      vz : 0.0
      Ricker:
        factor: 1e10
        tshift: 0.0
        f0: 170000.0

Note

Instead of numbers we use names for the different source time functions. The Ricker wavelet is used here, but you can define other types as needed. Some of the supported time functions include: - Ricker - Gaussian - dGaussian (first derivative of Gaussian) - external Please refer to the parameters documentation for more details. See Source Description for more information on the source parameters.

Running the example using SPECFEM++

# Create output directories as specified in Par_file and specfem_config.yaml
mkdir -p OUTPUT_FILES/seismograms OUTPUT_FILES/display

# Separate configuration files
xmeshfem2D -p Par_file
specfem2d -p specfem_config.yaml

Summary

This migration pattern applies to any SPECFEM2D example - identify meshing vs. solver parameters, convert source definitions to YAML, and structure the configuration files according to their specific roles in the simulation workflow.

Benefits of the New Structure

Separation of Concerns: - Meshing parameters stay in Par_file - Solver parameters moved to specfem_config.yaml

Improved Readability: - YAML format is more human-readable - Hierarchical structure reflects parameter relationships - Clear separation between different simulation aspects

Parameter Mapping Reference

Here, we list a non-exhaustive mapping of parameters from the original anisotropic zinc crystal example to the new SPECFEM++ format. This is useful for understanding how to translate the parameters from the Fortran Par_file and SOURCE file to the new SPECFEM++ configuration files.

Par_file Parameters

Some parameters are newly added or modified in SPECFEM++:

SPECFEM2D Par_file

SPECFEM++ Par_file

title = Test of anisotropic zinc crystal

title = Anisotropic Crystal

(implicit output directory)

OUTPUT_FILES = OUTPUT_FILES

(implicit stations file)

stations_filename = ./OUTPUT_FILES/STATIONS

Solver Parameters

SPECFEM2D Par_file

SPECFEM++ specfem_config.yaml

DT = 55.e-9

dt: 55.e-9

NSTEP = 1500

nstep: 1500

time_stepping_scheme = 1

type: Newmark

seismotype = 1

seismogram-type: [displacement]

save_ASCII_seismograms = .true.

format: ascii

NTSTEP_BETWEEN_OUTPUT_IMAGES = 100

time-interval: 100

output_color_image = .true.

format: PNG

imagetype_JPEG = 2

field: displacement

Source Parameters

Only listing the parameters that are different from the original Fortran SOURCE file:

SPECFEM2D SOURCE

SPECFEM++ source.yaml

xs = 0.165

x: 0.165

zs = 0.165

z: 0.165

source_surf = .false.

source_surf: false

anglesource = 0.0

angle: 0.0

time_function_type = 1

Ricker: (section)