Skip to content

Configuration files

In exaStamp, multiple configuration files are located in the data/config folder. The master configuration file is the main-config.msp file which controls the entire simulation graph and defines both simulation, includes and configuration blocks. The content of main-config.msp and all other configuration files are displayed below.

Files included by default

Main configuration

The main-config.msp file is included by default by your input file when launching exaStamp. You can redefine its content to define new simulation scenarios at your own risk.

main-config.msp content
######################################################################################################
############################## Main configuration of exaStamp simulations ############################
######################################################################################################

######################################################################################################
############################## exaStamp logo banner + version information ############################
######################################################################################################

# Banner is generated using the ANSI Shadow style from this website:
# https://patorjk.com/software/taag/#p=display&f=ANSI+Shadow&t=exaStamp+v3.8&x=none&v=4&h=4&w=80&we=false
print_logo_banner:
  profiling: false
  body:
    - message: |

        ███████╗██╗  ██╗ █████╗ ███████╗████████╗ █████╗ ███╗   ███╗██████╗     ██╗   ██╗██████╗     █████╗ 
        ██╔════╝╚██╗██╔╝██╔══██╗██╔════╝╚══██╔══╝██╔══██╗████╗ ████║██╔══██╗    ██║   ██║╚════██╗   ██╔══██╗
        █████╗   ╚███╔╝ ███████║███████╗   ██║   ███████║██╔████╔██║██████╔╝    ██║   ██║ █████╔╝   ╚█████╔╝
        ██╔══╝   ██╔██╗ ██╔══██║╚════██║   ██║   ██╔══██║██║╚██╔╝██║██╔═══╝     ╚██╗ ██╔╝ ╚═══██╗   ██╔══██╗
        ███████╗██╔╝ ██╗██║  ██║███████║   ██║   ██║  ██║██║ ╚═╝ ██║██║          ╚████╔╝ ██████╔╝██╗╚█████╔╝
        ╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝╚══════╝   ╚═╝   ╚═╝  ╚═╝╚═╝     ╚═╝╚═╝           ╚═══╝  ╚═════╝ ╚═╝ ╚════╝

    - print_version_info

######################################################################################################
######################################################################################################

######################################################################################################
############################### Default inclusion of configuration files #############################
######################################################################################################

includes:
  - config_defaults.msp                # Configuration block default definition
  - config_move_particles.msp          # Operators for updating particles/neighbors positions + move across domain + neighbor lists
  - config_numerical_schemes.msp       # Numerical schemes (NVE, LNVT, BNVT, NHNVT, NHNPT)
  - config_globals.msp                 # Global block definition with simulation-wide default variables (global control of simulation)
  - config_thermostate.msp             # Thermodynamic state trigger + print/write operators (screen/file/compute)
  - config_snapshot.msp                # Snapshots trigger + write operators (for visualization)
  - config_restart.msp                 # Restarts trigger + write operatos (to continue a stopped simulation)
  - config_analysis.msp                # Analysis trigger + compute operators (for on-the-fly analysis)
  - config_setup_system.msp            # Default setup_system operator for setting up the system

######################################################################################################
######################################################################################################

######################################################################################################
############################ Cutoff radius pre-calculation + initialization ##########################
######################################################################################################

# Pre-calculation of cutoff radius
# Executed once (whitout verbosity) at start to enable automatic cell_size calculation
preinit_rcut_max:
  profiling: false
  rebind: { grid: null_grid, chunk_neighbors: null_neighbors, domain: empty_domain }
  body:
    - domain:
        cell_size: 0.0 ang
        grid_dims: [ 0 , 0 , 0 ]
        periodic: [ true , true , true ]
    - compute_force
    - nbh_dist

# Initialization of cutoff radius    
# Executing potential sub nodes initializes rcut_max
# won't actually compute anything since grid is empty at this time
init_rcut_max:
  profiling: false
  rebind: { grid: null_grid, chunk_neighbors: null_neighbors }
  body:
    - compute_force    # Executed on an empty grid, just here to update rcut_max
    - nbh_dist:        # Compute neighborhood distance in grid space (nbh_dist) + physical space
        verbose: true  # also computes maximum particle move tolerance in grid space (max_displ) + physical space
                       # and ghost_dist, a constant scaling of of nbh_dist using scale factor nbh_ghost_scale

######################################################################################################
######################################################################################################

######################################################################################################
############################# Hardware setup and finalization operators ##############################
######################################################################################################

# This enables the user to use --set-init_cuda-enable_cuda false to disable cuda
init_cuda:
  enable_cuda: true

# Hardware setup (communicator + CUDA initialization) + ghost configuration
hw_device_init:
  - mpi_comm_world
  - init_cuda
  - update_ghost_config

# Hardware finalization (CUDA)
hw_device_finalize:
  - finalize_cuda

######################################################################################################
######################################################################################################

######################################################################################################
############################## Simulation epilog (Write restart file) ################################
######################################################################################################

write_final_restart: write_restart

simulation_epilog:
  - default_thermostate_compute
  - write_final_restart

######################################################################################################
######################################################################################################

######################################################################################################
################################## Default initial species generation ################################
######################################################################################################

species: { species: [ ] , verbose: false }
generate_default_species: species

######################################################################################################
######################################################################################################

######################################################################################################
####################################### Simulation compute loop ######################################
######################################################################################################

# Trigger operators to know what to do later
begin_iteration:
  - trigger_restart
  - trigger_analysis
  - trigger_snapshot
  - trigger_thermostate_screen
  - trigger_thermostate_file
  - trigger_thermostate_compute

# Perform compute/print/write operations if triggered
end_iteration:
  - thermostate_compute_if_triggered
  - thermostate_screen_if_triggered
  - thermostate_file_if_triggered
  - write_restart_if_triggered
  - perform_analysis_if_triggered
  - write_snapshot_if_triggered

# First iteration of MD trajectory
first_iteration:
  - init_particles
  - compute_all_forces_energy
  - default_thermostate_compute
  - default_thermostate_screen: { lb_flag: false , move_flag: false , print_header: true }
  - default_thermostate_file
  - nose_hoover_additional_step
  - next_time_step

# If Nose-Hoover scheme is used an additional step is required
# By default, it does nothing. This is defined in the config_nose_hoover.msp file
nose_hoover_additional_step: nop

# MD Simulation loop    
md_trajectory_loop:
  loop: true
  name: md_loop
  condition: md_loop_continue
  body:
    - md_loop_prolog
    - begin_iteration
    - numerical_scheme
    - end_iteration
    - md_loop_epilog
    - next_time_step
    - md_loop_stop

# Prolog + epilog operations (nop by default)    
md_loop_prolog: nop
md_loop_epilog: nop

# Condition for stopping the MD simulation loop
# This condition is fulfilled when the current timestep reaches max_iteration
md_loop_stop:
  profiling: false
  rebind: { end_at: max_iteration , result: md_loop_continue }
  body:
    - sim_continue

######################################################################################################
######################################################################################################

######################################################################################################
##################################### Additional default definitions #################################
######################################################################################################

# Memory statistics
memory_stats: { graph_res_mem: false }

# In case the data reader (in setup_system) doesn't provide any species description
# Usually outputs ParticleSpecies type to a slot named species
reduce_species_after_read: nop

# Default grid variant we use
grid_flavor: grid_flavor_full

make_empty_grid:
  rebind: { grid: null_grid }
  body:
    - grid_flavor

# Default domain parameters
domain:
  grid_dims: [ 0 , 0 , 0 ] # deduced from cell_size
  cell_size: 0.0 ang # deduced from max rcut (a.k.a. output slot ghost_dist from nbh_dist node)
  expandable: false

# Empty regions by default
particles_regions: []

# No additional parameters by default
init_parameters: nop

# Initialization part prolog + epilog
# These can be customized in other config files (see config_nose_hoover.msp or config_molecule.msp for examples)
init_prolog: nop
init_epilog: nop

######################################################################################################
######################################################################################################

######################################################################################################
################################# exaStamp default simulation graph ##################################
######################################################################################################
simulation:
  name: exaStamp_simulation
  body:
    - print_logo_banner # Print exaStamp banner
    - hw_device_init # Hardware setup (communicator + CUDA initialization)
    - make_empty_grid # Simulation grid setup
    - grid_flavor # Grid flavor == what mandatory per-particle data is stored
    - global # Global setup
    - init_parameters # Additional parameters
    - generate_default_species # Default species
    - particle_regions # Region initialization
    - preinit_rcut_max # Automatic cell_size calculation
    - domain # Domain definition
    - init_prolog # Init prolog
    - setup_system # Setup system and populate it with particles
    - species: { verbose: false , fail_if_empty: true } # Grid memory compaction
    - grid_post_processing # Reduce species
    - reduce_species_after_read # Update particle species 
    - init_rcut_max # Update cutoff radius + displacement tolerance
    - print_domain # Print domain
    - performance_adviser: { verbose: true } # Print performance recommendations
    - init_epilog # Init epilog
    - species: { verbose: true , fail_if_empty: true }  # Species sanity check
    - first_iteration # Simulation first iteration 
    - md_trajectory_loop # Simulation compute loop
    - simulation_epilog # Simulation finalization
    - hw_device_finalize # CUDA finalization

######################################################################################################
######################################################################################################

Particle species

The config_species.msp file defines the default periodic table (H to Og) used to generate default particle species, with mass, atomic number and charge, whenever the input data reader does not provide a species description itself. It also defines reduce_species_after_read, which trims this species list down to the species actually present in the system once the input data has been read.

