module subroutine parse_fragmentation_section(unit, config, error)
integer, intent(in) :: unit
type(mqc_config_t), intent(inout) :: config
type(error_t), intent(out) :: error
character(len=MAX_LINE_LEN) :: line, key, value
integer :: io_stat, eq_pos
logical :: in_cutoffs
in_cutoffs = .false.
do
read (unit, '(A)', iostat=io_stat) line
if (io_stat /= 0) then
call error%set(ERROR_IO, "Unexpected end of file in %fragmentation section")
return
end if
line = adjustl(line)
if (len_trim(line) == 0) cycle
if (line(1:1) == '#' .or. line(1:1) == '!') cycle
if (trim(strip_comment(line)) == 'end') then
if (in_cutoffs) then
! Validate cutoffs before leaving the cutoffs section
call validate_cutoffs(config, error)
if (error%has_error()) then
call error%add_context("mqc_config_parser:parse_fragmentation_section")
return
end if
in_cutoffs = .false.
cycle
else
exit
end if
end if
if (trim(line) == '%cutoffs') then
in_cutoffs = .true.
cycle
end if
eq_pos = index(line, '=')
if (eq_pos == 0) cycle
key = adjustl(line(1:eq_pos - 1))
value = adjustl(line(eq_pos + 1:))
if (in_cutoffs) then
! Parse cutoffs: numeric keys like "2", "3", "4", etc.
! representing n-mer level (2=dimer, 3=trimer, etc.)
block
integer :: nmer_level
real(dp) :: cutoff_value
! Try to read the key as an integer (n-mer level)
read (key, *, iostat=io_stat) nmer_level
if (io_stat /= 0) then
call error%set(ERROR_PARSE, "Invalid n-mer level in cutoffs (expected integer): "//trim(key))
return
end if
! Validate n-mer level
if (nmer_level < 2) then
call error%set(ERROR_PARSE, "N-mer level must be >= 2 in cutoffs")
return
end if
if (nmer_level > 10) then
call error%set(ERROR_PARSE, "N-mer level too large in cutoffs (max 10 for decamer)")
return
end if
! Read the cutoff value
read (value, *, iostat=io_stat) cutoff_value
if (io_stat /= 0) then
call error%set(ERROR_PARSE, "Invalid cutoff value: "//trim(value))
return
end if
! Allocate array if not yet allocated (up to decamer = 10)
if (.not. allocated(config%fragment_cutoffs)) then
allocate (config%fragment_cutoffs(10))
config%fragment_cutoffs = -1.0_dp ! Initialize with sentinel value
end if
! Store the cutoff value at the appropriate index
config%fragment_cutoffs(nmer_level) = cutoff_value
end block
else
select case (trim(key))
case ('method')
config%frag_method = trim(value)
case ('level')
read (value, *, iostat=io_stat) config%frag_level
if (io_stat == 0) then
if (config%frag_level < 0) then
call error%set(ERROR_VALIDATION, "Fragmentation level must be >= 0 (0 = unfragmented)")
return
end if
if (config%frag_level > 10) then
call error%set(ERROR_VALIDATION, &
"Fragmentation level must be <= 10 (decamers). Higher levels not supported.")
return
end if
end if
case ('allow_overlapping_fragments')
config%allow_overlapping_fragments = (trim(value) == 'true')
case ('max_intersection_level')
read (value, *, iostat=io_stat) config%max_intersection_level
if (io_stat == 0) then
if (config%max_intersection_level < 1) then
call error%set(ERROR_VALIDATION, "max_intersection_level must be >= 1")
return
end if
if (config%max_intersection_level > 10) then
call error%set(ERROR_VALIDATION, &
"max_intersection_level must be <= 10 (decamers). Higher levels not supported.")
return
end if
end if
case ('embedding')
config%embedding = trim(value)
case ('cutoff_method')
config%cutoff_method = trim(value)
case ('distance_metric')
config%distance_metric = trim(value)
case default
call error%set(ERROR_PARSE, "Unknown key in %fragmentation section: "//trim(key))
return
end select
end if
end do
end subroutine parse_fragmentation_section