Skip to content

File EmissionConfigValidator_Mod.F90

File List > core > EmissionConfigValidator_Mod.F90

Go to the documentation of this file

module emissionconfigvalidator_mod
   use precision_mod
   use error_mod
   use statemanager_mod, only : statemanagertype
   use chemstate_mod, only : chemstatetype
   ! use logging_mod, only : log_message, LOG_INFO

   implicit none
   private

   public :: emissionconfigvalidatortype
   public :: validationresulttype
   public :: validation_success, validation_warning, validation_error

   ! Validation result constants
   integer, parameter :: VALIDATION_SUCCESS = 0
   integer, parameter :: VALIDATION_WARNING = 1
   integer, parameter :: VALIDATION_ERROR = 2

   type :: validationresulttype
      integer :: status = validation_success
      character(len=512) :: message = ''
      character(len=32) :: species_name = ''
      character(len=32) :: emission_source = ''
   end type validationresulttype

   type :: emissionconfigvalidatortype
      private

      ! Validation settings
      logical :: strict_mode = .false.
      logical :: require_mass_conservation = .true.
      real(fp) :: mass_conservation_tolerance = 1.0e-6_fp
      logical :: check_species_existence = .true.
      logical :: validate_units = .true.
      logical :: check_scale_factors = .true.

      ! Validation statistics
      integer :: n_warnings = 0
      integer :: n_errors = 0
      integer :: n_species_validated = 0

   contains
      procedure :: validate_emission_config
      procedure :: validate_species_mapping
      procedure :: validate_emission_sources
      procedure :: validate_vertical_distributions
      procedure :: validate_mass_conservation

      ! Utility methods
      procedure :: reset_counters
      procedure :: get_validation_summary
      procedure :: set_validation_mode

      ! Private validation helpers
      procedure, private :: validate_single_species
      procedure, private :: check_species_in_mechanism
      procedure, private :: validate_scale_factors
   end type emissionconfigvalidatortype