config_species.msp content
######################################################################################################
############################# Default configuration for particle species #############################
######################################################################################################

reduce_species_after_read:
  - species: { verbose: false }
  - reduce_species
  - species

generate_default_species:
  - message: "Initialize default species"
  - species:
      verbose: false
      species:
        - H: { mass: 1.007 Da , z: 1 , charge: 0.0 e- }
        - He: { mass: 4.002 Da , z: 2 , charge: 0.0 e- }
        - Li: { mass: 6.941 Da , z: 3 , charge: 0.0 e- }
        - Be: { mass: 9.012 Da , z: 4 , charge: 0.0 e- }
        - B: { mass: 10.811 Da , z: 5 , charge: 0.0 e- }
        - C: { mass: 12.011 Da , z: 6 , charge: 0.0 e- }
        - N: { mass: 14.007 Da , z: 7 , charge: 0.0 e- }
        - O: { mass: 15.999 Da , z: 8 , charge: 0.0 e- }
        - F: { mass: 18.998 Da , z: 9 , charge: 0.0 e- }
        - Ne: { mass: 20.18 Da , z: 10 , charge: 0.0 e- }
        - Na: { mass: 22.99 Da , z: 11 , charge: 0.0 e- }
        - Mg: { mass: 24.305 Da , z: 12 , charge: 0.0 e- }
        - Al: { mass: 26.982 Da , z: 13 , charge: 0.0 e- }
        - Si: { mass: 28.086 Da , z: 14 , charge: 0.0 e- }
        - P: { mass: 30.974 Da , z: 15 , charge: 0.0 e- }
        - S: { mass: 32.065 Da , z: 16 , charge: 0.0 e- }
        - Cl: { mass: 35.453 Da , z: 17 , charge: 0.0 e- }
        - Ar: { mass: 39.948 Da , z: 18 , charge: 0.0 e- }
        - K: { mass: 39.098 Da , z: 19 , charge: 0.0 e- }
        - Ca: { mass: 40.078 Da , z: 20 , charge: 0.0 e- }
        - Sc: { mass: 44.956 Da , z: 21 , charge: 0.0 e- }
        - Ti: { mass: 47.867 Da , z: 22 , charge: 0.0 e- }
        - V: { mass: 50.942 Da , z: 23 , charge: 0.0 e- }
        - Cr: { mass: 51.996 Da , z: 24 , charge: 0.0 e- }
        - Mn: { mass: 54.938 Da , z: 25 , charge: 0.0 e- }
        - Fe: { mass: 55.845 Da , z: 26 , charge: 0.0 e- }
        - Co: { mass: 58.933 Da , z: 27 , charge: 0.0 e- }
        - Ni: { mass: 58.693 Da , z: 28 , charge: 0.0 e- }
        - Cu: { mass: 63.546 Da , z: 29 , charge: 0.0 e- }
        - Zn: { mass: 65.38 Da , z: 30 , charge: 0.0 e- }
        - Ga: { mass: 69.723 Da , z: 31 , charge: 0.0 e- }
        - Ge: { mass: 72.64 Da , z: 32 , charge: 0.0 e- }
        - As: { mass: 74.922 Da , z: 33 , charge: 0.0 e- }
        - Se: { mass: 78.96 Da , z: 34 , charge: 0.0 e- }
        - Br: { mass: 79.904 Da , z: 35 , charge: 0.0 e- }
        - Kr: { mass: 83.798 Da , z: 36 , charge: 0.0 e- }
        - Rb: { mass: 85.468 Da , z: 37 , charge: 0.0 e- }
        - Sr: { mass: 87.62 Da , z: 38 , charge: 0.0 e- }
        - Y: { mass: 88.906 Da , z: 39 , charge: 0.0 e- }
        - Zr: { mass: 91.224 Da , z: 40 , charge: 0.0 e- }
        - Nb: { mass: 92.906 Da , z: 41 , charge: 0.0 e- }
        - Mo: { mass: 95.96 Da , z: 42 , charge: 0.0 e- }
        - Tc: { mass: 98 Da , z: 43 , charge: 0.0 e- }
        - Ru: { mass: 101.07 Da , z: 44 , charge: 0.0 e- }
        - Rh: { mass: 102.906 Da , z: 45 , charge: 0.0 e- }
        - Pd: { mass: 106.42 Da , z: 46 , charge: 0.0 e- }
        - Ag: { mass: 107.868 Da , z: 47 , charge: 0.0 e- }
        - Cd: { mass: 112.411 Da , z: 48 , charge: 0.0 e- }
        - In: { mass: 114.818 Da , z: 49 , charge: 0.0 e- }
        - Sn: { mass: 118.71 Da , z: 50 , charge: 0.0 e- }
        - Sb: { mass: 121.76 Da , z: 51 , charge: 0.0 e- }
        - Te: { mass: 127.6 Da , z: 52 , charge: 0.0 e- }
        - I: { mass: 126.904 Da , z: 53 , charge: 0.0 e- }
        - Xe: { mass: 131.293 Da , z: 54 , charge: 0.0 e- }
        - Cs: { mass: 132.905 Da , z: 55 , charge: 0.0 e- }
        - Ba: { mass: 137.327 Da , z: 56 , charge: 0.0 e- }
        - La: { mass: 138.905 Da , z: 57 , charge: 0.0 e- }
        - Ce: { mass: 140.116 Da , z: 58 , charge: 0.0 e- }
        - Pr: { mass: 140.908 Da , z: 59 , charge: 0.0 e- }
        - Nd: { mass: 144.242 Da , z: 60 , charge: 0.0 e- }
        - Pm: { mass: 145 Da , z: 61 , charge: 0.0 e- }
        - Sm: { mass: 150.36 Da , z: 62 , charge: 0.0 e- }
        - Eu: { mass: 151.964 Da , z: 63 , charge: 0.0 e- }
        - Gd: { mass: 157.25 Da , z: 64 , charge: 0.0 e- }
        - Tb: { mass: 158.925 Da , z: 65 , charge: 0.0 e- }
        - Dy: { mass: 162.5 Da , z: 66 , charge: 0.0 e- }
        - Ho: { mass: 164.93 Da , z: 67 , charge: 0.0 e- }
        - Er: { mass: 167.259 Da , z: 68 , charge: 0.0 e- }
        - Tm: { mass: 168.934 Da , z: 69 , charge: 0.0 e- }
        - Yb: { mass: 173.054 Da , z: 70 , charge: 0.0 e- }
        - Lu: { mass: 174.967 Da , z: 71 , charge: 0.0 e- }
        - Hf: { mass: 178.49 Da , z: 72 , charge: 0.0 e- }
        - Ta: { mass: 180.948 Da , z: 73 , charge: 0.0 e- }
        - W: { mass: 183.84 Da , z: 74 , charge: 0.0 e- }
        - Re: { mass: 186.207 Da , z: 75 , charge: 0.0 e- }
        - Os: { mass: 190.23 Da , z: 76 , charge: 0.0 e- }
        - Ir: { mass: 192.217 Da , z: 77 , charge: 0.0 e- }
        - Pt: { mass: 195.084 Da , z: 78 , charge: 0.0 e- }
        - Au: { mass: 196.967 Da , z: 79 , charge: 0.0 e- }
        - Hg: { mass: 200.59 Da , z: 80 , charge: 0.0 e- }
        - Tl: { mass: 204.383 Da , z: 81 , charge: 0.0 e- }
        - Pb: { mass: 207.2 Da , z: 82 , charge: 0.0 e- }
        - Bi: { mass: 208.98 Da , z: 83 , charge: 0.0 e- }
        - Po: { mass: 210 Da , z: 84 , charge: 0.0 e- }
        - At: { mass: 210 Da , z: 85 , charge: 0.0 e- }
        - Rn: { mass: 222 Da , z: 86 , charge: 0.0 e- }
        - Fr: { mass: 223 Da , z: 87 , charge: 0.0 e- }
        - Ra: { mass: 226 Da , z: 88 , charge: 0.0 e- }
        - Ac: { mass: 227 Da , z: 89 , charge: 0.0 e- }
        - Th: { mass: 232.038 Da , z: 90 , charge: 0.0 e- }
        - Pa: { mass: 231.036 Da , z: 91 , charge: 0.0 e- }
        - U: { mass: 238.029 Da , z: 92 , charge: 0.0 e- }
        - Np: { mass: 237 Da , z: 93 , charge: 0.0 e- }
        - Pu: { mass: 244 Da , z: 94 , charge: 0.0 e- }
        - Am: { mass: 243 Da , z: 95 , charge: 0.0 e- }
        - Cm: { mass: 247 Da , z: 96 , charge: 0.0 e- }
        - Bk: { mass: 247 Da , z: 97 , charge: 0.0 e- }
        - Cf: { mass: 251 Da , z: 98 , charge: 0.0 e- }
        - Es: { mass: 252 Da , z: 99 , charge: 0.0 e- }
        - Fm: { mass: 257 Da , z: 100 , charge: 0.0 e- }
        - Md: { mass: 258 Da , z: 101 , charge: 0.0 e- }
        - No: { mass: 259 Da , z: 102 , charge: 0.0 e- }
        - Lr: { mass: 262 Da , z: 103 , charge: 0.0 e- }
        - Rf: { mass: 261 Da , z: 104 , charge: 0.0 e- }
        - Db: { mass: 262 Da , z: 105 , charge: 0.0 e- }
        - Sg: { mass: 266 Da , z: 106 , charge: 0.0 e- }
        - Bh: { mass: 264 Da , z: 107 , charge: 0.0 e- }
        - Hs: { mass: 267 Da , z: 108 , charge: 0.0 e- }
        - Mt: { mass: 268 Da , z: 109 , charge: 0.0 e- }
        - Ds: { mass: 271 Da , z: 110 , charge: 0.0 e- }
        - Rg: { mass: 272 Da , z: 111 , charge: 0.0 e- }
        - Cn: { mass: 285 Da , z: 112 , charge: 0.0 e- }
        - Nh: { mass: 284 Da , z: 113 , charge: 0.0 e- }
        - Fl: { mass: 289 Da , z: 114 , charge: 0.0 e- }
        - Mc: { mass: 288 Da , z: 115 , charge: 0.0 e- }
        - Lv: { mass: 292 Da , z: 116 , charge: 0.0 e- }
        - Ts: { mass: 295 Da , z: 117 , charge: 0.0 e- }
        - Og: { mass: 294 Da , z: 118 , charge: 0.0 e- }

