!> TOML設定ファイルを `toml-f` で読み込み、`app_config` へ反映する。 module bem_app_config_parser use bem_kinds, only: dp, i32 use bem_types, only: bc_open, bc_reflect, bc_periodic, bc_redistributed_reflect use bem_app_config_types, only: & app_config, particle_species_spec, template_spec, mesh_part_config_path, & max_templates, max_particle_species, particle_bc_inherit, & particle_inflow_reservoir, species_from_defaults, species_config_path use bem_physics_config_types, only: & field_physics_config, panel_kernel_config, normalize_legacy_physics_config, derive_field_panel_config, & validate_active_physics_config, physics_config_ok use bem_app_config_authoring, only: & app_config_authoring, particle_authoring_spec, template_authoring_spec, mesh_group_authoring_spec, & domain_authoring_spec, field_boundary_authoring_spec, particle_boundary_authoring_spec, reservoir_authoring_spec, & init_app_config_authoring, ensure_authoring_particle_capacity, ensure_authoring_template_capacity, & ensure_authoring_group_capacity, normalize_high_level_config, lower_boundary_authoring use bem_string_utils, only: lower_ascii use bem_config_layout, only: normalize_config_layout use bem_config_toml, only: require_toml_success, get_toml_real, get_toml_int, get_toml_logical, & get_toml_string, get_toml_real_array, & get_toml_real_scalar_or_array3, get_toml_particle_boundary_mode, & get_toml_boundary_inflow_mode, stop_config_error use bem_injection_flux, only: compute_inflow_flux_from_drifting_maxwellian use bem_injection_geometry, only: compute_face_area_from_bounds ! Intel 2023 で同名の TOML constructor と host association が衝突しないよう型名を分ける。 use tomlf, only: config_toml_array => toml_array, config_toml_table => toml_table, & toml_error, toml_key, toml_parse, toml_stat, get_value, toml_len => len use, intrinsic :: ieee_arithmetic, only: ieee_is_finite implicit none private :: finalize_loaded_config private :: validate_simulation_config private :: validate_field_config private :: validate_particle_species_config private :: validate_surface_current_model_config private :: resolve_boundary_inflow_weight private :: resolve_photo_raycast_direction private :: stop_config_error interface !> 読み込み済み設定を正規化し、派生値を確定して全体整合性を検証する。 module subroutine finalize_loaded_config(cfg, authoring) type(app_config), intent(inout) :: cfg type(app_config_authoring), intent(in) :: authoring end subroutine finalize_loaded_config !> `sim.batch_duration` と `sim.batch_duration_step` の整合を検証して確定値を反映する。 module subroutine resolve_batch_duration(cfg) type(app_config), intent(inout) :: cfg end subroutine resolve_batch_duration !> `sim.e0` または `sim.e0_abs` + angle 指定を内部ベクトルへ正規化する。 module subroutine resolve_external_e_field(cfg) type(app_config), intent(inout) :: cfg end subroutine resolve_external_e_field !> box境界に結び付いた reservoir 流入の密度条件を検査し、目標 macro 粒子数から重みを導いて書き戻す。 module subroutine resolve_boundary_inflow_weight(cfg, species_idx) type(app_config), intent(inout) :: cfg integer, intent(in) :: species_idx end subroutine resolve_boundary_inflow_weight !> `photo_raycast` 粒子種の開口と放出条件を検査し、入射方向を正規化して書き戻す。 module subroutine resolve_photo_raycast_direction(cfg, species_idx) type(app_config), intent(inout) :: cfg integer, intent(in) :: species_idx end subroutine resolve_photo_raycast_direction module subroutine apply_periodic2_toml_table(table, authoring) type(config_toml_table), intent(inout) :: table type(app_config_authoring), intent(inout) :: authoring end subroutine apply_periodic2_toml_table module subroutine apply_domain_toml_table(table, domain) type(config_toml_table), intent(inout) :: table type(domain_authoring_spec), intent(inout) :: domain end subroutine apply_domain_toml_table module subroutine apply_field_boundary_toml_table(table, field) type(config_toml_table), intent(inout) :: table type(field_boundary_authoring_spec), intent(inout) :: field end subroutine apply_field_boundary_toml_table module subroutine apply_particle_boundary_toml_table(table, particles) type(config_toml_table), intent(inout) :: table type(particle_boundary_authoring_spec), intent(inout) :: particles end subroutine apply_particle_boundary_toml_table module subroutine apply_reservoir_toml_table(table, reservoir) type(config_toml_table), intent(inout) :: table type(reservoir_authoring_spec), intent(inout) :: reservoir end subroutine apply_reservoir_toml_table module subroutine apply_sim_toml_table(cfg, table) type(app_config), intent(inout) :: cfg type(config_toml_table), intent(inout) :: table end subroutine apply_sim_toml_table module subroutine apply_output_toml_table(cfg, table) type(app_config), intent(inout) :: cfg type(config_toml_table), intent(inout) :: table end subroutine apply_output_toml_table module subroutine ensure_particle_species_capacity(cfg, required_size) type(app_config), intent(inout) :: cfg integer, intent(in) :: required_size end subroutine ensure_particle_species_capacity module subroutine apply_particles_toml_table(cfg, table, authoring) type(app_config), intent(inout) :: cfg type(config_toml_table), intent(inout) :: table type(app_config_authoring), intent(inout) :: authoring end subroutine apply_particles_toml_table module subroutine read_particle_species_array(cfg, table, key, authoring) type(app_config), intent(inout) :: cfg type(config_toml_table), intent(inout) :: table type(toml_key), intent(in) :: key type(app_config_authoring), intent(inout) :: authoring end subroutine read_particle_species_array module subroutine apply_particles_species_toml_table(spec, table, auth, species_path) character(len=*), intent(in) :: species_path type(particle_species_spec), intent(inout) :: spec type(config_toml_table), intent(inout) :: table type(particle_authoring_spec), intent(inout) :: auth end subroutine apply_particles_species_toml_table module subroutine apply_species_boundary_toml_table(spec, table, species_path) character(len=*), intent(in) :: species_path type(particle_species_spec), intent(inout) :: spec type(config_toml_table), intent(inout) :: table end subroutine apply_species_boundary_toml_table module subroutine apply_species_boundary_inflow_toml_table(spec, table, species_path) character(len=*), intent(in) :: species_path type(particle_species_spec), intent(inout) :: spec type(config_toml_table), intent(inout) :: table end subroutine apply_species_boundary_inflow_toml_table module subroutine ensure_template_capacity(cfg, required_size) type(app_config), intent(inout) :: cfg integer, intent(in) :: required_size end subroutine ensure_template_capacity module subroutine apply_mesh_toml_table(cfg, table, authoring) type(app_config), intent(inout) :: cfg type(config_toml_table), intent(inout) :: table type(app_config_authoring), intent(inout) :: authoring end subroutine apply_mesh_toml_table module subroutine read_mesh_groups_table(table, key, authoring) type(config_toml_table), intent(inout) :: table type(toml_key), intent(in) :: key type(app_config_authoring), intent(inout) :: authoring end subroutine read_mesh_groups_table module subroutine apply_mesh_group_toml_table(group, table) type(mesh_group_authoring_spec), intent(inout) :: group type(config_toml_table), intent(inout) :: table end subroutine apply_mesh_group_toml_table module subroutine read_template_array(cfg, table, key, authoring) type(app_config), intent(inout) :: cfg type(config_toml_table), intent(inout) :: table type(toml_key), intent(in) :: key type(app_config_authoring), intent(inout) :: authoring end subroutine read_template_array module subroutine apply_template_toml_table(spec, table, auth, part_idx) integer, intent(in) :: part_idx type(template_spec), intent(inout) :: spec type(config_toml_table), intent(inout) :: table type(template_authoring_spec), intent(inout) :: auth end subroutine apply_template_toml_table module subroutine apply_surface_current_model_toml_table(cfg, table) type(app_config), intent(inout) :: cfg type(config_toml_table), intent(inout) :: table end subroutine apply_surface_current_model_toml_table module subroutine validate_simulation_config(cfg) type(app_config), intent(inout) :: cfg end subroutine validate_simulation_config module subroutine validate_field_config(cfg) type(app_config), intent(inout) :: cfg end subroutine validate_field_config module subroutine validate_particle_species_config(cfg) type(app_config), intent(inout) :: cfg end subroutine validate_particle_species_config module subroutine validate_surface_current_model_config(cfg, periodic2_split_explicit) type(app_config), intent(in) :: cfg logical, intent(in) :: periodic2_split_explicit end subroutine validate_surface_current_model_config module subroutine apply_physics_authoring(cfg, authoring) type(app_config), intent(inout) :: cfg type(app_config_authoring), intent(in) :: authoring end subroutine apply_physics_authoring end interface contains !> `.toml` 拡張子の設定ファイルを読み込み、既存値へ上書き適用する。 !! @param[in] path 読み込む設定ファイルパス(`.toml` 必須)。 !! @param[inout] cfg 読み込み結果で上書きするアプリ設定。 subroutine load_app_config(path, cfg) character(len=*), intent(in) :: path type(app_config), intent(inout) :: cfg if (.not. has_suffix(lower_ascii(trim(path)), '.toml')) then error stop 'Only TOML config is supported. Please pass a .toml file.' end if call load_toml_config(path, cfg) end subroutine load_app_config !> 文字列が指定した接尾辞で終わるかを判定する。 pure logical function has_suffix(s, suffix) character(len=*), intent(in) :: s character(len=*), intent(in) :: suffix integer :: ls, lf ls = len_trim(s) lf = len_trim(suffix) if (lf > ls) then has_suffix = .false. else has_suffix = (s(ls - lf + 1:ls) == suffix(1:lf)) end if end function has_suffix !> TOML 文書を `toml-f` で解釈して設定へ反映する。 !! 現在は `sim` / `mesh` / `output` / `[[mesh.parts]]` / `[[particles.species]]` を扱う。 !! @param[in] path 読み込むTOMLファイルパス。 !! @param[inout] cfg 読み込み結果で更新するアプリ設定。 subroutine load_toml_config(path, cfg) character(len=*), intent(in) :: path type(app_config), intent(inout) :: cfg integer :: u, ios type(config_toml_table), allocatable :: document type(toml_error), allocatable :: parse_error type(app_config_authoring) :: authoring if (.not. allocated(cfg%mesh_parts)) then allocate (cfg%mesh_parts(max_templates)) cfg%n_mesh_parts = 0_i32 end if if (.not. allocated(cfg%particle_species)) then allocate (cfg%particle_species(max_particle_species)) cfg%particle_species = particle_species_spec() cfg%n_particle_species = 0_i32 end if call init_app_config_authoring(authoring, size(cfg%mesh_parts), size(cfg%particle_species)) open (newunit=u, file=trim(path), status='old', action='read', iostat=ios) if (ios /= 0) error stop 'Could not open TOML file.' call toml_parse(document, u, parse_error) close (u) if (allocated(parse_error)) then error stop 'Failed to parse TOML config: '//parse_error%message end if if (.not. allocated(document)) error stop 'Failed to parse TOML config.' cfg%n_mesh_parts = 0_i32 call normalize_config_layout(document) call apply_toml_document(cfg, document, authoring) call document%destroy call finalize_loaded_config(cfg, authoring) end subroutine load_toml_config !> `toml-f` のルートテーブルから既知セクションを読み込む。 subroutine apply_toml_document(cfg, document, authoring) type(app_config), intent(inout) :: cfg type(config_toml_table), intent(inout) :: document type(app_config_authoring), intent(inout) :: authoring type(toml_key), allocatable :: keys(:) type(config_toml_table), pointer :: section integer :: ikey, stat character(len=:), allocatable :: key_name call document%get_keys(keys) do ikey = 1, size(keys) key_name = lower_ascii(trim(keys(ikey)%key)) nullify (section) call get_value(document, keys(ikey), section, requested=.false., stat=stat) call require_toml_success(stat, '['//trim(keys(ikey)%key)//']') select case (trim(key_name)) case ('sim') if (.not. associated(section)) error stop 'TOML section [run], [particles.tracking], or [fields] must be a table.' call apply_sim_toml_table(cfg, section) case ('domain') if (.not. associated(section)) error stop 'TOML section [domain] must be a table.' call apply_domain_toml_table(section, authoring%domain) case ('field_boundary') if (.not. associated(section)) error stop 'TOML section [fields] must be a table.' call apply_field_boundary_toml_table(section, authoring%field_boundary) case ('particle_boundary') if (.not. associated(section)) error stop 'TOML section [particles.boundary] must be a table.' call apply_particle_boundary_toml_table(section, authoring%particle_boundary) case ('reservoir') if (.not. associated(section)) error stop 'TOML section [particles.reservoir] must be a table.' call apply_reservoir_toml_table(section, authoring%reservoir) case ('surface_current_model') if (.not. associated(section)) error stop 'TOML section [sheath] must be a table.' call apply_surface_current_model_toml_table(cfg, section) case ('particles') if (.not. associated(section)) error stop 'TOML section [particles] must be a table.' call apply_particles_toml_table(cfg, section, authoring) case ('periodic2') if (.not. associated(section)) error stop 'TOML section [fields.periodic] must be a table.' call apply_periodic2_toml_table(section, authoring) case ('mesh') if (.not. associated(section)) error stop 'TOML section [mesh] must be a table.' call apply_mesh_toml_table(cfg, section, authoring) case ('output') if (.not. associated(section)) error stop 'TOML section [output] must be a table.' call apply_output_toml_table(cfg, section) case default error stop 'Unknown TOML section or top-level key: '//trim(keys(ikey)%key) end select end do end subroutine apply_toml_document !> 現在のメッシュ入力設定が指定された表面モデルを使うかを返す。 logical function config_uses_surface_model(cfg, surface_model) result(uses_surface_model) type(app_config), intent(in) :: cfg character(len=*), intent(in) :: surface_model integer :: i uses_surface_model = .false. do i = 1, cfg%n_mesh_parts if (.not. cfg%mesh_parts(i)%enabled) cycle if (trim(cfg%mesh_parts(i)%surface_model) == surface_model) then uses_surface_model = .true. return end if end do end function config_uses_surface_model end module bem_app_config_parser