contains

   subroutine validate_emission_config(this, config_file, container, results, rc)
      class(EmissionConfigValidatorType), intent(inout) :: this
      character(len=*), intent(in) :: config_file
      type(StateManagerType), intent(inout) :: container
      type(ValidationResultType), allocatable, intent(out) :: results(:)
      integer, intent(out) :: rc

      type(ErrorManagerType), pointer :: error_mgr
      character(len=256) :: message
      integer :: max_results = 1000
      integer :: n_results = 0

      rc = cc_success
      error_mgr => container%get_error_manager()

      ! Reset validation counters
      call this%reset_counters()

      ! Allocate results array
      allocate(results(max_results))

      write(message, '(A,A)') 'Starting validation of emission config: ', trim(config_file)
      print *, trim(message)

      ! TODO: Parse YAML configuration file
      ! For now, we'll validate the example configuration

      ! Validate species mappings
      call this%validate_species_mapping(container, results, n_results, rc)
      if (rc /= cc_success) return

      ! Validate emission sources
      call this%validate_emission_sources(results, n_results, rc)
      if (rc /= cc_success) return

      ! Validate vertical distributions
      call this%validate_vertical_distributions(results, n_results, rc)
      if (rc /= cc_success) return

      ! Resize results array to actual size
      if (n_results > 0) then
         results = results(1:n_results)
      else
         deallocate(results)
         allocate(results(0))
      end if

      ! Report validation summary
      call this%get_validation_summary(message)
      print *, trim(message)

   end subroutine validate_emission_config

   subroutine validate_species_mapping(this, container, results, n_results, rc)
      class(EmissionConfigValidatorType), intent(inout) :: this
      type(StateManagerType), intent(inout) :: container
      type(ValidationResultType), intent(inout) :: results(:)
      integer, intent(inout) :: n_results
      integer, intent(out) :: rc

      ! Example validation for common species
      character(len=32), parameter :: test_species(5) = &
         ['NO  ', 'SO2 ', 'CO  ', 'ISOP', 'NH3 ']
      integer :: i

      rc = cc_success

      do i = 1, size(test_species)
         call this%validate_single_species(trim(test_species(i)), container, &
            results, n_results, rc)
         if (rc /= cc_success) return
      end do

   end subroutine validate_species_mapping

   subroutine validate_single_species(this, species_name, container, &
      results, n_results, rc)
      class(EmissionConfigValidatorType), intent(inout) :: this
      character(len=*), intent(in) :: species_name
      type(StateManagerType), intent(inout) :: container
      type(ValidationResultType), intent(inout) :: results(:)
      integer, intent(inout) :: n_results
      integer, intent(out) :: rc

      type(ValidationResultType) :: result
      logical :: species_exists

      rc = cc_success
      this%n_species_validated = this%n_species_validated + 1

      ! Check if species exists in chemical mechanism
      call this%check_species_in_mechanism(species_name, container, species_exists, rc)
      if (rc /= cc_success) return

      if (.not. species_exists) then
         result%status = validation_error
         result%species_name = species_name
         write(result%message, '(A,A,A)') 'Species "', trim(species_name), &
            '" not found in chemical mechanism'

         n_results = n_results + 1
         results(n_results) = result
         this%n_errors = this%n_errors + 1

         if (this%strict_mode) then
            rc = error_invalid_config
            return
         end if
      end if

      ! TODO: Add more validations for this species
      ! - Scale factors
      ! - Units compatibility
      ! - Vertical distribution validity

   end subroutine validate_single_species

   subroutine check_species_in_mechanism(this, species_name, container, &
      species_exists, rc)
      class(EmissionConfigValidatorType), intent(in) :: this
      character(len=*), intent(in) :: species_name
      type(StateManagerType), intent(inout) :: container
      logical, intent(out) :: species_exists
      integer, intent(out) :: rc

      type(ChemStateType), pointer :: chem_state
      integer :: species_idx

      rc = cc_success
      species_exists = .false.

      if (.not. this%check_species_existence) then
         species_exists = .true.  ! Skip check if disabled
         return
      end if

      chem_state => container%get_chem_state_ptr()

      species_idx = chem_state%find_species(species_name)
      species_exists = (species_idx > 0)

      ! Reset rc since this is just a check
      rc = cc_success

   end subroutine check_species_in_mechanism

   subroutine validate_scale_factors(this, scale_factors, n_factors, &
      species_name, results, n_results, rc)
      class(EmissionConfigValidatorType), intent(inout) :: this
      real(fp), intent(in) :: scale_factors(:)
      integer, intent(in) :: n_factors
      character(len=*), intent(in) :: species_name
      type(ValidationResultType), intent(inout) :: results(:)
      integer, intent(inout) :: n_results
      integer, intent(out) :: rc

      type(ValidationResultType) :: result
      real(fp) :: total_scale

      rc = cc_success

      if (.not. this%check_scale_factors) return

      total_scale = sum(scale_factors(1:n_factors))

      if (this%require_mass_conservation) then
         if (abs(total_scale - 1.0_fp) > this%mass_conservation_tolerance) then
            result%status = validation_warning
            result%species_name = species_name
            write(result%message, '(A,A,A,F8.5,A)') 'Scale factors for "', &
               trim(species_name), '" sum to ', total_scale, &
               ' (expected 1.0 for mass conservation)'

            n_results = n_results + 1
            results(n_results) = result
            this%n_warnings = this%n_warnings + 1
         end if
      end if

      ! Check for negative scale factors
      if (any(scale_factors(1:n_factors) < 0.0_fp)) then
         result%status = validation_error
         result%species_name = species_name
         write(result%message, '(A,A,A)') 'Negative scale factors found for "', &
            trim(species_name), '"'

         n_results = n_results + 1
         results(n_results) = result
         this%n_errors = this%n_errors + 1

         if (this%strict_mode) then
            rc = error_invalid_config
            return
         end if
      end if

   end subroutine validate_scale_factors

   subroutine validate_emission_sources(this, results, n_results, rc)
      class(EmissionConfigValidatorType), intent(inout) :: this
      type(ValidationResultType), intent(inout) :: results(:)
      integer, intent(inout) :: n_results
      integer, intent(out) :: rc

      ! TODO: Validate that emission source files exist and are accessible
      rc = cc_success

   end subroutine validate_emission_sources

   subroutine validate_vertical_distributions(this, results, n_results, rc)
      class(EmissionConfigValidatorType), intent(inout) :: this
      type(ValidationResultType), intent(inout) :: results(:)
      integer, intent(inout) :: n_results
      integer, intent(out) :: rc

      ! TODO: Validate vertical distribution parameters
      rc = cc_success

   end subroutine validate_vertical_distributions

   subroutine validate_mass_conservation(this, results, n_results, rc)
      class(EmissionConfigValidatorType), intent(inout) :: this
      type(ValidationResultType), intent(inout) :: results(:)
      integer, intent(inout) :: n_results
      integer, intent(out) :: rc

      ! TODO: Check mass conservation across all mappings
      rc = cc_success

   end subroutine validate_mass_conservation

   subroutine reset_counters(this)
      class(EmissionConfigValidatorType), intent(inout) :: this

      this%n_warnings = 0
      this%n_errors = 0
      this%n_species_validated = 0

   end subroutine reset_counters

   subroutine get_validation_summary(this, summary)
      class(EmissionConfigValidatorType), intent(in) :: this
      character(len=*), intent(out) :: summary

      write(summary, '(A,I0,A,I0,A,I0,A)') &
         'Emission config validation complete: ', &
         this%n_species_validated, ' species validated, ', &
         this%n_warnings, ' warnings, ', &
         this%n_errors, ' errors'

   end subroutine get_validation_summary

   subroutine set_validation_mode(this, strict_mode, require_mass_conservation, &
      check_species_existence)
      class(EmissionConfigValidatorType), intent(inout) :: this
      logical, intent(in), optional :: strict_mode
      logical, intent(in), optional :: require_mass_conservation
      logical, intent(in), optional :: check_species_existence

      if (present(strict_mode)) this%strict_mode = strict_mode
      if (present(require_mass_conservation)) &
         this%require_mass_conservation = require_mass_conservation
      if (present(check_species_existence)) &
         this%check_species_existence = check_species_existence

   end subroutine set_validation_mode

end module emissionconfigvalidator_mod