Default configuration block

The config_defaults.msp file defines the configuration block, which sets the default physical units (angstrom, Dalton, picosecond, elementary charge, kelvin, etc.), logging/profiling/debug options, and threading settings (mpimt, pinethreads, num_threads).

config_defaults.msp content
######################################################################################################
##################################### Default configuration block  ###################################
######################################################################################################

configuration:
  physics:
    units:
      length: angstrom
      mass: Dalton
      time: picosecond
      charge: elementary_charge
      temperature: kelvin
      amount: particle
      luminosity: candela
      angle: radian
      energy: joule
  logging:
    parallel: false
    debug: false
    profiling: false
  profiling:
    exectime: false
    summary: false
  debug:
    plugins: false
    config: false
    graph: false
    graph_lod: 0
    filter: []
  mpimt: true
  pinethreads: false
  num_threads: {}
  omp_max_nesting: 2

######################################################################################################
######################################################################################################

Particle motion and neighbor lists

The config_move_particles.msp file defines the operators used to move particles across MPI domains, update ghost particles and neighbor lists, and trigger load balancing. It includes config_load_balance.msp by default, which defines the default load-balancing cost model and RCB-based balancing operators.

config_move_particles.msp content
######################################################################################################
############### Default configuration for building neighbor list and updating particles ##############
######################################################################################################

######################################################################################################
################################## Include load balancing  ###########################################

includes:
  - config_load_balance.msp

######################################################################################################
######################################################################################################

######################################################################################################
###################################### Trigger function  #############################################

# define a test node which outputs a boolean value 'trigger_move_particles'
# which tells when to move particles across cells and update neighbor lists
trigger_move_particles:
  rebind: { threshold: max_displ , threshold_lab: max_displ_lab , result: trigger_move_particles }
  body:
    - particle_displ_over

######################################################################################################
######################################################################################################

################### AMR ############################
rebuild_amr:
  sub_grid_density: 6.5
  amr_z_curve: false
  enforced_ordering: 1
####################################################

######################################################################################################
############################# Default ghost update configuration  ####################################

update_ghost_config:
  verbose: true
  update_ghost_config:
    mpi_tag: 0
    gpu_buffer_pack: true
    async_buffer_pack: true
    staging_buffer: true
    serialize_pack_send: true
    wait_all: false
    device_side_buffer: false

######################################################################################################
######################################################################################################

######################################################################################################
################################### Neighbors list update  ###########################################

chunk_neighbors:
  config:
    free_scratch_memory: false
    build_particle_offset: true
    subcell_compaction: true
    scratch_mem_per_cell: 1048576
    stream_prealloc_factor: 1.05 # standard value to avoid most of dynamic allocations
    chunk_size: 1

chunk_neighbors_impl: chunk_neighbors

update_particle_neighbors:
  - amr_grid_pairs
  - chunk_neighbors_impl
  - resize_particle_locks

######################################################################################################
######################################################################################################

######################################################################################################
############################### Parallell particles migration  #######################################

grid_post_processing: grid_memory_compact

profile_ghost_comm_scheme: nop
#profile_ghost_comm_scheme: print_ghost_comm_stats # exchange volume stats
#profile_ghost_comm_scheme: print_ghost_comm_scheme # full print

ghost_update_all_impl: ghost_update_all_no_fv

ghost_full_update:
  - ghost_comm_scheme
  - profile_ghost_comm_scheme
  - ghost_update_all_impl

parallel_update_particles:
  - migrate_cell_particles
  - rebuild_amr
  - backup_r
  - ghost_full_update
  - grid_post_processing
  - update_particle_neighbors

######################################################################################################
######################################################################################################

######################################################################################################
################################## Particles Initialization  #########################################

# define actions to initialize particles at startup, just after file read
init_particles:
  - move_particles
  - extend_domain
  - load_balance
  - parallel_update_particles

######################################################################################################
######################################################################################################

######################################################################################################
################################## Particles Initialization  #########################################

# NOTE : Full update is done when trigger_move_particles is true, i.e. when a particle has displaced
# more than half the skin size since the last update.
# NOTE : Fast update is done each time step, except when full update is done.

# Body part of update_particles_full operator
update_particles_full_body:
  - move_particles
  - trigger_load_balance
  - load_balancing_if_triggered
  - parallel_update_particles

# Conditional update_particles_full operator  
update_particles_full:
  condition: trigger_move_particles
  body:
    - update_particles_full_body

# Body part of update_particles_fast operator
update_particles_fast_body:
    - ghost_update_r

# Conditional update_particles_fast operator  
update_particles_fast:
  condition: not trigger_move_particles
  body:
    - update_particles_fast_body

######################################################################################################
############################# Main function called in all numerical schemes ##########################

check_and_update_particles:
  - trigger_move_particles
  - update_particles_full
  - update_particles_fast
  - loadbalance_log_helper:
      rebind: { lb_flag: trigger_load_balance , move_flag: trigger_move_particles }
      body: [ lb_event_counter ]

######################################################################################################
######################################################################################################

Numerical schemes

The config_numerical_schemes.msp file contains the exaStamp default and available numerical schemes: velocity-Verlet NVE, Langevin NVT, Berendsen NVT, and Nosé-Hoover NVT/NPT. The scheme actually used is selected through the numerical_scheme variable.

config_numerical_schemes.msp content
######################################################################################################
######################## Default configuration for numerical schemes  ################################
######################################################################################################

######################################################################################################
################# Default configuration for forces and energy calculations  ##########################

compute_force_prolog: zero_force_energy
compute_force: nop
compute_force_epilog: force_to_accel

compute_all_forces_energy:
  - compute_force_prolog
  - compute_force
  - compute_force_epilog

######################################################################################################
######################################################################################################

######################################################################################################
####################################### Velocity-Verlet Steps ########################################

verlet_first_half:
  - push_f_v_r: { dt_scale: 1.0, xform_mode: INV_XFORM }
  - push_f_v: { dt_scale: 0.5, xform_mode: IDENTITY }

verlet_second_half:
  - push_f_v: { dt_scale: 0.5, xform_mode: IDENTITY }

######################################################################################################
######################################################################################################

######################################################################################################
#################################### Default numerical scheme: NVE ###################################

numerical_scheme: verlet_nve

######################################################################################################
######################################################################################################

######################################################################################################
######################################### Numerical scheme NVE #######################################

verlet_nve:
  name: NVE_scheme
  body:
    - verlet_first_half
    - check_and_update_particles
    - load_balance_auto_tune_start
    - compute_all_forces_energy
    - verlet_second_half
    - load_balance_auto_tune_end

######################################################################################################
######################################################################################################

######################################################################################################
#################################### Numerical scheme NVT Langevin ###################################

verlet_lnvt:
  name: LNVT_scheme
  body:
    - verlet_first_half
    - check_and_update_particles
    - load_balance_auto_tune_start
    - compute_force_prolog
    - compute_force
    - langevin_thermostat
    - compute_force_epilog
    - verlet_second_half
    - load_balance_auto_tune_end

######################################################################################################
######################################################################################################

######################################################################################################
################################### Numerical scheme NVT Berendsen ###################################

verlet_bnvt:
  name: BNVT_scheme
  body:
    - verlet_first_half
    - check_and_update_particles
    - load_balance_auto_tune_start
    - compute_force_prolog
    - compute_force
    - compute_force_epilog
    - verlet_second_half
    - simulation_thermodynamic_state
    - berendsen_thermostat
    - load_balance_auto_tune_end

######################################################################################################
######################################################################################################

######################################################################################################
################################## Numerical scheme NVT Nosé-Hoover ##################################

verlet_nhnvt:
  name: NHNVT_scheme
  body:
    - simulation_thermodynamic_state
    - nhc_temp_integrate
    - nh_v_temp:
        rebind: { value: vscale }
        body: [ scale_v ]
    - compute_vel_bias:
        rebind: { out: vbias }
        body: [ avg_v_m ]
    - remove_vel_bias:
        rebind: { value: vbias }
        body: [ shift_v ]
    - push_f_v: { dt_scale: 0.5, xform_mode: IDENTITY }
    - push_v_r: { dt_scale: 1.0, xform_mode: INV_XFORM }
    - check_and_update_particles
    - load_balance_auto_tune_start
    - compute_all_forces_energy
    - push_f_v: { dt_scale: 0.5, xform_mode: IDENTITY }
    - simulation_thermodynamic_state
    - nhc_temp_integrate
    - nh_v_temp:
        rebind: { value: vscale }
        body: [ scale_v ]
    - load_balance_auto_tune_end

