validate_params Subroutine

private subroutine validate_params(params)

Validates all parsed parameters against physical and algorithmic limits.

Triggers fatal_error for non-physical values (e.g., negative density, zero timestep) or unsupported configurations.

Arguments

Type IntentOptional Attributes Name
type(case_params_t), intent(in) :: params

Source Code

   subroutine validate_params(params)
      type(case_params_t), intent(in) :: params

      if (params%nsteps < 0) call fatal_error('input', 'nsteps must be non-negative')
      if (params%dt <= zero) call fatal_error('input', 'dt must be positive')
      if (params%max_dt <= zero) call fatal_error('input', 'max_dt must be positive')
      if (params%min_dt <= zero) call fatal_error('input', 'min_dt must be positive')
      if (params%min_dt > params%max_dt) call fatal_error('input', 'min_dt must be <= max_dt')
      if (params%dt_growth_limit < one) call fatal_error('input', 'dt_growth_limit must be >= 1')
      if (params%max_step_retries < 0) call fatal_error('input', 'max_step_retries must be non-negative')
      if (params%step_reject_cut_factor <= zero .or. params%step_reject_cut_factor >= one) then
         call fatal_error('input', 'step_reject_cut_factor must be in (0,1)')
      end if
      if (params%step_reject_min_dt <= zero) call fatal_error('input', 'step_reject_min_dt must be positive')
      if (params%max_KE_growth_per_step < zero) call fatal_error('input', 'max_KE_growth_per_step must be non-negative')
      if (params%ke_reject_floor < zero) call fatal_error('input', 'ke_reject_floor must be non-negative')
      if (params%max_cfl_overshoot_factor < zero) call fatal_error('input', 'max_cfl_overshoot_factor must be non-negative')
      if (params%output_interval <= 0) call fatal_error('input', 'output_interval must be positive')
      if (params%terminal_interval <= 0) call fatal_error('input', 'terminal_interval must be positive')
      select case (trim(params%terminal_detail))
      case ('brief', 'health', 'full')
         continue
      case default
         call fatal_error('input', 'terminal_detail must be one of: brief, health, full')
      end select
      if (params%rho <= zero) call fatal_error('input', 'rho must be positive')
      if (params%nu < zero) call fatal_error('input', 'nu must be non-negative')
      if (params%enable_variable_nu .and. .not. params%enable_cantera_fluid) then
         call fatal_error('input', 'enable_variable_nu=.true. requires fluid_input enable_cantera=.true.; otherwise use constant nu')
      end if
      if (params%transport_update_interval <= 0) call fatal_error('input', 'transport_update_interval must be positive')
      if (params%pressure_max_iter <= 0) call fatal_error('input', 'pressure_max_iter must be positive')
      call validate_advection_scheme_local(params%momentum_convection_scheme, 'momentum_convection_scheme', .false.)
      call validate_advection_scheme_local(params%convection_scheme, 'convection_scheme', .false.)
      call validate_advection_scheme_local(params%species_convection_scheme, 'species_convection_scheme', .true.)
      call validate_advection_scheme_local(params%energy_convection_scheme, 'energy_convection_scheme', .true.)
      call validate_limiter_name_local(params%scalar_limiter)
      call validate_time_scheme_local(params%species_time_scheme, 'species_time_scheme')
      call validate_time_scheme_local(params%energy_time_scheme, 'energy_time_scheme')

      if (params%initial_T <= zero) call fatal_error('input', 'initial_T must be positive')
      if (params%energy_reference_T <= zero) call fatal_error('input', 'energy_reference_T must be positive')
      if (params%energy_cp <= zero) call fatal_error('input', 'energy_cp must be positive')
      if (params%energy_lambda < zero) call fatal_error('input', 'energy_lambda must be non-negative')
      if (params%thermo_update_interval <= 0) call fatal_error('input', 'thermo_update_interval must be positive')
      if (params%enable_cantera_thermo .and. params%thermo_update_interval /= 1) then
         call fatal_error('input', 'thermo_update_interval values other than 1 are reserved; Cantera thermo is currently updated every energy step')
      end if
      if (params%enable_cantera_thermo .and. len_trim(params%thermo_default_species) == 0) &
         call fatal_error('input', 'thermo_default_species must not be empty when enable_cantera_thermo is true')

      if (params%enable_species_enthalpy_diffusion) then
         if (.not. params%enable_energy) then
            call fatal_error('input', 'enable_species_enthalpy_diffusion requires enable_energy=.true.')
         end if
         if (.not. params%enable_species) then
            call fatal_error('input', 'enable_species_enthalpy_diffusion requires transported species')
         end if
         if (params%nspecies <= 0 .and. .not. params%enable_reactions .and. &
             .not. (params%enable_species .and. params%enable_cantera_species)) then
            call fatal_error('input', 'enable_species_enthalpy_diffusion requires nspecies > 0 unless Cantera auto-discovers mechanism species')
         end if
         if (.not. params%enable_cantera_thermo) then
            call fatal_error('input', 'enable_species_enthalpy_diffusion currently requires enable_cantera_thermo=.true. for species sensible enthalpies')
         end if
      end if

      if (params%n_patches < 0 .or. params%n_patches > max_patches) then
         call fatal_error('input', 'n_patches is outside supported range')
      end if

      if (len_trim(params%mesh_dir) == 0) then
         call fatal_error('input', 'mesh_dir cannot be empty')
      end if

      if (len_trim(params%output_dir) == 0) then
         call fatal_error('input', 'output_dir cannot be empty')
      end if

      if (params%vtu_format /= "ascii" .and. params%vtu_format /= "binary") then
         call fatal_error('input', 'vtu_format must be either "ascii" or "binary"')
      end if

      if (params%nspecies < 0 .or. params%nspecies > max_species) then
         call fatal_error('input', 'nspecies is outside supported range')
      end if

      if (params%enable_reactions) then
         if (.not. params%enable_species) call fatal_error('input', 'enable_reactions requires enable_species=.true.')
         if (.not. params%enable_energy) call fatal_error('input', 'enable_reactions requires enable_energy=.true.')
         if (.not. params%enable_cantera_thermo) call fatal_error('input', 'enable_reactions requires enable_cantera_thermo=.true.')
         if (params%chemistry_update_interval <= 0) call fatal_error('input', 'chemistry_update_interval must be positive')
         if (params%chemistry_rtol <= zero) call fatal_error('input', 'chemistry_rtol must be positive')
         if (params%chemistry_atol <= zero) call fatal_error('input', 'chemistry_atol must be positive')
         if (params%chemistry_max_steps <= 0) call fatal_error('input', 'chemistry_max_steps must be positive')
         if (params%chemistry_temperature_cutoff < zero) call fatal_error('input', 'chemistry_temperature_cutoff must be non-negative')
         if (params%chemistry_min_reactive_mass_fraction < zero) call fatal_error('input', 'chemistry_min_reactive_mass_fraction must be non-negative')
         if (params%chemistry_active_species_threshold < zero) call fatal_error('input', 'chemistry_active_species_threshold must be non-negative')
         if (params%chemistry_max_dT_per_step < zero) call fatal_error('input', 'chemistry_max_dT_per_step must be non-negative')
         if (params%chemistry_max_rel_rho_change_per_step < zero) call fatal_error('input', 'chemistry_max_rel_rho_change_per_step must be non-negative')
         if (params%chemistry_max_dY_per_step < zero) call fatal_error('input', 'chemistry_max_dY_per_step must be non-negative')
         if (params%chemistry_dt_safety <= zero .or. params%chemistry_dt_safety > one) call fatal_error('input', 'chemistry_dt_safety must be in (0,1]')
         if (params%chemistry_dt_min_factor <= zero .or. params%chemistry_dt_min_factor > one) call fatal_error('input', 'chemistry_dt_min_factor must be in (0,1]')
         if (params%chemistry_source_relaxation <= zero .or. params%chemistry_source_relaxation > one) call fatal_error('input', 'chemistry_source_relaxation must be in (0,1]')
         if (params%chemistry_n_active_species < 0 .or. params%chemistry_n_active_species > max_species) then
            call fatal_error('input', 'chemistry_n_active_species must be between 0 and max_species')
         end if
      end if

      if (params%variable_density_debug_interval <= 0) then
         call fatal_error('input', 'variable_density_debug_interval must be positive')
      end if

      if (params%enable_ignition_kernel) then
         if (.not. params%enable_energy) call fatal_error('input', 'enable_ignition_kernel requires enable_energy=.true.')
         select case (trim(lowercase(params%ignition_kernel_shape)))
         case ('sphere')
            continue
         case default
            call fatal_error('input', 'ignition_kernel_shape currently supports only sphere')
         end select
         select case (trim(lowercase(params%ignition_kernel_blend)))
         case ('overwrite')
            continue
         case default
            call fatal_error('input', 'ignition_kernel_blend currently supports only overwrite')
         end select
         if (params%ignition_kernel_radius <= zero) call fatal_error('input', 'ignition_kernel_radius must be positive')
         if (params%ignition_kernel_T <= zero) call fatal_error('input', 'ignition_kernel_T must be positive')
         if (len_trim(params%ignition_kernel_composition) > 0 .and. .not. params%enable_species) then
            call fatal_error('input', 'ignition_kernel_composition requires enable_species=.true.')
         end if
      end if

      if (params%restart_from_file .and. len_trim(params%restart_file) == 0) then
         call fatal_error('input', 'restart_from_file=.true. requires restart_file')
      end if
      if (params%write_restart) then
         if (params%restart_interval <= 0) call fatal_error('input', 'write_restart=.true. requires restart_interval > 0')
         if (len_trim(params%restart_output_dir) == 0) call fatal_error('input', 'restart_output_dir cannot be empty')
         if (params%restart_keep < 0) call fatal_error('input', 'restart_keep must be non-negative')
      end if

      if (params%enable_radiation) then
         if (.not. params%enable_energy) call fatal_error('input', 'enable_radiation requires enable_energy=.true.')
         if (params%radiation_update_interval <= 0) call fatal_error('input', 'radiation_update_interval must be positive')
         if (params%radiation_n_wavenumbers <= 0) call fatal_error('input', 'radiation_n_wavenumbers must be positive when radiation is enabled')
         if (params%radiation_n_species < 0 .or. params%radiation_n_species > max_species) then
            call fatal_error('input', 'radiation_n_species is outside supported range')
         end if
         if (params%radiation_n_species > 0 .and. .not. params%enable_species) then
            call fatal_error('input', 'radiation species selection requires enable_species=.true.')
         end if
         select case (trim(lowercase(params%radiation_source_model)))
         case ('none', 'spectral_test', 'external', 'p1', 'dom')
            continue
         case default
            call fatal_error('input', 'radiation_source_model must be one of: none, spectral_test, external, p1, dom')
         end select
         if (trim(lowercase(params%radiation_source_model)) == 'dom') then
            if (trim(lowercase(params%radiation_dom_quadrature)) /= 's2' .and. &
                trim(lowercase(params%radiation_dom_quadrature)) /= 's4' .and. &
                trim(lowercase(params%radiation_dom_quadrature)) /= 's6' .and. &
                trim(lowercase(params%radiation_dom_quadrature)) /= 's8') then
               call fatal_error('input', 'radiation_dom_quadrature must be s2, s4, s6, or s8')
            end if
         end if
         if (params%radiation_n_scalars < 0 .or. params%radiation_n_scalars > max_species) then
            call fatal_error('input', 'radiation_n_scalars is outside supported range')
         end if
         if (trim(lowercase(params%radiation_pressure_source)) /= 'background' .and. &
             trim(lowercase(params%radiation_pressure_source)) /= 'system') then
            call fatal_error('input', 'radiation_pressure_source must be one of: background, system')
         end if
      end if

      call validate_boundary_arrays(params)
   end subroutine validate_params