subroutine write_mbe_breakdown_json_impl(data)
!! Write detailed MBE energy breakdown to JSON file
type(json_output_data_t), intent(in) :: data
type(json_core) :: json
type(json_value), pointer :: root, main_obj, levels_arr, level_obj, frags_arr, frag_obj
type(json_value), pointer :: dipole_obj
integer(int64) :: i, count_by_level
integer :: fragment_size, j, frag_level, iunit, io_stat
integer, allocatable :: indices(:)
character(len=32) :: level_name
character(len=256) :: output_file, basename
output_file = get_output_json_filename()
basename = get_basename()
if (data%max_level > 10) then
call logger%warning("Fragment levels exceed decamers (10-mers). JSON will use generic N-mers notation.")
end if
call json%initialize(real_format=JSON_REAL_FORMAT)
call json%create_object(root, '')
call json%create_object(main_obj, trim(basename))
call json%add(root, main_obj)
call json%add(main_obj, 'total_energy', data%total_energy)
! Build levels array
call json%create_array(levels_arr, 'levels')
call json%add(main_obj, levels_arr)
do frag_level = 1, data%max_level
count_by_level = 0_int64
do i = 1_int64, data%fragment_count
fragment_size = count(data%polymers(i, :) > 0)
if (fragment_size == frag_level) count_by_level = count_by_level + 1_int64
end do
if (count_by_level > 0_int64) then
call json%create_object(level_obj, '')
call json%add(levels_arr, level_obj)
level_name = get_frag_level_name(frag_level)
call json%add(level_obj, 'frag_level', frag_level)
call json%add(level_obj, 'name', trim(level_name))
call json%add(level_obj, 'count', int(count_by_level))
if (allocated(data%sum_by_level)) then
call json%add(level_obj, 'total_energy', data%sum_by_level(frag_level))
end if
call json%create_array(frags_arr, 'fragments')
call json%add(level_obj, frags_arr)
do i = 1_int64, data%fragment_count
fragment_size = count(data%polymers(i, :) > 0)
if (fragment_size == frag_level) then
call json%create_object(frag_obj, '')
call json%add(frags_arr, frag_obj)
allocate (indices(fragment_size))
indices = data%polymers(i, 1:fragment_size)
call json%add(frag_obj, 'indices', indices)
deallocate (indices)
if (allocated(data%fragment_energies)) then
call json%add(frag_obj, 'energy', data%fragment_energies(i))
end if
if (allocated(data%fragment_distances)) then
call json%add(frag_obj, 'distance', data%fragment_distances(i))
end if
if (frag_level > 1 .and. allocated(data%delta_energies)) then
call json%add(frag_obj, 'delta_energy', data%delta_energies(i))
end if
end if
end do
end if
end do
! Add dipole if computed
if (data%has_dipole .and. allocated(data%dipole)) then
call json%create_object(dipole_obj, 'dipole')
call json%add(main_obj, dipole_obj)
call json%add(dipole_obj, 'x', data%dipole(1))
call json%add(dipole_obj, 'y', data%dipole(2))
call json%add(dipole_obj, 'z', data%dipole(3))
call json%add(dipole_obj, 'magnitude_debye', norm2(data%dipole)*AU_TO_DEBYE)
end if
if (data%has_gradient .and. allocated(data%gradient)) then
call json%add(main_obj, 'gradient_norm', sqrt(sum(data%gradient**2)))
end if
if (data%has_hessian .and. allocated(data%hessian)) then
call json%add(main_obj, 'hessian_frobenius_norm', sqrt(sum(data%hessian**2)))
end if
! Write to file
call logger%info("Writing JSON output to "//trim(output_file))
open (newunit=iunit, file=trim(output_file), status='replace', action='write', iostat=io_stat)
if (io_stat /= 0) then
call logger%error("Failed to open "//trim(output_file)//" for writing")
call json%destroy(root)
return
end if
call json%print(root, iunit)
close (iunit)
call json%destroy(root)
call logger%info("JSON output written successfully to "//trim(output_file))
end subroutine write_mbe_breakdown_json_impl