######################################################################################################
######################################################################################################

######################################################################################################
################################## Numerical scheme NPT Nosé-Hoover ##################################

verlet_nhnpt:
  name: NHNPT_scheme
  body:
    - simulation_thermodynamic_state
    - nhc_press_integrate
    - nhc_temp_integrate
    - nh_v_temp:
        rebind: { value: vscale }
        body: [ scale_v ]
    - compute_vel_bias:
        rebind: { out: vbias }
        body: [ avg_v_m ]
    - remove_vel_bias:
        rebind: { value: vbias }
        body: [ shift_v ]
    - simulation_thermodynamic_state
    - couple_npt
    - nh_omega_dot
    - nh_v_press
    - push_f_v: { dt_scale: 0.5, xform_mode: IDENTITY }
    - remap_npt
    - push_v_r: { dt_scale: 1.0, xform_mode: INV_XFORM }
    - remap_npt
    - check_and_update_particles
    - load_balance_auto_tune_start
    - compute_all_forces_energy
    - push_f_v: { dt_scale: 0.5, xform_mode: IDENTITY }
    - simulation_thermodynamic_state
    - nh_v_press
    - simulation_thermodynamic_state
    - couple_npt
    - nh_omega_dot
    - nhc_temp_integrate
    - nh_v_temp:
        rebind: { value: vscale }
        body: [ scale_v ]
    - nhc_press_integrate
    - load_balance_auto_tune_end

######################################################################################################
######################################################################################################

Global block

The config_globals.msp file defines the global block, which holds simulation-wide default variables such as the number of timesteps, timestep size, restart/snapshot/analysis/thermostate frequencies, and load-balancing parameters.

config_globals.msp content
######################################################################################################
######################################### Default global block  ######################################
######################################################################################################

global:
  max_iteration: 1000                            # number of timesteps
  start_iteration: 0                             # number of timesteps  
  rcut_inc: 1.0 ang                              # skin distance for neighbor list 
  timestep: 0                                    # starting timestep
  physical_time: 0.                              # starting physical time
  dt: 1.0e-3 ps                                  # timestep
  log_mode: mechanical                           # set to chemistry or default

  simulation_restart_frequency: 1000             # restart frequency
  simulation_snapshot_frequency: 1000            # snapshot frequency  
  simulation_analysis_frequency: 1000            # analysis frequency
  simulation_thermostate_file_frequency: 10      # thermostate to file frequency
  thermostate_file: "thermodynamic_state.csv"    # default name of .csv thermostate file
  simulation_thermostate_screen_frequency: 10    # thermostate to screen frequency

  simulation_load_balance_frequency: 100         # load balancing frequency
  enable_load_balance: true                      # enable load balancing
  trigger_cost_model_fitting: false              # for load balancing
  cost_model_coefs: [ 0.0 , 0.0 , 1.0 , 0.0 ]    # for load balancing (RCB)
  enable_grid_compact: true                      # Enable array shrinking of particle arrays
  init_temperature: -1.0
  scale_temperature: -1.0
  md_loop_continue: true                         # needed for the computation loop to start
  trigger_thermo_state: true                     # needed to get the initial thermo state

######################################################################################################
######################################################################################################

Thermodynamic state

The config_thermostate.msp file defines the trigger, compute, screen-print and file-write operators for the thermodynamic state (temperature, pressure, energy, etc.).

config_thermostate.msp content
######################################################################################################
####################### Default configuration for thermodynamic state functions ######################
######################################################################################################

######################################################################################################
############################### Print thermodynamic state to the screen ##############################

# Trigger function
trigger_thermostate_screen:
  rebind: { freq: simulation_thermostate_screen_frequency , result: trigger_thermostate_screen, lb_flag: trigger_load_balance , move_flag: trigger_move_particles }
  body:
    - nth_timestep: { first: true }

# Printing function
thermostate_screen_if_triggered:
  condition: trigger_thermostate_screen
  body:
    - default_thermostate_screen: { print_header: false }

# Default operator
default_thermostate_screen:  print_thermodynamic_state

######################################################################################################
######################################################################################################

######################################################################################################
################################# Write thermodynamic state to a file ################################

# Trigger function
trigger_thermostate_file:
  rebind: { freq: simulation_thermostate_file_frequency , result: trigger_thermostate_file }
  body:
    - nth_timestep: { first: true }

# Writing function
thermostate_file_if_triggered:
  condition: trigger_thermostate_file
  body:
    - default_thermostate_file: { print_header: false }

# Default operator
default_thermostate_file: dump_thermodynamic_state

######################################################################################################
######################################################################################################

######################################################################################################
##################################### Compute thermodynamic state ####################################

# Trigger function
trigger_thermostate_compute:
  - combine1:
      rebind: { in1: trigger_restart , in2: trigger_thermostate_screen , result: output1 }
      body:
        - boolean_or
  - combine2:
      rebind: { in1: output1 , in2: trigger_thermostate_file , result: trigger_thermostate_compute }
      body:
        - boolean_or

# Compute function
thermostate_compute_if_triggered:
  condition: trigger_thermostate_compute
  body:
    - default_thermostate_compute

# Default operator
default_thermostate_compute: simulation_thermodynamic_state

######################################################################################################
######################################################################################################

Snapshots

The config_snapshot.msp file defines the trigger and write operators for simulation snapshots, along with a collection of predefined writers (Paraview, grid VTK, XYZ, LAMMPS data) used for visualization.

config_snapshot.msp content
######################################################################################################
################################# Default configuration for snapshot  ################################
######################################################################################################

######################################################################################################
############################# Default snapshot operator : no snapshot  ###############################

write_snapshot: nop

######################################################################################################
######################################################################################################

######################################################################################################
#################################### Snapshot trigger function  ######################################

trigger_snapshot:
  rebind: { freq: simulation_snapshot_frequency , result: trigger_snapshot }
  body:
    - nth_timestep

######################################################################################################
######################################################################################################

######################################################################################################
################################ Conditional operator for snapshot  ##################################

write_snapshot_if_triggered:
  condition: trigger_snapshot
  body:
    - write_snapshot

######################################################################################################
######################################################################################################

######################################################################################################
########################### Collection of pre-defined snapshot operators #############################

write_snapshot_paraview:
  - timestep_file: "paraview/output_%09d"
  - message: { mesg: "Write paraview file" , endl: false }
  - print_dump_file:
      rebind: { mesg: filename }
      body:
        - message: { endl: true }
  - write_paraview

write_snapshot_grid_vtk:
  - grid_flavor
  - resize_grid_cell_values
  - atom_cell_projection
  - timestep_file: "grid_%09d"
  - message: { mesg: "Write grid vtk file" , endl: false }
  - print_dump_file:
      rebind: { mesg: filename }
      body:
        - message: { endl: true }
  - write_grid_vtk

write_snapshot_xyz:
  - timestep_file: "exaStamp_%09d.xyz"
  - message: { mesg: "Write xyz file" , endl: false }
  - print_dump_file:
      rebind: { mesg: filename }
      body:
        - message: { endl: true }
  - write_xyz_file

write_snapshot_lammps_data:
  - timestep_file: "exaStamp_%09d.lmp"
  - message: { mesg: "Write lammps data file" , endl: false }
  - print_dump_file:
      rebind: { mesg: filename }
      body:
        - message: { endl: true }
  - write_lmp_file

######################################################################################################
######################################################################################################

Restarts

The config_restart.msp file defines the trigger and write operators for restart files, along with a collection of predefined writers (ExaStampV4, StampV4, StampV3, native atoms/molecule/rigid-molecule formats) used to continue a stopped simulation.

config_restart.msp content
######################################################################################################
################################# Default configuration for restart  #################################
######################################################################################################

######################################################################################################
############################## Default restart operator : no restart  ################################

write_restart: nop

######################################################################################################
######################################################################################################

######################################################################################################
##################################### Restart trigger function  ######################################

trigger_restart:
  rebind: { freq: simulation_restart_frequency , result: trigger_restart }
  body:
    - nth_timestep

######################################################################################################
######################################################################################################

######################################################################################################
################################ Conditional operator for restart  ###################################

write_restart_if_triggered:
  condition: trigger_restart
  body:
    - write_restart

######################################################################################################
######################################################################################################

######################################################################################################
########################### Collection of pre-defined restart operators ##############################

write_restart_exastamp_v4:
  rebind: { thermodynamic_state: thermodynamic_state_4_dump }
  body:
    - timestep_file: "ExaStampV4prot_%09d.MpiIO"
    - message: { mesg: "Write restart " , endl: false }
    - print_restart_file:
        rebind: { mesg: filename }
        body:
          - message: { endl: true }
    - simulation_thermodynamic_state
    - write_exastamp_v4

write_restart_stamp_v4:
  rebind: { thermodynamic_state: thermodynamic_state_4_dump }
  body:
    - timestep_file: "StampV4prot_%09d.MpiIO"
    - message: { mesg: "Write restart " , endl: false }
    - print_restart_file:
        rebind: { mesg: filename }
        body:
          - message: { endl: true }
    - simulation_thermodynamic_state
    - write_stamp_v4

write_restart_stamp_v3:
  - timestep_file: "StampV3prot_%09d.MpiIO"
  - message: { mesg: "Write restart " , endl: false }
  - print_restart_file:
      rebind: { mesg: filename }
      body:
        - message: { endl: true }
  - write_stamp_v3

