!> 実行サマリと再構築用メタデータの出力。 submodule(bem_output_writer) bem_output_writer_summary use bem_types, only: surface_model_dielectric use bem_charge_ledger, only: finite_charge_sum use bem_checkpoint_contract, only: checkpoint_schema_version_current use bem_field_solver, only: & field_solver_fmm_expansion_order, & resolve_field_solver_mode, & resolve_field_solver_tree_params use bem_external_boundary_contract, only: & external_boundary_contract_type, & external_boundary_ok, & external_inflow_none, & external_inflow_scalar_barrier, & external_open_escape, & external_open_potential_barrier, & resolve_external_boundary_contract use bem_mesh_identity, only: mesh_fingerprint use bem_physics_config_types, only: field_physics_config, panel_kernel_config, derive_field_panel_config use bem_surface_current_model, only: surface_current_model_result_type, evaluate_surface_current_model use bem_version, only: beach_build_id, beach_source_commit, beach_version, beach_version_mode use bem_string_utils, only: lower_ascii implicit none contains !> 実行統計を `summary.txt` に書き出す。 !! @param[in] out_dir 出力先ディレクトリ。 !! @param[in] mesh メッシュ情報(要素数を書き出す)。 !! @param[in] stats 実行統計。 module procedure write_summary_file type(external_boundary_contract_type) :: resolved_boundary type(surface_current_model_result_type) :: current_model type(field_physics_config) :: field_config type(panel_kernel_config) :: panel_config character(len=1024) :: summary_path character(len=256) :: boundary_message character(len=16) :: resolved_field_solver integer :: u, ios integer(i32) :: world_size, boundary_status, resolved_tree_leaf_max real(dp) :: resolved_tree_theta call resolve_external_boundary_contract( & cfg%sim%reservoir_potential_model, cfg%sim%open_boundary_model, & resolved_boundary, boundary_status, boundary_message & ) if (boundary_status /= external_boundary_ok) then error stop 'write_summary_file: invalid local boundary contract: '//trim(boundary_message) end if call evaluate_surface_current_model(cfg, current_model) call derive_field_panel_config(cfg%sim, field_config, panel_config) call resolve_field_solver_tree_params( & mesh%nelem, cfg%sim, resolved_tree_theta, resolved_tree_leaf_max & ) resolved_field_solver = resolve_field_solver_mode(mesh%nelem, cfg%sim) summary_path = trim(out_dir)//'/summary.txt' open (newunit=u, file=trim(summary_path), status='replace', action='write', iostat=ios) if (ios /= 0) error stop 'Failed to open summary file.' world_size = 1_i32 if (present(mpi_world_size)) world_size = max(1_i32, mpi_world_size) write (u, '(a,i0)') 'checkpoint_schema_version=', checkpoint_schema_version_current write (u, '(a)') 'build_info_schema_version=1' write (u, '(a,a)') 'build_version=', beach_version write (u, '(a,a)') 'build_version_mode=', beach_version_mode write (u, '(a,a)') 'build_source_commit=', beach_source_commit write (u, '(a,a)') 'build_id=', beach_build_id write (u, '(a,a)') 'mesh_fingerprint=', mesh_fingerprint(mesh) write (u, '(a,i0)') 'mesh_nelem=', mesh%nelem write (u, '(a,i0)') 'mesh_count=', max(1_i32, maxval(mesh%elem_mesh_id)) write (u, '(a,i0)') 'mpi_world_size=', world_size write (u, '(a,i0)') 'processed_particles=', stats%processed_particles write (u, '(a,i0)') 'absorbed=', stats%absorbed write (u, '(a,i0)') 'escaped=', stats%escaped write (u, '(a,i0)') 'batches=', stats%batches write (u, '(a,i0)') 'checkpoint_stride=', cfg%checkpoint_stride write (u, '(a,i0)') 'escaped_boundary=', stats%escaped_boundary write (u, '(a,i0)') 'survived_max_step=', stats%survived_max_step write (u, '(a,i0)') 'multiple_box_events_retry_attempted=', stats%multiple_box_events_retry_attempted write (u, '(a,i0)') 'multiple_box_events_retry_resolved=', stats%multiple_box_events_retry_resolved write (u, '(a,i0)') 'multiple_box_events_soft_discarded=', stats%multiple_box_events_soft_discarded write (u, '(a,es24.16)') 'multiple_box_events_soft_discard_fraction=', soft_discard_fraction(stats) write (u, '(a,es24.16)') 'multiple_box_events_soft_discarded_abs_charge_C=', & stats%multiple_box_events_soft_discarded_abs_charge write (u, '(a,es24.16)') 'last_rel_change=', stats%last_rel_change write (u, '(a,es24.16)') 'simulated_time_s=', stats%simulated_time write (u, '(a,i0)') 'adaptive_nonzero_mode_rejected_trials=', & stats%adaptive_nonzero_mode_rejected_trials write (u, '(a,es24.16)') 'adaptive_nonzero_mode_last_batch_duration_s=', & stats%adaptive_nonzero_mode_last_batch_duration write (u, '(a,es24.16)') 'adaptive_nonzero_mode_last_potential_step_V=', & stats%adaptive_nonzero_mode_last_potential_step write (u, '(a,i0)') 'adaptive_nonzero_mode_omp_threads=', & stats%adaptive_nonzero_mode_omp_threads write (u, '(a,l1)') 'matching_plane_state_valid=', stats%matching_plane_state_valid write (u, '(a,es24.16)') 'matching_plane_displacement_C_m2=', stats%matching_plane_displacement_c_m2 write (u, '(a,es24.16)') 'matching_plane_phi_V=', stats%matching_plane_phi_v write (u, '(a,es24.16)') 'matching_plane_electron_inward_flux_m2_s=', stats%matching_plane_response(2) write (u, '(a,es24.16)') 'matching_plane_ion_inward_flux_m2_s=', stats%matching_plane_response(3) write (u, '(a,es24.16)') 'matching_plane_electron_access_potential_V=', stats%matching_plane_response(4) write (u, '(a,es24.16)') 'matching_plane_ion_access_potential_V=', stats%matching_plane_response(5) write (u, '(a,es24.16)') 'matching_plane_photoelectron_barrier_potential_V=', & stats%matching_plane_response(6) write (u, '(a,es24.16)') 'matching_plane_photoelectron_outward_flux_m2_s=', & stats%matching_plane_feedback(1) write (u, '(a,es24.16)') 'matching_plane_photoelectron_mean_normal_energy_eV=', & stats%matching_plane_feedback(2) write (u, '(a,es24.16)') 'matching_plane_electron_outward_flux_m2_s=', & stats%matching_plane_feedback(3) write (u, '(a,es24.16)') 'matching_plane_ion_outward_flux_m2_s=', & stats%matching_plane_feedback(4) write (u, '(a,es24.16)') 'matching_plane_photoelectron_return_flux_m2_s=', & stats%matching_plane_photoelectron_return_flux_m2_s write (u, '(a,es24.16)') 'matching_plane_photoelectron_escape_flux_m2_s=', & stats%matching_plane_photoelectron_escape_flux_m2_s write (u, '(a,i0)') 'matching_plane_iterations=', stats%matching_plane_iterations write (u, '(a,es24.16)') 'matching_plane_residual=', stats%matching_plane_residual write (u, '(a)') 'particle_time_centering=same_time_midpoint_boris' write (u, '(a,a)') 'field_backend=', trim(field_config%backend) write (u, '(a,a)') 'field_normalization=', trim(field_config%normalization) write (u, '(a)') 'field_source_model=triangle_p0' write (u, '(a,a)') 'field_kernel_id=', trim(panel_config%kernel_id) write (u, '(a)') 'field_reconstruction_schema_version=2' write (u, '(a,a)') 'field_reconstruction_resolved_field_solver=', trim(resolved_field_solver) write (u, '(a,i0)') 'field_reconstruction_fmm_expansion_order=', field_solver_fmm_expansion_order write (u, '(a,a)') 'field_reconstruction_field_bc_mode=', trim(cfg%sim%field_bc_mode) write (u, '(a,es24.16)') 'field_reconstruction_tree_theta=', resolved_tree_theta write (u, '(a,i0)') 'field_reconstruction_tree_leaf_max=', resolved_tree_leaf_max write (u, '(a,3(1x,es24.16))') 'field_reconstruction_e0_V_m=', cfg%sim%e0 write (u, '(a,l1)') 'field_reconstruction_use_box=', cfg%sim%use_box write (u, '(a,3(1x,es24.16))') 'field_reconstruction_box_min_m=', cfg%sim%box_min write (u, '(a,3(1x,es24.16))') 'field_reconstruction_box_max_m=', cfg%sim%box_max write (u, '(a,3(1x,i0))') 'field_reconstruction_boundary_low=', cfg%sim%bc_low write (u, '(a,3(1x,i0))') 'field_reconstruction_boundary_high=', cfg%sim%bc_high write (u, '(a,i0)') 'field_reconstruction_periodic_image_layers=', cfg%sim%field_periodic_image_layers write (u, '(a,a)') 'field_reconstruction_periodic_far_correction=', & trim(cfg%sim%field_periodic_far_correction) write (u, '(a,a)') 'field_reconstruction_periodic_nonzero_mode_backend=', & trim(cfg%periodic2%nonzero_mode_backend) write (u, '(a,a)') 'field_reconstruction_periodic_zero_mode_policy=', & trim(cfg%periodic2%zero_mode_policy) write (u, '(a,a)') 'field_reconstruction_periodic_lower_boundary_model=', & trim(cfg%periodic2%lower_boundary_model) write (u, '(a,i0)') 'field_reconstruction_periodic_reference_mode_layers=', & cfg%periodic2%reference_mode_layers write (u, '(a,i0)') 'field_reconstruction_periodic_panel_quadrature_order=', & cfg%periodic2%panel_quadrature_order write (u, '(a,es24.16)') 'field_reconstruction_periodic_ewald_alpha=', cfg%sim%field_periodic_ewald_alpha write (u, '(a,i0)') 'field_reconstruction_periodic_ewald_layers=', cfg%sim%field_periodic_ewald_layers write (u, '(a,a)') 'field_reconstruction_periodic_cache_dir=', trim(cfg%sim%field_periodic_cache_dir) write (u, '(a,es24.16)') 'field_reconstruction_periodic_generation_tolerance=', & cfg%sim%field_periodic_generation_tolerance write (u, '(a,a)') 'periodic2_nonzero_mode_backend=', trim(cfg%periodic2%nonzero_mode_backend) write (u, '(a,a)') 'periodic2_zero_mode_policy=', trim(cfg%periodic2%zero_mode_policy) write (u, '(a,a)') 'periodic2_lower_boundary_model=', trim(cfg%periodic2%lower_boundary_model) write (u, '(a,es24.16)') 'periodic2_max_nonzero_mode_potential_step_V=', & cfg%periodic2%max_nonzero_mode_potential_step write (u, '(a,a)') 'periodic2_cache_dir=', trim(cfg%sim%field_periodic_cache_dir) write (u, '(a,es24.16)') 'periodic2_generation_tolerance=', & cfg%sim%field_periodic_generation_tolerance write (u, '(a,a)') 'reservoir_inflow_map=', trim(external_inflow_map_name(resolved_boundary%inflow_map)) write (u, '(a,a)') 'particle_ordinary_open_model=', & trim(external_open_model_name(resolved_boundary%ordinary_open_model)) write (u, '(a,a)') 'surface_current_model=', trim(current_model%model) if (current_model%active) then write (u, '(a,a)') 'surface_current_model_kinetic_contract=', trim(current_model%kinetic_contract) if (trim(current_model%model) == 'matching_plane_quasistatic') then write (u, '(a,a)') 'surface_current_model_response_backend=', & trim(lower_ascii(cfg%surface_current%response_backend)) write (u, '(a,l1)') 'surface_current_model_implicit_zero_mode=', & cfg%surface_current%implicit_zero_mode select case (trim(lower_ascii(cfg%surface_current%response_backend))) case ('table') write (u, '(a,a)') 'surface_current_model_response_table_path=', & trim(cfg%surface_current%response_table_path) case ('zhao_online') write (u, '(a)') 'surface_current_model_response_contract=matching_plane_zhao_online_v1' write (u, '(a,a)') 'surface_current_model_zhao_branch=', & trim(lower_ascii(cfg%surface_current%zhao_branch)) write (u, '(a,a)') 'surface_current_model_zhao_root_selection=', & trim(lower_ascii(cfg%surface_current%zhao_root_selection)) write (u, '(a)') & 'surface_current_model_outer_solver=charge_driven_finite_h_sagdeev' write (u, '(a)') & 'surface_current_model_photoelectron_closure=moment_matched_half_maxwellian' write (u, '(a)') & 'surface_current_model_ambient_outward_feedback=transparent' if (trim(lower_ascii(cfg%surface_current%zhao_root_selection)) == 'continuation') then write (u, '(a)') & 'surface_current_model_outer_solver_state=accepted_endpoint_continuation_v2' else write (u, '(a)') 'surface_current_model_outer_solver_state=stateless' end if case default error stop 'write_summary_file: unknown matching-plane response backend.' end select write (u, '(a,es24.16)') 'surface_current_model_matching_plane_z_m=', cfg%sim%box_max(3) write (u, '(a,a)') 'surface_current_model_electron_species=', & trim(cfg%surface_current%electron_species) write (u, '(a,a)') 'surface_current_model_ion_species=', trim(cfg%surface_current%ion_species) write (u, '(a,a)') 'surface_current_model_photoelectron_species=', & trim(cfg%surface_current%photoelectron_species) write (u, '(a,es24.16)') 'surface_current_model_coupling_rtol=', cfg%surface_current%coupling_rtol write (u, '(a,4(1x,es24.16))') 'surface_current_model_coupling_atol=', & cfg%surface_current%coupling_atol write (u, '(a,i0)') 'surface_current_model_coupling_max_iterations=', & cfg%surface_current%coupling_max_iterations write (u, '(a,es24.16)') 'surface_current_model_coupling_relaxation=', & cfg%surface_current%coupling_relaxation write (u, '(a)') 'surface_current_model_dynamic_state_source=accepted_batch_fixed_point' else write (u, '(a,a)') 'surface_current_model_zhao_branch=', current_model%zhao_branch write (u, '(a,l1)') 'surface_current_model_photoelectron_active=', current_model%photoelectron_active write (u, '(a,es24.16)') 'surface_current_model_reference_area_m2=', current_model%reference_area_m2 write (u, '(a,es24.16)') 'surface_current_model_phi0_V=', current_model%phi0_v write (u, '(a,es24.16)') 'surface_current_model_phi_m_V=', current_model%phi_m_v write (u, '(a,es24.16)') 'surface_current_model_ambient_electron_density_m3=', & current_model%ambient_electron_density_m3 write (u, '(a,es24.16)') 'surface_current_model_electron_current_density_A_m2=', & current_model%electron_current_density_a_m2 write (u, '(a,es24.16)') 'surface_current_model_ion_current_density_A_m2=', & current_model%ion_current_density_a_m2 write (u, '(a,es24.16)') 'surface_current_model_pe_emission_current_density_A_m2=', & current_model%photoelectron_emission_current_density_a_m2 write (u, '(a,es24.16)') 'surface_current_model_pe_escape_current_density_A_m2=', & current_model%photoelectron_escape_current_density_a_m2 write (u, '(a,es24.16)') 'surface_current_model_pe_return_current_density_A_m2=', & current_model%photoelectron_return_current_density_a_m2 write (u, '(a,es24.16)') 'surface_current_model_net_current_density_A_m2=', & current_model%net_current_density_a_m2 write (u, '(a)') 'surface_current_model_current_budget_contract=surface_targets_plus_external_escape' write (u, '(a,es24.16)') 'surface_current_model_pe_budget_residual_current_density_A_m2=', & current_model%photoelectron_budget_residual_current_density_a_m2 write (u, '(a,es24.16)') 'surface_current_model_surface_budget_residual_current_density_A_m2=', & current_model%surface_budget_residual_current_density_a_m2 if (current_model%photoelectron_active) then write (u, '(a,es24.16)') 'surface_current_model_pe_escape_particle_current_A=', & current_model%escaped_particle_current_a(current_model%photoelectron_species_idx) else write (u, '(a,es24.16)') 'surface_current_model_pe_escape_particle_current_A=', 0.0_dp end if write (u, '(a,es24.16)') 'surface_current_model_electron_inflow_reservoir_potential_V=', & current_model%inflow_reservoir_potential_v(current_model%electron_species_idx) write (u, '(a,es24.16)') 'surface_current_model_electron_inflow_access_potential_V=', & current_model%inflow_access_potential_v(current_model%electron_species_idx) write (u, '(a,i0)') 'surface_current_model_electron_inflow_face=', & current_model%inflow_kinetic_face(current_model%electron_species_idx) if (current_model%photoelectron_active) then write (u, '(a,es24.16)') 'surface_current_model_pe_outflow_barrier_potential_V=', & current_model%outflow_barrier_potential_v(current_model%photoelectron_species_idx) write (u, '(a,i0)') 'surface_current_model_pe_outflow_barrier_face=', & current_model%outflow_barrier_face(current_model%photoelectron_species_idx) else write (u, '(a,es24.16)') 'surface_current_model_pe_outflow_barrier_potential_V=', 0.0_dp write (u, '(a,i0)') 'surface_current_model_pe_outflow_barrier_face=', 0_i32 end if end if end if if (present(electrostatic_diagnostics)) then write (u, '(a,l1)') 'top_reference_available=', electrostatic_diagnostics%top_reference_available if (electrostatic_diagnostics%top_reference_available) then write (u, '(a)') 'top_reference_definition=box_z_high_plane_mean' write (u, '(a,i0)') 'top_reference_last_batch=', electrostatic_diagnostics%top_reference_last_batch write (u, '(a,es24.16)') 'top_reference_simulated_time_s=', electrostatic_diagnostics%top_reference_simulated_time write (u, '(a,es24.16)') 'top_reference_z_high_m=', electrostatic_diagnostics%top_reference_z_high write (u, '(a,i0)') 'top_reference_sample_n=', electrostatic_diagnostics%top_reference_sample_n write (u, '(a,es24.16)') 'top_reference_potential_mean_V=', electrostatic_diagnostics%top_reference_potential_mean write (u, '(a,es24.16)') 'top_reference_potential_std_V=', electrostatic_diagnostics%top_reference_potential_std write (u, '(a,es24.16)') 'top_reference_potential_min_V=', electrostatic_diagnostics%top_reference_potential_min write (u, '(a,es24.16)') 'top_reference_potential_max_V=', electrostatic_diagnostics%top_reference_potential_max end if write (u, '(a,l1)') 'electrostatic_split_periodic_active=', electrostatic_diagnostics%split_periodic_active write (u, '(a,a)') 'electrostatic_status=', trim(electrostatic_diagnostics%status) write (u, '(a,es24.16)') 'gauss_residual_C=', electrostatic_diagnostics%gauss_residual write (u, '(a,l1)') 'periodic2_cache_hit=', electrostatic_diagnostics%periodic_cache_hit write (u, '(a,i0)') 'periodic2_operator_build_count=', electrostatic_diagnostics%periodic_operator_build_count write (u, '(a,a)') 'periodic2_cache_fingerprint=', trim(electrostatic_diagnostics%periodic_cache_fingerprint) write (u, '(a,a)') 'periodic2_cache_path=', trim(electrostatic_diagnostics%periodic_cache_path) end if if (present(charge_ledger)) then write (u, '(a,i0)') 'charge_ledger_nspecies=', charge_ledger%nspecies write (u, '(a,i0)') 'charge_ledger_batch_count=', charge_ledger%batch_count write (u, '(a,es24.16)') 'charge_ledger_surface_charge_before_C=', charge_ledger%surface_charge_before write (u, '(a,es24.16)') 'charge_ledger_surface_charge_after_C=', charge_ledger%surface_charge_after write (u, '(a,es24.16)') 'charge_ledger_local_flight_charge_before_C=', & charge_ledger%local_flight_charge_before write (u, '(a,es24.16)') 'charge_ledger_local_flight_charge_after_C=', & charge_ledger%local_flight_charge_after write (u, '(a,es24.16)') 'charge_ledger_unresolved_stock_before_C=', & charge_ledger%unresolved_stock_before write (u, '(a,es24.16)') 'charge_ledger_unresolved_stock_after_C=', & charge_ledger%unresolved_stock_after write (u, '(a,es24.16)') 'charge_ledger_residual_C=', charge_ledger%residual() write (u, '(a,es24.16)') 'charge_ledger_discarded_unresolved_abs_C=', & charge_ledger%discarded_unresolved_abs() write (u, '(a,es24.16)') 'charge_ledger_neutral_return_correction_C=', & finite_charge_sum(charge_ledger%neutral_return_correction, 'summary neutral-return correction') write (u, '(a,es24.16)') 'charge_ledger_fixed_current_correction_C=', & finite_charge_sum(charge_ledger%fixed_current_correction, 'summary fixed-current correction') write (u, '(a,es24.16)') 'charge_ledger_fixed_absorbed_applied_charge_C=', & finite_charge_sum(charge_ledger%fixed_absorbed_target_charge, 'summary fixed absorbed applied charge') write (u, '(a,es24.16)') 'charge_ledger_fixed_emission_applied_charge_C=', & finite_charge_sum(charge_ledger%fixed_emission_target_charge, 'summary fixed emission applied charge') write (u, '(a,es24.16)') 'charge_ledger_raw_escape_charge_C=', & finite_charge_sum(charge_ledger%escaped_to_infinity, 'summary raw escape charge') write (u, '(a,es24.16)') 'charge_ledger_fixed_escape_target_charge_C=', & finite_charge_sum(charge_ledger%fixed_escape_target_charge, 'summary fixed escape target charge') write (u, '(a,es24.16)') 'charge_ledger_fixed_escape_applied_charge_C=', & finite_charge_sum(charge_ledger%fixed_escape_target_charge, 'summary fixed escape applied charge') write (u, '(a,es24.16)') 'charge_ledger_fixed_escape_correction_C=', & finite_charge_sum(charge_ledger%fixed_escape_correction, 'summary fixed escape correction') write (u, '(a,es24.16)') 'charge_ledger_fixed_applied_surface_net_charge_C=', & finite_charge_sum( & [charge_ledger%fixed_absorbed_target_charge, charge_ledger%fixed_emission_target_charge], & 'summary fixed applied surface net charge' & ) if (current_model%active .and. current_model%photoelectron_active) then write (u, '(a,es24.16)') 'charge_ledger_fixed_pe_continuity_residual_C=', & finite_charge_sum( & [ & charge_ledger%fixed_absorbed_target_charge(current_model%photoelectron_species_idx), & charge_ledger%fixed_emission_target_charge(current_model%photoelectron_species_idx), & charge_ledger%fixed_escape_target_charge(current_model%photoelectron_species_idx) & ], & 'summary fixed photoelectron continuity residual' & ) end if end if if (count_dielectric_surfaces(mesh) > 0_i32) then write (u, '(a,i0)') 'surface_model_dielectric_elem_count=', count_dielectric_surfaces(mesh) write (u, '(a)') 'surface_model_note=metadata_only_dielectric_present' end if close (u) end procedure write_summary_file !> 解決済みの流入モデルを summary 用の安定した語彙へ変換する。 function external_inflow_map_name(inflow_map) result(name) integer(i32), intent(in) :: inflow_map character(len=32) :: name select case (inflow_map) case (external_inflow_none) name = 'source_vdf' case (external_inflow_scalar_barrier) name = 'infinity_barrier' case default error stop 'write_summary_file: unknown resolved external inflow map.' end select end function external_inflow_map_name !> 解決済みの通常 open 境界モデルを summary 用の安定した語彙へ変換する。 function external_open_model_name(open_model) result(name) integer(i32), intent(in) :: open_model character(len=32) :: name select case (open_model) case (external_open_escape) name = 'escape' case (external_open_potential_barrier) name = 'potential_barrier' case default error stop 'write_summary_file: unknown resolved ordinary open model.' end select end function external_open_model_name !> 処理済みmacro particleに対する累積soft-discard率を返す。 module procedure soft_discard_fraction fraction = 0.0_dp if (stats%processed_particles <= 0) return fraction = real(stats%multiple_box_events_soft_discarded, dp)/real(stats%processed_particles, dp) end procedure soft_discard_fraction !> 現行物理モデルで未分岐の dielectric 要素数を数える。 module procedure count_dielectric_surfaces n = 0_i32 if (.not. allocated(mesh%elem_surface_model)) return n = int(count(mesh%elem_surface_model == surface_model_dielectric), kind=i32) end procedure count_dielectric_surfaces end submodule bem_output_writer_summary