module read_file use constants, only: dp use, intrinsic :: ieee_arithmetic, only: ieee_value, ieee_quiet_nan use, intrinsic :: ieee_arithmetic, only: ieee_is_nan implicit none private public :: read_namelist character(len=100), public, protected :: field_file character(len=20), public, protected :: field_type real(dp), public, protected :: M_pol real(dp), public, protected :: N_tor real(dp), dimension(:), allocatable, public, protected :: s_tor real(dp), public, protected :: sign_sqrtg integer, public, protected :: max_n_fieldlines logical, public, protected :: should_calc_shaing_callen integer, public, protected :: n_eta logical, public, protected :: unsafe_mode real(dp), public, protected :: s_tor_min real(dp), public, protected :: s_tor_max integer, public, protected :: n_s_tor namelist /rabe_config/ & field_file, & field_type, & M_pol, & N_tor, & s_tor, & s_tor_min, & s_tor_max, & n_s_tor, & sign_sqrtg, & max_n_fieldlines, & should_calc_shaing_callen, & n_eta, & unsafe_mode contains subroutine read_namelist(filename) use utils, only: linspace implicit none character(len=*), intent(in) :: filename integer :: ios, unit logical :: file_exists real(dp), dimension(:), allocatable :: s_tor_temp integer, parameter :: n_stor_max = 1000 integer :: n_list real(dp) :: nan_value logical :: has_list, has_range inquire (file=filename, exist=file_exists) if (.not. file_exists) then print *, "Error in read_namelist: file not found: ", filename error stop end if open (newunit=unit, file=filename, status="old", action="read", iostat=ios) if (ios /= 0) then print *, "Error in read_namelist: cannot open file: ", filename error stop end if nan_value = ieee_value(nan_value, ieee_quiet_nan) ! Default values field_type = 'vmec_nc' unsafe_mode = .false. should_calc_shaing_callen = .false. n_eta = 100 s_tor_min = nan_value s_tor_max = nan_value n_s_tor = 0 if (allocated(s_tor)) deallocate (s_tor) allocate (s_tor(n_stor_max)) s_tor = nan_value read (unit, nml=rabe_config, iostat=ios) if (ios /= 0) then print *, "Error in read_namelist:" print *, "iostat = ", ios error stop end if close (unit) n_list = count(.not. ieee_is_nan(s_tor)) has_list = n_list > 0 has_range = (.not. ieee_is_nan(s_tor_min)) .and. & (.not. ieee_is_nan(s_tor_max)) .and. & (n_s_tor > 0) if (has_list .and. has_range) then print *, "Error in read_namelist: both s_tor list and s_tor range " & //"(s_tor_min, s_tor_max, n_s_tor) are specified. Use one or the other." error stop end if if (.not. has_list .and. .not. has_range) then print *, "Error in read_namelist: no s_tor values provided. " & //"Set either s_tor or (s_tor_min, s_tor_max, n_s_tor)." error stop end if if (has_range) then deallocate (s_tor) allocate (s_tor(n_s_tor)) call linspace(s_tor_min, s_tor_max, n_s_tor, s_tor) else if (n_list >= n_stor_max) then print *, "Error in read_namelist: too many s_tor values ", & "provided in namelist" error stop end if if (allocated(s_tor_temp)) deallocate (s_tor_temp) allocate (s_tor_temp(n_list)) s_tor_temp = pack(s_tor,.not. ieee_is_nan(s_tor)) deallocate (s_tor) allocate (s_tor(n_list)) s_tor = s_tor_temp deallocate (s_tor_temp) end if call check_if_valid_namelist() end subroutine read_namelist subroutine check_if_valid_namelist() use make_fieldline, only: is_not_integer use utils, only: not_same real(dp), parameter :: tol = 1e-15 logical :: is_valid is_valid = .true. if (len(trim(field_file)) == 0) then print *, "field_file is empty!" is_valid = .false. end if if (len(trim(field_type)) == 0 .or. & (trim(field_type) /= 'vmec_nc' .and. & trim(field_type) /= 'booz_xform' .and. & trim(field_type) /= 'chartmap')) then print *, "field_type must be 'vmec_nc', 'booz_xform', or 'chartmap'" is_valid = .false. end if if (ieee_is_nan(M_pol)) then print *, "M_pol is NaN!" is_valid = .false. end if if (ieee_is_nan(N_tor)) then print *, "N_tor is NaN!" is_valid = .false. end if if (any(ieee_is_nan(s_tor))) then print *, "s_tor is NaN!" is_valid = .false. end if if (ieee_is_nan(sign_sqrtg)) then print *, "sign_sqrtg is NaN!" is_valid = .false. end if if (is_not_integer(M_pol, tol)) then print *, "M_pol must be integer" is_valid = .false. end if if (is_not_integer(N_tor, tol)) then print *, "N_tor must be integer" is_valid = .false. end if if (not_same(sign_sqrtg, 1.0_dp, reltol_in=0.0_dp, abstol_in=tol) .and. & not_same(sign_sqrtg, -1.0_dp, reltol_in=0.0_dp, abstol_in=tol)) then print *, "sign_sqrtg must be +-1" is_valid = .false. end if if (any(s_tor <= 0.0_dp) .or. any(s_tor >= 1.0_dp)) then print *, "s_tor must be in ]0.0, 1.0[" is_valid = .false. end if if (n_s_tor > 0) then if (s_tor_min >= s_tor_max) then print *, "s_tor_min must be less than s_tor_max" is_valid = .false. end if if (n_s_tor < 2) then print *, "n_s_tor must be at least 2" is_valid = .false. end if end if if (max_n_fieldlines <= 1) then print *, "max_n_fieldlines must be bigger than 1" is_valid = .false. end if if (should_calc_shaing_callen .and. n_eta <= 3) then print *, "n_eta must be bigger than 3" end if if (.not. is_valid) error stop end subroutine check_if_valid_namelist end module read_file