# Native ExaNB restart format for single atoms
write_restart_atoms:
  - timestep_file: "atoms_%09d.MpiIO"
  - message: { mesg: "Write restart " , endl: false }
  - print_restart_file:
      rebind: { mesg: filename }
      body:
        - message: { endl: true }
  - write_dump_atoms

# Native ExaNB restart format for rigid molecules
write_restart_rigid_molecule:
  - timestep_file: "rigidmol_%09d.MpiIO"
  - message: { mesg: "Write restart " , endl: false }
  - print_restart_file:
      rebind: { mesg: filename }
      body:
        - message: { endl: true }
  - write_dump_rigidmol

# Native exaNBody restart format for flexible molecules
write_restart_molecule:
  - timestep_file: "molecule_%09d.MpiIO"
  - message: { mesg: "Write restart " , endl: false }
  - print_restart_file:
      rebind: { mesg: filename }
      body:
        - message: { endl: true }
  - write_dump_molecule

######################################################################################################
######################################################################################################

Analysis

The config_analysis.msp file defines the trigger and compute operators for on-the-fly analysis, along with a predefined connected-component labeling operator (perform_analysis_ccl).

config_analysis.msp content
######################################################################################################
################################# Default configuration for analysis #################################
######################################################################################################

######################################################################################################
############################# Default analysis operator : no analysis  ###############################

perform_analysis: nop

######################################################################################################
######################################################################################################

######################################################################################################
#################################### Analysis trigger function  ######################################

trigger_analysis:
  rebind: { freq: simulation_analysis_frequency , result: trigger_analysis }
  body:
    - nth_timestep

######################################################################################################
######################################################################################################

######################################################################################################
################################ Conditional operator for analysis  ##################################

perform_analysis_if_triggered:
  condition: trigger_analysis
  body:
    - perform_analysis

######################################################################################################
######################################################################################################

######################################################################################################
########################### Collection of pre-defined analysis operators #############################

perform_analysis_ccl:
  - grid_flavor
  - resize_grid_cell_values
  - atom_cell_projection
  - cc_label
  - timestep_file: "cc_%09d"
  - write_grid_vtk
  - timestep_file: "cc_table_%09d"
  - write_cc_table

######################################################################################################
######################################################################################################

System setup

The config_setup_system.msp file contains the default definition of the setup_system block. By default, it tries to read the lastLegacyDump file with StampV3 format. If the read fails, it generates a default species and print the message No input data.

config_setup_system.msp content
######################################################################################################
############################### Default configuration for setup_system ###############################
######################################################################################################

# StampV3 reader
read_stamp_v3:
  file: lastLegacyDump
  filename: lastLegacyDump
  bounds_mode: FILE

# Operator that tests if file exists
has_legacy_dump_file:
  rebind: { result: has_dump_file }
  body: [ file_exists: { filename: lastLegacyDump } ]

# Definition of setup_system operator  
setup_system:
  - has_legacy_dump_file
  - read_lastLegacyDump:
      condition: has_dump_file
      body: [ read_stamp_v3 ]
  - reset_input_data:
      condition: not has_dump_file
      body:
        - message: "No input data"
        - grid_flavor
        - species:
            verbose: false
            species:
              - XX: { mass: 1.0 Da , z: 1 , charge: 0.0 e- }

######################################################################################################
######################################################################################################

Additional available files

Additional files available to the includes: command are located in data/config. Depending on your simulation scenario, include them as follows:

1
2
3
includes:
  - file1.msp
  - file2.msp

Applying deformation

Whenever you need to dynamically impose a deformation to your box through the xform_function operator, include the config_deformation.msp file. This file pre-applies a deformation gradient tensor called deformation_xform to the simulation cell and appends the xform_function operator to the md_loop_prolog. This basically means that each timestep, the user-defined deformation will be applied at the end of the step.

config_deformation.msp content
######################################################################################################
######################## Deformation-related specific init functions  ################################
######################################################################################################

# Initialize an applied deformation that does nothing
+init_prolog:
  - deformation_xform:
      defbox: { extension: [ 1.0, 1.0, 1.0 ] }

# End of MD loop : apply deformation
md_loop_prolog:
  - xform_function
  - nbh_dist

# No deformation function by default: F = I
xform_function: nop

######################################################################################################
######################################################################################################

Nosé-Hoover ensembles

Whenever you use one of the Nosé-Hoover numerical schemes (verlet_nhnvt or verlet_nhnpt, defined in config_numerical_schemes.msp), include the config_nose_hoover.msp file. It initializes the Nosé-Hoover chain variables and defines nose_hoover_additional_step, the extra integration step these schemes require at the end of each timestep.

config_nose_hoover.msp content
######################################################################################################
############################ Nose-Hoover specific init functions  ####################################
######################################################################################################

+init_prolog:
  - deformation_xform:
      defbox: { extension: [ 1.0 , 1.0 , 1.0 ] }

+init_epilog:
  - init_nose_hoover

nose_hoover_additional_step:  
  - setup_nose_hoover
  - couple_npt

######################################################################################################
######################################################################################################

Symmetric force contributions

Whenever your force field can exploit Newton's third law to halve pair computations, include the config_update_symmetric_forces.msp file. It zeroes forces and energies on ghost particles too, then adds a step that accumulates ghost contributions back onto local particles before forces are pushed to acceleration.

config_update_symmetric_forces.msp content
######################################################################################################
####################### Default configuration for symmetric forces contribution ######################
######################################################################################################

# Zero force and energy everywhere and in the ghosts as well
compute_force_prolog:
  - zero_force_energy: { ghost: true }

# Update forces of non-ghost particles from their ghosts before pushing total force to acceleration
compute_force_epilog:
  - update_force_energy_from_ghost
  - force_to_accel

######################################################################################################
######################################################################################################

Flexible molecules

Whenever your simulation involves flexible (bonded) molecules, include the config_molecule.msp file. It switches to an extramolecular neighbor list, adds bonded (bond/bend/torsion/improper) and non-bonded force computations, sets a dedicated molecule restart writer, and adjusts the default domain cell size.

config_molecule.msp content
######################################################################################################
###################### Default configuration for flexible molecules calculations #####################
######################################################################################################

######################################################################################################
######################################### Restart function ###########################################

write_restart: write_restart_molecule

######################################################################################################
######################################################################################################

######################################################################################################
################################### Neighbors list update  ###########################################

extramolecular_neighbors:
  config:
    free_scratch_memory: false
    build_particle_offset: false
    subcell_compaction: true
    scratch_mem_per_cell: 1048576
    stream_prealloc_factor: 1.05 # standard value to avoid most of dynamic allocations
    chunk_size: 1

chunk_neighbors_impl: extramolecular_neighbors

parallel_update_particles:
  - migrate_cell_particles
  - rebuild_amr
  - backup_r
  - ghost_full_update
  - grid_post_processing
  - id_map
  - mol_extract_connectivity
  - intramolecular_pair_list
  - mol_optimize_connectivity
  - update_particle_neighbors

######################################################################################################
######################################################################################################

######################################################################################################
################################### Force calculation procedure ######################################

# Prolog: add long range energy correction if needed
compute_force_prolog: zero_force_energy_with_correction

# Default configuration of ljexp6rf_pc
ljexp6rf_pc:
  enable_pair_weights: false
  per_atom_charge: true
  use_symmetry: false
  compute_virial: false

# Non bonding forces (default = ljexp6rf_pc)
compute_nonbonding_forces:
  rebind: { parameters: potentials_for_pairs }
  body: [ ljexp6rf_pc ]

# Bonding forces
compute_bonding_forces:
  - compute_force_bond
  - compute_force_bend
  - compute_force_torsion
  - compute_force_improper
  - intramolecular_pair_force

# Total forces (nonbonding + bonding)  
compute_force:
  - compute_nonbonding_forces
  - compute_bonding_forces

######################################################################################################
######################################################################################################

######################################################################################################
############################## Some default operators for molecules ##################################

preinit_rcut_max: nop

+init_epilog:
  - intramolecular_setup

domain:
  cell_size: 8 ang
  periodic: [true, true, true]
  expandable: false

######################################################################################################
######################################################################################################

Rigid molecules

Whenever your simulation involves rigid molecules, include the config_rigid_molecule.msp file. It defines rigid-molecule-specific thermodynamic state, restart, and numerical-scheme operators (quaternion/torque integration), plus an optional temperature initialization step.

config_rigid_molecule.msp content
######################################################################################################
######################## Default configuration for rigid molecules calculations ######################
######################################################################################################

######################################################################################################
######################################### Restart function ###########################################

write_restart: write_restart_rigid_molecule

######################################################################################################
######################################################################################################

######################################################################################################
############################# Thermodynamic state operators procedure ################################

default_thermostate_compute: simulation_thermodynamic_state_rigidmol

default_thermostate_screen: print_thermodynamic_state_rigidmol

default_thermostate_file: dump_thermodynamic_state_rigidmol

######################################################################################################
######################################################################################################

######################################################################################################
######################################## Numerical schemes ###########################################

update_particles_fast_body:
  - ghost_update_rq

verlet_first_half:
  - push_f_v_r: { dt_scale: 1.0, xform_mode: INV_XFORM }
  - push_f_v: { dt_scale: 0.5, xform_mode: IDENTITY }
  - torque_to_quaternion

verlet_second_half:
  - push_f_v: { dt_scale: 0.5, xform_mode: IDENTITY }
  - push_torque_angmom

