parse_named_composition Subroutine

public subroutine parse_named_composition(text, species_names, nspecies, values, owner, normalize, require_sum_positive)

Systematically parses a composition string and maps values to species array indexes.

Splits key-value tokens (e.g., "H2:2.0,O2:1.0") separated by commas, matches name keys with the registered species, and populates the mass fraction array. Optionally normalizes the output array to sum to unity.

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: text

The composition input string to parse.

character(len=*), intent(in) :: species_names(:)
integer, intent(in) :: nspecies

Number of active species.

real(kind=rk), intent(out) :: values(:)
character(len=*), intent(in) :: owner

Name of the calling subsystem for error traceback.

logical, intent(in), optional :: normalize

Optional flag to normalize values to sum to 1.0 (default true).

logical, intent(in), optional :: require_sum_positive

Optional flag to mandate a non-zero sum (default true).


Source Code

   subroutine parse_named_composition(text, species_names, nspecies, values, owner, normalize, require_sum_positive)
      character(len=*), intent(in) :: text                   !< Composition string to parse.
      character(len=*), intent(in) :: species_names(:)       !< Array of active species names.
      integer, intent(in) :: nspecies                        !< Number of species.
      real(rk), intent(out) :: values(:)                     !< Target array to populate.
      character(len=*), intent(in) :: owner                  !< Traceback owner name.
      logical, intent(in), optional :: normalize              !< Whether to normalize results.
      logical, intent(in), optional :: require_sum_positive  !< Whether sum must be strictly positive.

      character(len=:), allocatable :: work !< Scalable workspace copy of the input string.
      character(len=:), allocatable :: token !< Single name-value pair segment (e.g. "CH4:1.0").
      character(len=:), allocatable :: name !< Parsed species name token.
      character(len=:), allocatable :: value_text !< Parsed numeric value text.
      integer :: pos !< Position index of comma separator.
      integer :: colon !< Position index of colon separator.
      integer :: idx !< Matched index of species in the registry.
      real(rk) :: val !< Parsed real representation of key value.
      real(rk) :: sum_y !< Cumulative sum of fractions.
      logical :: do_normalize !< Internal resolved normalization flag.
      logical :: need_positive !< Internal resolved positive requirement flag.

      if (size(values) < nspecies) call fatal_error(trim(owner), 'composition output vector is too small')
      values = zero
      if (nspecies <= 0) then
         if (len_trim(text) > 0) call fatal_error(trim(owner), 'composition was specified but no species are available')
         return
      end if

      do_normalize = .true.
      if (present(normalize)) do_normalize = normalize
      need_positive = .true.
      if (present(require_sum_positive)) need_positive = require_sum_positive

      work = trim(adjustl(text))
      do while (len_trim(work) > 0)
         pos = index(work, ',')
         if (pos > 0) then
            token = trim(adjustl(work(:pos-1)))
            work = trim(adjustl(work(pos+1:)))
         else
            token = trim(adjustl(work))
            work = ''
         end if

         if (len_trim(token) == 0) cycle
         colon = index(token, ':')
         if (colon <= 1 .or. colon >= len_trim(token)) then
            call fatal_error(trim(owner), 'bad composition token "'//trim(token)//'"; expected NAME:VALUE')
         end if

         name = trim(adjustl(token(:colon-1)))
         value_text = trim(adjustl(token(colon+1:)))
         read(value_text, *, err=100) val
         if (val < zero) call fatal_error(trim(owner), 'negative mass fraction for species '//trim(name))

         idx = species_index_of(species_names, nspecies, name)
         if (idx <= 0) then
            call fatal_error(trim(owner), 'composition species "'//trim(name)//'" is not in the active species list')
         end if
         values(idx) = values(idx) + val
         cycle
 100      call fatal_error(trim(owner), 'could not parse composition value in token "'//trim(token)//'"')
      end do

      sum_y = sum(values(1:nspecies))
      if (sum_y <= tiny_safe) then
         if (need_positive) call fatal_error(trim(owner), 'composition mass-fraction sum is zero')
      else if (do_normalize) then
         values(1:nspecies) = values(1:nspecies) / sum_y
      end if
   end subroutine parse_named_composition