######################################################################################################
######################################################################################################

######################################################################################################
################################### Temperature initialization #######################################

do_init_temperature:
  - block1:
      rebind: { value: init_temperature, result: enable_init_temperature }
      body:
        - greater_than: { threshold: 0.0 K }
  - block3:
      condition: enable_init_temperature
      rebind: { T: init_temperature }
      body:
        - message: "Initialize temperature"
        - init_mass_center
        - init_rigid_mol_inertial_mass
        - gaussian_noise_v
        - random_orient
        - init_temperature_rigidmol

######################################################################################################
######################################################################################################

Load balancing auto-tuning

Whenever you want the load-balancing cost model to be fitted automatically from measured per-cell compute costs, instead of relying on the fixed cost_model_coefs values, include the config_load_balance_auto_tune.msp file. It periodically profiles the grid and re-fits the cost model at the frequency set by simulation_load_balance_frequency.

config_load_balance_auto_tune.msp content
######################################################################################################
####################### Default configuartion for load balancing auto tuning  ########################
######################################################################################################

# Automatic fitting of cost model parameters (prolog)
cost_model_fitting_prolog:
  - trigger_cost_model_fitting:
      condition: enable_load_balance
      rebind: { result: trigger_cost_model_fitting , freq: simulation_load_balance_frequency }
      body:
        - nth_timestep: { first: false , delayed: true }
  - do_cost_model_fitting_prolog:
      condition: trigger_cost_model_fitting
      rebind: { rcut: nbh_dist_lab }
      body:
        - message: "Start load balance auto tuning"
        - start_grid_cell_profiling # starting profiling befor prefetchng also prefetch cell profiling data array
        - zero_compute_force: { type: ignore } # data prefetching for more accurate measure
        - start_grid_cell_profiling # prepare for real profiling during compute_force block

# Automatic fitting of cost model parameters (epilog)        
cost_model_fitting_epilog:
  condition: trigger_cost_model_fitting
  body:
    - cost_model_fit: { order: 2 , samples: 256 }

# Override start stop operators for auto tuning of cost model
load_balance_auto_tune_start: cost_model_fitting_prolog
load_balance_auto_tune_end: cost_model_fitting_epilog

######################################################################################################
######################################################################################################

Conjugate-gradient energy minimization

Whenever you want to relax a structure to a local energy minimum instead of running time-integrated dynamics, include the config_conjugate_gradient.msp file. It replaces the whole simulation: scenario with a Fletcher-Reeves conjugate-gradient loop plus an Armijo backtracking line search — see Energy Minimization for the full tunable/algorithm reference.

config_conjugate_gradient.msp content
######################################################################################################
################# Conjugate-gradient energy minimization (Fletcher-Reeves + Armijo line search) ######
######################################################################################################
#
# This defines a whole alternative simulation scenario (see 'simulation:' override at the bottom):
# instead of the usual time-integrated md_trajectory_loop, the top level loop here iterates a CG
# minimization step until the force falls below a tolerance (or the iteration/wall-clock limits from
# sim_continue kick in). There is no time integration: 'timestep' is still counted (so restart/
# snapshot/screen triggers and sim_continue's max_iteration/stop-file/signal handling keep working
# unchanged) but dt stays at 0 and physical_time never advances.
#
# vx,vy,vz (normally velocity) are repurposed to hold the CG search direction h, since a static
# minimization has no use for real velocities. Consequence: do NOT resume a time-integrated scheme
# (verlet_nve, ...) directly from a restart file written during/after a CG run without first
# re-initializing velocities (see init_temperature/scale_temperature in config_globals.msp) -
# otherwise the CG direction vector would be read back in as spurious atomic velocities.
#
# Every non-trivial piece below is its own operator connected purely through named input/output
# slots (cg_force_stats, cg_beta, cg_direction, cg_trial_step, ...); the actual iterate-until-
# converged control flow is expressed declaratively with the same loop/condition batch mechanism
# used by md_trajectory_loop in main-config.msp, plus the generic greater_than/boolean_and/
# boolean_set building blocks already used elsewhere in this codebase (cg_value_scale is the
# one new small generic-shaped operator this file adds, see numerical_schemes/cg_value_scale.cpp).

######################################################################################################
############################### A note on force units #################################################

# compute_force_epilog is left untouched here (still whatever the including config already set it
# to - typically force_to_accel, or update_force_energy_from_ghost + force_to_accel when
# config_update_symmetric_forces.msp is used): overriding it unconditionally would silently drop
# potential-specific steps like the ghost-force fold-back that some potentials rely on.
# Consequence: fx,fy,fz (aliased to ax,ay,az) hold force divided by mass, not raw force. For a
# single-species system this is just a global constant rescale (beta and the search direction are
# unaffected - the mass cancels in the Fletcher-Reeves ratio), it only shifts what units
# cg_tolerance and the Armijo bound are expressed in. For a multi-species system it also mildly
# biases the search direction towards lighter atoms; harmless for convergence (force_max still
# drives the stopping test on whatever is in fx,fy,fz) but worth knowing about if you want a strict
# per-species-mass-independent minimizer.

######################################################################################################
############################################ Tunables #################################################

# These become named OUTPUT slots via the 'global' operator's own YAML handling (see
# global.cpp/make_global_operator) - a bare top-level 'key: value' entry elsewhere in an .msp
# file is not a generic slot-default mechanism, it only works nested under 'global:' like this
# (merged key-by-key with whatever config_globals.msp/baseline.yaml already declared there).
global:
  cg_tolerance: 1.0e-4          # convergence threshold on max atomic force magnitude
  alpha: 0.01 ang                # current line-search step (max single-atom displacement); adapts
  alpha_min: 1.0e-7 ang          # give up the line search (and the whole CG run) below this step size
  alpha_max: 1.0 ang             # cap on step growth after repeated accepted steps
  alpha_shrink_factor: 0.5       # step *= this on a rejected trial
  alpha_grow_factor: 1.2         # step *= this on an accepted trial
  c1: 1.0e-4                     # Armijo sufficient-decrease constant
  cg_restart_period: 20           # force a steepest-descent restart (beta=0) every N iterations -
                                  # plain Fletcher-Reeves directions degrade without this, plateauing
  cg_dt: 0.0 ps                  # fed to next_time_step so physical_time never advances
  cg_loop_continue: true         # needed for the cg_trajectory_loop to start (mirrors md_loop_continue)
  cg_continue_search: true       # needed for the cg_line_search_loop to start (same reason)
  cg_sim_continue_ok: true       # sim_continue only ever writes false explicitly, never true -
                                  # this seeds it so the very first check doesn't default to false

cg_loop_prolog: nop
cg_loop_epilog: nop

######################################################################################################
################################## Per-iteration progress print #######################################

# Replaces what gets printed by the default thermostate screen trigger (kinetic energy/temperature
# are meaningless here since vx,vy,vz hold the CG direction, not velocity), while keeping the exact
# same trigger/frequency machinery (trigger_thermostate_screen) from config_thermostate.msp.
thermostate_screen_if_triggered:
  condition: trigger_thermostate_screen
  body:
    - cg_progress_screen

cg_progress_screen:
  - cg_print_iter:
      rebind: { value: timestep }
      body: [ print_int: { prefix: "CG iteration " , suffix: "  " } ]
  # ref_energy (used by cg_armijo_bound) and force_max as fed into cg_direction/cg_beta/
  # cg_trial_step stay in internal units - only cg_check_force_converged (the convergence test,
  # a standalone decision that doesn't feed any other internal-unit-consistent formula) and this
  # progress screen convert a copy to eV/eV-per-atom, exactly like print_thermodynamic_state does
  # (see thermo_energy_display.cpp).
  - cg_force_max_ev:
      rebind: { value: force_max , value_ev: force_max_ev }
      body: [ internal_to_ev ]
  - cg_print_force:
      rebind: { value: force_max_ev }
      body: [ print_real: { prefix: "Fmax(eV/ang)=" , suffix: "  " } ]
  - cg_energy_ev:
      rebind: { value_ev: ref_energy_ev }
      body: [ thermo_potential_energy_ev_per_atom ]
  - cg_print_energy:
      rebind: { value: ref_energy_ev }
      body: [ print_real: { prefix: "Epot(eV/atom)=" } ]
  - message: { mesg: "" }

######################################################################################################
################################## Backtracking line search ###########################################

# One trial: move along h by the current step, refresh ghost positions (cheap - full neighbor
# rebuild only happens once per outer iteration, after acceptance, see cg_trajectory_loop below),
# recompute forces/energy, and accept/reject against the Armijo bound.
cg_line_search_loop:
  loop: true
  name: cg_ls_loop
  condition: cg_continue_search
  body:
    - cg_trial_step
    - ghost_update_r
    - compute_all_forces_energy
    - simulation_thermodynamic_state
    - cg_snapshot_trial_energy:
        rebind: { value: trial_energy }
        body: [ thermo_potential_energy ]
    - cg_armijo_bound
    - cg_check_armijo:
        rebind: { value: trial_energy , threshold: bound , result: reject_step }
        body: [ greater_than ]
    # Temporary per-trial debug print, so it's visible whether the line search is grinding
    # through many backtracks or genuinely stuck. Remove once things behave as expected.
    - cg_ls_debug_print_alpha:
        rebind: { value: alpha }
        body: [ print_real: { prefix: "  [line search] alpha=" , suffix: " " } ]
    - cg_ls_debug_print_reject:
        rebind: { value: reject_step }
        body: [ print_bool: { prefix: "reject=" } ]
    - message: { mesg: "" }
    - cg_restore_if_rejected:
        condition: reject_step
        body: [ restore_r_lt ]
    - cg_check_alpha_floor:
        rebind: { value: alpha , threshold: alpha_min , result: line_search_ok }
        body: [ greater_than ]
    - cg_shrink_if_rejected:
        condition: reject_step
        body:
          - cg_alpha_shrink:
              rebind: { value: alpha , factor: alpha_shrink_factor }
              body: [ cg_value_scale ]
    - cg_grow_if_accepted:
        condition: not reject_step
        body:
          - cg_alpha_grow:
              rebind: { value: alpha , factor: alpha_grow_factor , max: alpha_max }
              body: [ cg_value_scale ]
    # boolean_and's result is a plain OUTPUT slot, not INPUT_OUTPUT like sim_continue's -
    # the batch/loop compiler only auto-wires a loop's own body-computed value back into its
    # own "condition:" slot when the last producer is an in-place (INPUT_OUTPUT) pipe (this is
    # exactly how cg_loop_continue/md_loop_continue self-reference via sim_continue below).
    # A bare boolean_and here would leave cg_continue_search's only producer as whatever
    # external sibling seeds it once (see cg_continue_search's global default) - never updated
    # again, so the search would never stop. Route the computed value through boolean_set's
    # in-place "value" slot instead.
    - cg_compute_continue_search:
        rebind: { in1: reject_step , in2: line_search_ok , result: continue_search_computed }
        body: [ boolean_and ]
    - cg_update_continue_search:
        rebind: { value: cg_continue_search , set: continue_search_computed }
        body: [ boolean_set ]

######################################################################################################
################################## Outer CG iteration loop #############################################

cg_trajectory_loop:
  loop: true
  name: cg_loop
  condition: cg_loop_continue
  body:
    - cg_loop_prolog
    - begin_iteration
    - simulation_thermodynamic_state
    - cg_force_stats
    # force_max is in internal units (force/mass - see the note on force units above). Comparing
    # it directly against cg_tolerance meant cg_tolerance=1.0e-5 was actually an effective
    # ~1e-9 eV/ang threshold (same conversion factor as fire_tolerance's fix in config_fire.msp,
    # ~9650x for this Cu/EAM system) - unreachable in practice, since the line search always gave
    # up on alpha_min exhaustion first, around Fmax~1e-5 to 1e-4 eV/ang. Compare the eV-converted
    # copy instead so cg_tolerance means what it looks like it means. Never feed this converted
    # copy into cg_armijo_bound's own internal comparison - display/threshold uses only.
    - cg_force_max_ev_check:
        rebind: { value: force_max , value_ev: force_max_ev }
        body: [ internal_to_ev ]
    - cg_check_force_converged:
        rebind: { value: force_max_ev , threshold: cg_tolerance , result: force_not_converged }
        body: [ greater_than ]
    # "rebind:" only takes effect through the batch-construction code path, which only runs when
    # the referenced name is NOT itself a registered C++ factory. cg_beta IS a registered factory,
    # so this bare form silently dropped the rebind (yaml_initialize never reads "rebind" - it
    # only applies literal value overrides matching existing slot names). Wrapping with a
    # distinctly-named batch + explicit body: is what actually makes it apply.
    - cg_beta_step:
        rebind: { restart_period: cg_restart_period }
        body: [ cg_beta ]
    - cg_direction
    - cg_snapshot_ref_energy:
        rebind: { value: ref_energy }
        body: [ thermo_potential_energy ]
    - backup_r_lt
    # Needed every outer iteration: cg_line_search_loop's own run() gate reads cg_continue_search
    # BEFORE its body executes at all, and the PREVIOUS outer iteration's line search left it
    # false (that's what stopped it). Without resetting to true here, run() would skip the whole
    # search from iteration 2 onward. This is safe now that cg_update_continue_search (inside
    # cg_line_search_loop) is also an in-place boolean_set - both wire into the same shared
    # resource instead of one shadowing the other (see notes in cg_line_search_loop above).
    - cg_reset_continue_search:
        rebind: { value: cg_continue_search }
        body: [ boolean_set: { set: true } ]
    - cg_line_search_loop
    - check_and_update_particles
    - end_iteration
    - cg_loop_epilog
    - cg_next_iteration:
        rebind: { dt: cg_dt }
        body: [ next_time_step ]
    - cg_sim_continue:
        rebind: { end_at: max_iteration , result: cg_sim_continue_ok }
        body: [ sim_continue ]
    - cg_combine_continue_1:
        rebind: { in1: cg_sim_continue_ok , in2: force_not_converged , result: cg_partial_continue }
        body: [ boolean_and ]
    - cg_combine_continue_2:
        rebind: { in1: cg_partial_continue , in2: line_search_ok , result: loop_continue_computed }
        body: [ boolean_and ]
    # Same in-place-pipe requirement as cg_continue_search above - boolean_and's plain OUTPUT
    # can't self-feed cg_trajectory_loop's own condition.
    - cg_update_loop_continue:
        rebind: { value: cg_loop_continue , set: loop_continue_computed }
        body: [ boolean_set ]

######################################################################################################
################################## CG-flavored simulation scenario #####################################

# Same as first_iteration in main-config.msp, minus nose_hoover_additional_step (irrelevant here).
cg_first_iteration:
  - init_particles
  - compute_all_forces_energy
  - default_thermostate_compute
  - cg_force_stats
  - cg_snapshot_ref_energy:
      rebind: { value: ref_energy }
      body: [ thermo_potential_energy ]
  - cg_progress_screen
  - default_thermostate_file
  - cg_next_iteration:
      rebind: { dt: cg_dt }
      body: [ next_time_step ]

# Identical to the default 'simulation:' in main-config.msp, except first_iteration/
# md_trajectory_loop are swapped for their CG counterparts - everything else (setup, species,
# domain, load balancing, ...) is reused unchanged.
simulation:
  name: exaStamp_cg_minimization
  body:
    - print_logo_banner
    - hw_device_init
    - make_empty_grid
    - grid_flavor
    - global
    - init_parameters
    - generate_default_species
    - particle_regions
    - preinit_rcut_max
    - domain
    - init_prolog
    - setup_system
    - species: { verbose: false , fail_if_empty: true }
    - grid_post_processing
    - reduce_species_after_read
    - init_rcut_max
    - print_domain
    - performance_adviser: { verbose: true }
    - init_epilog
    - species: { verbose: true , fail_if_empty: true }
    - cg_first_iteration
    - cg_trajectory_loop
    - simulation_epilog
    - hw_device_finalize

######################################################################################################
######################################################################################################

FIRE 2.0 energy minimization

Whenever you want a faster, inertia-based relaxation to a local energy minimum, include the config_fire.msp file. It replaces the whole simulation: scenario with the FIRE 2.0 algorithm (Bitzek et al. 2006 / Guénolé et al. 2020) — see Energy Minimization for the full tunable/algorithm reference.

config_fire.msp content
######################################################################################################
################# FIRE 2.0 energy minimization (Bitzek et al. 2006 / Guenole et al. 2020) ###########
######################################################################################################
#
# This defines a whole alternative simulation scenario (see 'simulation:' override at the bottom):
# instead of the time-integrated md_trajectory_loop or the conjugate-gradient cg_trajectory_loop
# (see config_conjugate_gradient.msp), fire_trajectory_loop performs genuine MD-with-inertia
# pseudo-dynamics (Velocity-Verlet + an adaptive velocity/force mixing bias) until the force falls
# below a tolerance. Unlike CG, vx,vy,vz here hold real velocity - FIRE's whole idea is to use
# ordinary Newtonian dynamics with a steering term, so no field repurposing is needed. dt itself
# (fire_dt) is adaptive and IS fed to next_time_step, so physical_time advances meaningfully here
# (unlike CG's fixed cg_dt=0), consistent with FIRE being genuine (if fictitious) MD.
#
# Every non-trivial piece below is its own operator connected through named input/output slots
# (fire_power, fire_adapt, fire_norms, fire_velocity_mix, fire_zero_velocity - all in
# src/numerical_schemes/fire_*.cpp), reusing exaNBody's own push_f_v/push_v_r Verlet operators
# (rebound to fire_dt instead of the simulation's fixed global dt) and cg_force_stats (a fully
# generic force reduction despite its name) for the end-of-step force_max. The outer loop's
# control flow uses the same loop/condition batch mechanism as md_trajectory_loop/
# cg_trajectory_loop - see the note on self-referencing loop conditions below.

######################################################################################################
############################################ Tunables #################################################

# Defaults mirror FIRE 2.0's published/LAMMPS defaults (Guenole et al. 2020, Table 1): tmax=10,
# tmin=0.02, delaystep=20, dtgrow=1.1, dtshrink=0.5, alpha0=0.25, alphashrink=0.99, vdfmax=2000.
global:
  fire_tolerance: 1.0e-4          # convergence threshold on max atomic force magnitude
  fire_dt_start: 1.0e-3 ps        # reference timestep dt_max/dt_min are scaled from (paper recommends
                                  # the same value as an MD run at low temperature would use)
  fire_dt: 1.0e-3 ps              # current adaptive timestep; seeded to fire_dt_start
  fire_dt_max_factor: 10.0        # tmax: dt_max = fire_dt_start * this
  fire_dt_min_factor: 0.02        # tmin: dt_min = fire_dt_start * this
  fire_delaystep: 20              # N_delay: consecutive downhill steps needed before dt grows again;
                                  # also gates the startup grace period before the first shrink
  fire_dt_grow: 1.1               # dt *= this after delaystep consecutive downhill steps
  fire_dt_shrink: 0.5             # dt *= this on an uphill/stationary step
  fire_alpha_start: 0.25          # alpha0: mixing coefficient right after a reset
  fire_alpha: 0.25                # current adaptive mixing coefficient; seeded to fire_alpha_start
  fire_alpha_shrink: 0.99         # alpha *= this after delaystep consecutive downhill steps
  fire_pneg_max: 2000             # vdfmax: give up after this many consecutive uphill steps
  fire_initial_delay: true        # skip the very first dt-shrinks during the startup grace period
  fire_loop_continue: true        # needed for fire_trajectory_loop to start (mirrors md_loop_continue)
  fire_sim_continue_ok: true      # sim_continue only ever writes false explicitly, never true -
                                  # this seeds it so the very first check doesn't default to false

fire_loop_prolog: nop
fire_loop_epilog: nop

######################################################################################################
################################## Per-iteration progress print #######################################

# Reuses the exact same trigger/frequency machinery (trigger_thermostate_screen) as
# config_thermostate.msp; redefining "thermostate_screen_if_triggered" here means end_iteration's
# own generic call to it (see main-config.msp) picks up fire_progress_screen automatically - no
# need to invoke it again inside fire_trajectory_loop's own body.
thermostate_screen_if_triggered:
  condition: trigger_thermostate_screen
  body:
    - fire_progress_screen

fire_progress_screen:
  - fire_print_iter:
      rebind: { value: timestep }
      body: [ print_int: { prefix: "FIRE iteration " , suffix: "  " } ]
  - fire_force_max_ev:
      rebind: { value: force_max , value_ev: force_max_ev }
      body: [ internal_to_ev ]
  - fire_print_force:
      rebind: { value: force_max_ev }
      body: [ print_real: { prefix: "Fmax(eV/ang)=" , suffix: "  " } ]
  - fire_energy_ev:
      rebind: { value_ev: ref_energy_ev }
      body: [ thermo_potential_energy_ev_per_atom ]
  - fire_print_energy:
      rebind: { value: ref_energy_ev }
      body: [ print_real: { prefix: "Epot(eV/atom)=" , suffix: "  " } ]
  - fire_print_dt:
      rebind: { value: fire_dt }
      body: [ print_real: { prefix: "dt(ps)=" , suffix: "  " } ]
  - fire_print_alpha:
      rebind: { value: fire_alpha }
      body: [ print_real: { prefix: "alpha=" } ]
  - message: { mesg: "" }

######################################################################################################
################################## FIRE 2.0 trajectory loop #############################################

# One outer iteration = one FIRE step: compute the power P=F.v from the state left over at the
# end of the previous iteration (or the initial v=0), adapt dt/alpha and correct if the previous
# step went uphill, then perform one Velocity-Verlet step with the mixing folded in between the
# first half-kick and the drift (Guenole et al. 2020, Algorithm 6 - mixing uses the PRE-step force
# and the post-half-kick velocity, not the post-step ones).
fire_trajectory_loop:
  loop: true
  name: fire_loop
  condition: fire_loop_continue
  body:
    - fire_loop_prolog
    - begin_iteration
    - simulation_thermodynamic_state
    - fire_power
    # NOTE: "rebind:" is only ever applied by the batch-construction code path, which only
    # triggers when the referenced name is NOT itself a registered C++ factory (an "implicit
    # batch" fallback). fire_adapt IS a registered factory, so a bare "fire_adapt: {rebind:...}"
    # (no body:) would silently drop the rebind entirely - yaml_initialize only applies literal
    # value overrides matching EXISTING slot names, it never reads "rebind" at all. Wrapping it
    # in a distinctly-named batch with an explicit body: is what actually makes rebind apply
    # (same reason every OTHER rebind in this file, and in config_conjugate_gradient.msp, uses a
    # wrapper name different from the thing it wraps).
    - fire_adapt_step:
        rebind:
          dt_start: fire_dt_start
          dt_max_factor: fire_dt_max_factor
          dt_min_factor: fire_dt_min_factor
          delaystep: fire_delaystep
          dt_grow: fire_dt_grow
          dt_shrink: fire_dt_shrink
          alpha_start: fire_alpha_start
          alpha_shrink: fire_alpha_shrink
          pneg_max: fire_pneg_max
          initial_delay: fire_initial_delay
          dt: fire_dt
          alpha: fire_alpha
          n_ppos: fire_n_ppos
          n_pneg: fire_n_pneg
          iter: fire_iter
          uphill: fire_uphill
          fire_not_stalled: fire_not_stalled
        body: [ fire_adapt ]
    # Correct uphill motion from the PREVIOUS step (Algorithm 2 lines 28-29): move back by half
    # the (possibly just-shrunk) new dt using the still-nonzero velocity, THEN zero it - order
    # matters, the correction needs v before it's cleared.
    - fire_uphill_correct:
        condition: fire_uphill
        body:
          - fire_halfstep_back:
              rebind: { dt: fire_dt }
              body: [ push_v_r: { dt_scale: -0.5 , xform_mode: INV_XFORM } ]
          - fire_zero_velocity
    - fire_kick1:
        rebind: { dt: fire_dt }
        body: [ push_f_v: { dt_scale: 0.5 } ]
    - fire_norms
    - fire_velocity_mix_step:
        rebind: { alpha: fire_alpha }
        body: [ fire_velocity_mix ]
    - fire_drift:
        rebind: { dt: fire_dt }
        body: [ push_v_r: { dt_scale: 1.0 , xform_mode: INV_XFORM } ]
    - check_and_update_particles
    - compute_all_forces_energy
    - fire_kick2:
        rebind: { dt: fire_dt }
        body: [ push_f_v: { dt_scale: 0.5 } ]
    - cg_force_stats
    # force_max is in internal units (fx,fy,fz hold force/mass here, same as CG - see the note on
    # force units at the top of config_conjugate_gradient.msp). Unlike CG's cg_tolerance (left in
    # raw units, undocumented pitfall waiting to bite - it just never mattered because CG always
    # stopped on alpha_min first), compare the eV-converted copy here so fire_tolerance means what
    # it looks like it means (eV/ang), not ~9700x smaller. Never feed this converted copy into an
    # actual internal computation (e.g. the mixing ratio) - display/threshold comparisons only.
    - fire_force_max_ev_check:
        rebind: { value: force_max , value_ev: force_max_ev }
        body: [ internal_to_ev ]
    - fire_check_force_converged:
        rebind: { value: force_max_ev , threshold: fire_tolerance , result: force_not_converged }
        body: [ greater_than ]
    - fire_snapshot_ref_energy:
        rebind: { value: ref_energy }
        body: [ thermo_potential_energy ]
    - end_iteration
    - fire_loop_epilog
    - fire_next_iteration:
        rebind: { dt: fire_dt }
        body: [ next_time_step ]
    - fire_sim_continue:
        rebind: { end_at: max_iteration , result: fire_sim_continue_ok }
        body: [ sim_continue ]
    - fire_combine_continue_1:
        rebind: { in1: fire_sim_continue_ok , in2: force_not_converged , result: fire_partial_continue }
        body: [ boolean_and ]
    - fire_combine_continue_2:
        rebind: { in1: fire_partial_continue , in2: fire_not_stalled , result: fire_loop_continue_computed }
        body: [ boolean_and ]
    # boolean_and's result is a plain OUTPUT slot, not INPUT_OUTPUT like sim_continue's - route
    # through boolean_set's in-place "value" slot so it actually self-feeds the condition above.
    - fire_update_loop_continue:
        rebind: { value: fire_loop_continue , set: fire_loop_continue_computed }
        body: [ boolean_set ]

######################################################################################################
################################## FIRE-flavored simulation scenario #####################################

# Same as cg_first_iteration, minus nose_hoover_additional_step: sets v(t)=0 (Algorithm line 2)
# before the first progress print.
fire_first_iteration:
  - init_particles
  - compute_all_forces_energy
  - default_thermostate_compute
  - fire_zero_velocity
  - cg_force_stats
  - fire_snapshot_ref_energy:
      rebind: { value: ref_energy }
      body: [ thermo_potential_energy ]
  - fire_progress_screen
  - default_thermostate_file
  - fire_next_iteration:
      rebind: { dt: fire_dt }
      body: [ next_time_step ]

# Identical to the default 'simulation:' in main-config.msp, except first_iteration/
# md_trajectory_loop are swapped for their FIRE counterparts - everything else (setup, species,
# domain, load balancing, ...) is reused unchanged.
simulation:
  name: exaStamp_fire_minimization
  body:
    - print_logo_banner
    - hw_device_init
    - make_empty_grid
    - grid_flavor
    - global
    - init_parameters
    - generate_default_species
    - particle_regions
    - preinit_rcut_max
    - domain
    - init_prolog
    - setup_system
    - species: { verbose: false , fail_if_empty: true }
    - grid_post_processing
    - reduce_species_after_read
    - init_rcut_max
    - print_domain
    - performance_adviser: { verbose: true }
    - init_epilog
    - species: { verbose: true , fail_if_empty: true }
    - fire_first_iteration
    - fire_trajectory_loop
    - simulation_epilog
    - hw_device_finalize

######################################################################################################
######################################################################################################