From ac077ea6c1b8a324b91b9aff531938f7fb0a1272 Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Wed, 25 Mar 2026 14:14:22 +0100 Subject: [PATCH 01/11] docs: add IO refactor design for shared logger and data verbosity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design document for issue #116. Introduces a shared logger module in common/logger/ with leveled output (SILENT→TRACE), format helpers, and a separate data_verbosity integer for HDF5 output control. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/plans/2026-03-25-io-refactor-design.md | 150 ++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 docs/plans/2026-03-25-io-refactor-design.md diff --git a/docs/plans/2026-03-25-io-refactor-design.md b/docs/plans/2026-03-25-io-refactor-design.md new file mode 100644 index 00000000..0087a6dd --- /dev/null +++ b/docs/plans/2026-03-25-io-refactor-design.md @@ -0,0 +1,150 @@ +# IO Refactor Design: Shared Logger and Data Verbosity + +> **GitHub Issue:** #116 — Refactor IO in QL-Balance and KIM +> +> **Goal:** Replace ad-hoc `write(*,*)`/`print *` statements across both codes +> with a shared leveled logger module, and add an integer data-verbosity control +> for HDF5/file output. + +--- + +## 1. Logger Module + +New shared module at `common/logger/logger_m.f90`, built as a static library +(`kamel_logger`) and linked by both KIM and QL-Balance. + +### Log Levels + +| Constant | Value | Purpose | +|----------------|-------|---------------------------------------------------------------| +| `LVL_SILENT` | -1 | No output | +| `LVL_RESULT` | 0 | Final results only (banner, key computed quantities) | +| `LVL_ERROR` | 1 | Errors before `error stop` | +| `LVL_WARNING` | 2 | Warnings (sign mismatch, missing optional files, etc.) | +| `LVL_INFO` | 3 | Normal progress (**default**) — config summary, solver entry | +| `LVL_DEBUG` | 4 | Detailed diagnostics — per-resonance values, intermediates | +| `LVL_TRACE` | 5 | Everything — per-gridpoint dumps, inner-loop output | + +### API + +```fortran +! Level control (called once after namelist read) +call set_log_level(level) +integer function get_log_level() + +! Logging subroutines (string-only, level check is internal) +call log_error(msg) ! writes to stderr, then calls error stop +call log_warning(msg) ! writes to stderr +call log_info(msg) ! writes to stdout +call log_debug(msg) ! writes to stdout +call log_trace(msg) ! writes to stdout +call log_result(msg) ! writes to stdout (shown at LVL_RESULT and above) + +! Format helpers — return formatted strings, overloaded for real(dp), +! integer, logical, and character value types. +character(len=256) function fmt_val(label, value, unit) +``` + +Output format follows NEO-RT conventions: + +``` +[ERROR] message → stderr +[WARN ] message → stderr +[INFO ] message → stdout +[DEBUG] message → stdout +[TRACE] message → stdout +``` + +`log_result` prints the message without a prefix, for banners and key results. + +## 2. Data Verbosity + +A separate integer variable `data_verbosity` controlling how much HDF5/file +data gets written. Lives in each code's own config module, not in the shared +logger. + +### Levels + +| Value | Meaning | What gets written | +|-------|----------------------|----------------------------------------------------------------| +| 0 | Minimal | Final-state output only (the HDF5 downstream tools need) | +| 1 | Standard (**default**) | + per-timestep profiles, transport coefficients | +| 2 | Detailed | + per-mode fields (Es, Br), resonance diagnostics, currents | +| 3 | Full | + Jacobian data, intermediate solver states, gridpoint dumps | + +### Configuration + +Each code reads `log_level` and `data_verbosity` from its own namelist: + +- **QL-Balance:** `balance_conf.nml` → `BALANCENML` namelist +- **KIM:** `KIM_config.nml` → `KIM_CONFIG` namelist + +After reading, each code calls `set_log_level(log_level)`. + +The existing format-toggle variables (`ihdf5IO` in QL-Balance, `hdf5_output` +in KIM) are kept — they control *format*, not *amount*. + +## 3. Removed Variables (Clean Break) + +| Code | Removed | Replaced by | +|-------------|------------------------------------------------|--------------------------------| +| QL-Balance | `debug_mode` (logical) | `log_level` | +| QL-Balance | `diagnostics_output` (logical) | `data_verbosity` | +| KIM | `fdebug` (integer) | `log_level` | +| KIM | `fstatus` (integer) | `log_level` | +| KIM | `fdiagnostics` (integer) | `data_verbosity` | + +No backward-compatibility shims — old namelists must be updated. + +## 4. Migration Strategy + +### Classification of existing output (~880 statements across ~47 files) + +1. **Config display** (`read_config.f90`, `config_display.f90`) → + `log_info(fmt_val(...))` +2. **Progress/status** (`"Status: solve poisson"`) → `log_info(msg)` +3. **Warnings** (`"WARNING: ..."`) → `log_warning(msg)` +4. **Debug prints** (currently guarded by `if (debug_mode)` / `if (fdebug)`) → + `log_debug(msg)` or `log_trace(msg)` +5. **Error messages** before `error stop` → `log_error(msg)` +6. **HDF5 data writes** → add `if (data_verbosity >= N)` guards + +### What NOT to change + +- File I/O to unit numbers (namelist writes, data files) +- ASCII art banner → `log_result` (shown at verbosity 0) +- Third-party code (libcerf, ddeabm, slatec) + +### Order of work + +1. Create `common/logger/logger_m.f90` + CMake +2. Wire into both codes' CMakeLists +3. Migrate KIM (~27 files, ~565 statements) +4. Migrate QL-Balance (~20 files, ~316 statements) +5. Update namelists and Python interface (`balance_conf.py`, + `balance_interface.py`) +6. Update golden record test config + +## 5. File Changes + +### New files + +- `common/logger/logger_m.f90` +- `common/logger/CMakeLists.txt` + +### Config/build modifications + +- `CMakeLists.txt` — add `common/logger` subdirectory +- `KIM/src/CMakeLists.txt` — link `kamel_logger` +- `QL-Balance/CMakeLists.txt` — link `kamel_logger` +- `KIM/src/setup/config_mod.f90` — replace `fdebug`/`fstatus`/`fdiagnostics` +- `KIM/src/general/read_config.f90` — read new variables, call `set_log_level` +- `QL-Balance/src/base/control_mod.f90` — replace `debug_mode`/`diagnostics_output` +- `QL-Balance/src/base/read_config.f90` — read new variables, call `set_log_level` +- `QL-Balance/namelists/balance_conf.nml` +- `python/balance_interface/balance_interface.py` + +### Source migration (~47 files) + +- KIM: ~27 files +- QL-Balance: ~20 files From 74174b6bf31e9c25c39271bb3f791d1795e33928 Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Wed, 25 Mar 2026 14:18:58 +0100 Subject: [PATCH 02/11] docs: add IO refactor implementation plan Detailed task-by-task plan for issue #116: shared logger module, config variable migration, source file migration for KIM and QL-Balance, Python interface and golden record test updates. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/plans/2026-03-25-io-refactor-plan.md | 579 ++++++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 docs/plans/2026-03-25-io-refactor-plan.md diff --git a/docs/plans/2026-03-25-io-refactor-plan.md b/docs/plans/2026-03-25-io-refactor-plan.md new file mode 100644 index 00000000..8f3567c9 --- /dev/null +++ b/docs/plans/2026-03-25-io-refactor-plan.md @@ -0,0 +1,579 @@ +# IO Refactor Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Replace ad-hoc write/print statements in KIM and QL-Balance with a shared leveled logger module, and add integer data-verbosity control for HDF5 output. + +**Architecture:** A new `common/logger/logger_m.f90` static library provides leveled logging (SILENT..TRACE) and format helpers. Each code reads `log_level` and `data_verbosity` from its own namelist and calls `set_log_level()`. Old boolean/integer verbosity flags are removed (clean break). + +**Tech Stack:** Fortran 2008, CMake/Ninja, CTest, f90nml (Python) + +**Design document:** `docs/plans/2026-03-25-io-refactor-design.md` + +--- + +## Task 1: Create Logger Module + +**Files:** +- Create: `common/logger/logger_m.f90` +- Create: `common/logger/CMakeLists.txt` + +**Step 1: Write `common/logger/logger_m.f90`** + +```fortran +module logger_m + implicit none + private + + integer, parameter :: dp = kind(1.0d0) + integer, parameter :: FMT_LEN = 256 + + ! Log levels + integer, public, parameter :: LVL_SILENT = -1 + integer, public, parameter :: LVL_RESULT = 0 + integer, public, parameter :: LVL_ERROR = 1 + integer, public, parameter :: LVL_WARNING = 2 + integer, public, parameter :: LVL_INFO = 3 + integer, public, parameter :: LVL_DEBUG = 4 + integer, public, parameter :: LVL_TRACE = 5 + + integer :: current_level = LVL_INFO + + public :: set_log_level, get_log_level + public :: log_error, log_warning, log_info, log_debug, log_trace, log_result + + interface fmt_val + module procedure fmt_val_real, fmt_val_int, fmt_val_logical, fmt_val_str + end interface fmt_val + public :: fmt_val + +contains + + subroutine set_log_level(level) + integer, intent(in) :: level + current_level = max(LVL_SILENT, min(LVL_TRACE, level)) + end subroutine set_log_level + + function get_log_level() result(level) + integer :: level + level = current_level + end function get_log_level + + subroutine log_error(msg) + character(*), intent(in) :: msg + write(0, '(A)') '[ERROR] ' // trim(msg) + error stop + end subroutine log_error + + subroutine log_warning(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_WARNING) write(0, '(A)') '[WARN ] ' // trim(msg) + end subroutine log_warning + + subroutine log_info(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_INFO) write(6, '(A)') '[INFO ] ' // trim(msg) + end subroutine log_info + + subroutine log_debug(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_DEBUG) write(6, '(A)') '[DEBUG] ' // trim(msg) + end subroutine log_debug + + subroutine log_trace(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_TRACE) write(6, '(A)') '[TRACE] ' // trim(msg) + end subroutine log_trace + + subroutine log_result(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_RESULT) write(6, '(A)') trim(msg) + end subroutine log_result + + ! --- Format helpers --- + + function fmt_val_real(label, value, unit) result(s) + character(*), intent(in) :: label + real(dp), intent(in) :: value + character(*), intent(in), optional :: unit + character(len=FMT_LEN) :: s + character(len=20) :: vbuf + write(vbuf, '(ES15.8)') value + if (present(unit)) then + s = trim(label) // ' = ' // trim(adjustl(vbuf)) // ' ' // trim(unit) + else + s = trim(label) // ' = ' // trim(adjustl(vbuf)) + end if + end function fmt_val_real + + function fmt_val_int(label, value, unit) result(s) + character(*), intent(in) :: label + integer, intent(in) :: value + character(*), intent(in), optional :: unit + character(len=FMT_LEN) :: s + character(len=20) :: vbuf + write(vbuf, '(I0)') value + if (present(unit)) then + s = trim(label) // ' = ' // trim(adjustl(vbuf)) // ' ' // trim(unit) + else + s = trim(label) // ' = ' // trim(adjustl(vbuf)) + end if + end function fmt_val_int + + function fmt_val_logical(label, value, unit) result(s) + character(*), intent(in) :: label + logical, intent(in) :: value + character(*), intent(in), optional :: unit + character(len=FMT_LEN) :: s + if (present(unit)) then + s = trim(label) // ' = ' // merge('T', 'F', value) // ' ' // trim(unit) + else + s = trim(label) // ' = ' // merge('T', 'F', value) + end if + end function fmt_val_logical + + function fmt_val_str(label, value, unit) result(s) + character(*), intent(in) :: label + character(*), intent(in) :: value + character(*), intent(in), optional :: unit + character(len=FMT_LEN) :: s + if (present(unit)) then + s = trim(label) // ' = ' // trim(value) // ' ' // trim(unit) + else + s = trim(label) // ' = ' // trim(value) + end if + end function fmt_val_str + +end module logger_m +``` + +**Step 2: Write `common/logger/CMakeLists.txt`** + +```cmake +set(LOGGER_MODULE_DIR ${CMAKE_BINARY_DIR}/modules/logger) +file(MAKE_DIRECTORY ${LOGGER_MODULE_DIR}) + +add_library(kamel_logger STATIC + ${CMAKE_CURRENT_SOURCE_DIR}/logger_m.f90 +) + +set_target_properties(kamel_logger PROPERTIES + POSITION_INDEPENDENT_CODE ON + Fortran_MODULE_DIRECTORY ${LOGGER_MODULE_DIR} + LINKER_LANGUAGE Fortran +) + +target_include_directories(kamel_logger + PUBLIC ${LOGGER_MODULE_DIR} +) +``` + +**Step 3: Build and verify** + +Run: `make clean && make all` +Expected: Build succeeds (logger is built but not yet used) + +**Step 4: Commit** + +``` +git add common/logger/ +git commit -m "feat: add shared logger module with leveled output and format helpers" +``` + +--- + +## Task 2: Wire Logger into CMake for Both Codes + +**Files:** +- Modify: `CMakeLists.txt:103-105` (add subdirectory) +- Modify: `KIM/src/CMakeLists.txt:147-156` (link library) +- Modify: `QL-Balance/CMakeLists.txt:145-167` (link library) + +**Step 1: Add `common/logger` subdirectory to top-level CMakeLists.txt** + +In `CMakeLists.txt`, after line 103 (`add_subdirectory(common/math)`), add: + +```cmake +add_subdirectory(common/logger) +``` + +So lines 103-106 become: + +```cmake +add_subdirectory(common/math) +add_subdirectory(common/logger) +add_subdirectory(common/hdf5_tools) +add_subdirectory(common/equil) +``` + +**Step 2: Link `kamel_logger` into KIM** + +In `KIM/src/CMakeLists.txt`, add `kamel_logger` to the `target_link_libraries(KIM_lib PUBLIC ...)` block (after `kamel_hdf5_tools`). + +**Step 3: Link `kamel_logger` into QL-Balance** + +In `QL-Balance/CMakeLists.txt`, add `kamel_logger` to the `target_link_libraries(ql-balance_lib PUBLIC ...)` block (after `kamel_hdf5_tools`). + +**Step 4: Build and verify** + +Run: `make all` +Expected: Build succeeds, logger library is linked into both codes. + +**Step 5: Commit** + +``` +git add CMakeLists.txt KIM/src/CMakeLists.txt QL-Balance/CMakeLists.txt +git commit -m "build: wire kamel_logger into KIM and QL-Balance" +``` + +--- + +## Task 3: Add Config Variables and Namelist Wiring for KIM + +**Files:** +- Modify: `KIM/src/setup/config_mod.f90:34` (replace fdebug/fstatus/fdiagnostics) +- Modify: `KIM/src/general/read_config.f90:27-29` (update KIM_IO namelist) +- Modify: `KIM/nmls/KIM_config.nml:34-36` (update defaults) +- Modify: `KIM/src/util/IO_collection.f90:123-131` (update HDF5 output) + +**Step 1: Update `config_mod.f90`** + +Replace the declaration at line 34: +```fortran +integer :: fdebug, fstatus, fdiagnostics +``` +with: +```fortran +integer :: log_level = 3 ! maps to LVL_INFO +integer :: data_verbosity = 1 ! standard output +``` + +**Step 2: Update `read_config.f90` namelist definition** + +In the `KIM_IO` namelist (lines 27-29), replace `fdebug, fstatus, fdiagnostics` with `log_level, data_verbosity`. + +After the namelist read (after line 69 `close(unit = 77)`), add: +```fortran +use logger_m, only: set_log_level +call set_log_level(log_level) +``` + +**Step 3: Update `KIM_config.nml`** + +Replace lines 34-36: +``` + fdebug = 1 + fstatus = 1 + fdiagnostics = 0 +``` +with: +``` + log_level = 3 + data_verbosity = 1 +``` + +**Step 4: Update `IO_collection.f90` HDF5 output** + +Replace the `fdebug`/`fstatus`/`fdiagnostics` writes (lines 123, 125, 131) with: +```fortran +call h5_add(h5grpid, 'log_level', log_level, 'Log verbosity level', 'i') +call h5_add(h5grpid, 'data_verbosity', data_verbosity, 'Data output verbosity', 'i') +``` + +**Step 5: Build and verify** + +Run: `make all` +Expected: Build succeeds. KIM reads new variables from namelist. + +**Step 6: Commit** + +``` +git commit -am "feat(KIM): replace fdebug/fstatus/fdiagnostics with log_level and data_verbosity" +``` + +--- + +## Task 4: Add Config Variables and Namelist Wiring for QL-Balance + +**Files:** +- Modify: `QL-Balance/src/base/control_mod.f90:18,22` (replace debug_mode/diagnostics_output) +- Modify: `QL-Balance/src/base/read_config.f90:3-8,23-32,37-38,72,74` (update namelist + printing) +- Modify: `QL-Balance/namelists/balance_conf.nml:41,46` (update defaults) + +**Step 1: Update `control_mod.f90`** + +Replace line 18 (`logical :: debug_mode`) with: +```fortran +integer :: log_level = 3 ! maps to LVL_INFO +``` + +Replace line 22 (`logical :: diagnostics_output`) with: +```fortran +integer :: data_verbosity = 1 ! standard output +``` + +**Step 2: Update `read_config.f90`** + +In the `use control_mod` import (lines 3-8): replace `debug_mode` and `diagnostics_output` references with `log_level, data_verbosity`. Remove `debug_mode` from the import list entirely. + +In the namelist definition (lines 23-32): replace `diagnostics_output` with `data_verbosity` and `debug_mode` with `log_level`. Remove `suppression_mode` only if it was tied to diagnostics (check first — it may be independent). + +After the namelist read (after line 38), add: +```fortran +use logger_m, only: set_log_level +call set_log_level(log_level) +``` + +Update the print statements (lines 72, 74) to use the new variable names: +```fortran +write (*, "(A,I0)") " log_level = ", log_level +write (*, "(A,I0)") " data_verbosity = ", data_verbosity +``` + +**Step 3: Update `balance_conf.nml`** + +Replace: +``` + diagnostics_output = .false. , +``` +with: +``` + data_verbosity = 1 , +``` + +Replace: +``` + debug_mode = .false. , +``` +with: +``` + log_level = 3 , +``` + +**Step 4: Build — expect errors** + +Run: `make all` +Expected: **Compilation errors** in files that still reference `debug_mode` and `diagnostics_output`. This is expected — Task 6 will fix QL-Balance source files. For now just verify the config/namelist changes compile in `control_mod.f90` and `read_config.f90` themselves. + +**Step 5: Commit (WIP)** + +``` +git commit -am "feat(QL-Balance): replace debug_mode/diagnostics_output with log_level and data_verbosity + +WIP: source files still reference old variables, will be migrated in subsequent commits" +``` + +--- + +## Task 5: Migrate KIM Source Files to Logger + +**Files to modify (~12 files with active control variable usage):** +- `KIM/src/general/config_display.f90:119-121,338-374` +- `KIM/src/kernels/kernel.f90:80,129,372,473-475,847,947-949` +- `KIM/src/electrostatic_poisson/solve_poisson.f90:11,34-35,51,168,188` +- `KIM/src/background_equilibrium/calculate_equil.f90:74,180,185` +- `KIM/src/background_equilibrium/species_mod.f90:1171,1184,1275,1373,1377` +- `KIM/src/electromagnetic/electromagnetic_solver.f90:47,222` +- `KIM/src/grid/grid_mod.f90:197,274` +- `KIM/src/grid/gengrid.f90:6,37` +- `KIM/src/math/quadpack_integration_m.f90:204,274,299,368,393,462` + +Also migrate any remaining bare `write(*,*)` and `print *` statements in these files to appropriate logger calls. + +**Migration rules:** +- `if (fstatus >= 1) write(*,*) 'Status: ...'` → `call log_info('...')` +- `if (fstatus >= 2) write(*,*) ...` → `call log_debug('...')` +- `if (fdebug == 1) ...` → `call log_debug('...')` +- `if (fdebug >= 2) ...` → `call log_debug('...')` or `call log_trace('...')` +- `if (fdebug == 3) ...` → `call log_trace('...')` +- `if (fdiagnostics == 3) ...` → `if (data_verbosity >= 3) ...` (keep as data guard, not logger) +- Bare `write(*,*) 'Warning: ...'` → `call log_warning('...')` +- Bare `write(*,*) 'Error: ...'` before `error stop` → `call log_error('...')` +- Bare `write(*,*) ...` status messages → `call log_info('...')` +- Formatted output like `write(*,"(A,ES15.8,A)") "label", val, "unit"` → `call log_info(fmt_val('label', val, 'unit'))` + +**For each file:** +1. Replace `use config_m, only: ... fdebug ...` with `use logger_m, only: log_info, log_debug, ...` (and `use config_m, only: ... data_verbosity ...` where `fdiagnostics` was used for data guards) +2. Convert write/print statements per the rules above +3. Remove bare `if (fdebug ...)` / `if (fstatus ...)` guards — the logger checks internally + +**Step 1: Migrate config_display.f90** + +Update lines 119-121 to use `log_level` and `data_verbosity` display strings. Update or remove `get_debug_string`/`get_status_string` helpers (lines 338-374) — replace with a single helper or inline. + +**Step 2: Migrate remaining KIM source files** + +Work through each file listed above, applying the migration rules. + +**Step 3: Build and verify** + +Run: `make all` +Expected: Build succeeds. No references to `fdebug`, `fstatus`, or `fdiagnostics` remain. + +**Step 4: Verify no old references remain** + +Run: `grep -rn 'fdebug\|fstatus\|fdiagnostics' KIM/src/` +Expected: No matches (except possibly comments). + +**Step 5: Run tests** + +Run: `make test` +Expected: All KIM tests pass. + +**Step 6: Commit** + +``` +git commit -am "refactor(KIM): migrate all IO to shared logger module" +``` + +--- + +## Task 6: Migrate QL-Balance Source Files to Logger + +**Files to modify (~17 files referencing debug_mode, ~9 referencing diagnostics_output):** + +Key files: +- `QL-Balance/src/base/wave_code_data_64bit.f90` (heaviest: ~20 debug_mode refs) +- `QL-Balance/src/base/ramp_coil.f90` (~25 debug_mode refs) +- `QL-Balance/src/base/paramscan.f90` (~12 debug_mode refs) +- `QL-Balance/src/base/SingleStep.f90` (~8 debug_mode refs) +- `QL-Balance/src/base/writeData.f90` (~8 debug_mode + diagnostics_output refs) +- `QL-Balance/src/base/get_dql.f90` +- `QL-Balance/src/base/diff_coeffs.f90` +- `QL-Balance/src/base/time_evolution.f90` +- `QL-Balance/src/base/calc_current_densities.f90` +- `QL-Balance/src/base/plasma_parameters.f90` +- `QL-Balance/src/base/h5mod.f90` +- `QL-Balance/src/base/balance_eqs_source_terms.f90` +- `QL-Balance/src/base/kim_wave_code_adapter.f90` +- `QL-Balance/src/base/integrate_parallel_current.f90` +- `QL-Balance/src/base/transp_coeffs_mod.f90` +- `QL-Balance/src/stellarator/balance_eqs_source_terms_stell.f90` +- `QL-Balance/src/stellarator/time_evol_stell.f90` + +**Migration rules:** +- `if (debug_mode) write(*,*) ...` → `call log_debug('...')` +- `if (debug_mode) print *, ...` → `call log_debug('...')` +- `if (diagnostics_output) call write_..._to_hdf5(...)` → `if (data_verbosity >= 2) call write_..._to_hdf5(...)` +- Bare `write(*,*) 'WARNING: ...'` → `call log_warning('...')` +- `error stop "msg"` → `call log_error('msg')` (which calls error stop internally) +- Bare status `write(*,*)` → `call log_info('...')` +- Formatted values → `call log_info(fmt_val(...))` + +**For each file:** +1. Replace `use control_mod, only: ... debug_mode ...` with `use logger_m, only: log_debug, ...` (and `use control_mod, only: ... data_verbosity ...` where `diagnostics_output` was used) +2. Convert write/print statements per the rules above +3. Remove bare `if (debug_mode)` guards — the logger checks internally + +**Step 1: Migrate files in batches** + +Start with the most-referenced files (wave_code_data_64bit, ramp_coil, paramscan) then work through the rest. + +**Step 2: Handle read_config.f90 print block (lines 41-98)** + +The large config-display block of ~50 write statements should be converted to `log_info(fmt_val(...))` calls. For example: +```fortran +! Before: +write (*, "(A,ES15.8,A)") " B_tor = ", btor, " G" +! After: +call log_info(fmt_val(' B_tor', btor, 'G')) +``` + +**Step 3: Build and verify** + +Run: `make all` +Expected: Build succeeds. No references to `debug_mode` or `diagnostics_output` remain. + +**Step 4: Verify no old references remain** + +Run: `grep -rn 'debug_mode\|diagnostics_output' QL-Balance/src/` +Expected: No matches (except possibly comments). + +**Step 5: Run tests** + +Run: `make test` +Expected: All tests pass. + +**Step 6: Commit** + +``` +git commit -am "refactor(QL-Balance): migrate all IO to shared logger module" +``` + +--- + +## Task 7: Update Python Interface and Golden Record Test + +**Files:** +- Modify: `python/balance_interface/balance_interface.py` — update any references to old namelist keys +- Modify: `test/ql-balance/golden_record/setup_runfolder.py` — update namelist key if `diagnostics_output` is set there + +**Step 1: Update `setup_runfolder.py`** + +In `setup_runfolder.py`, line 96 currently sets: +```python +bi.conf.conf["balancenml"]["diagnostics_output"] = True +``` +Replace with: +```python +bi.conf.conf["balancenml"]["data_verbosity"] = 2 +``` + +Also check if `debug_mode` is set anywhere in the test setup and replace with `log_level`. + +**Step 2: Check `balance_interface.py`** + +Search for any hardcoded references to `debug_mode` or `diagnostics_output` in namelist manipulation. The Python `debug` flag (constructor parameter) is a Python-side flag and should NOT be changed — it's independent. + +**Step 3: Update `suppression_mode` reference** + +In `setup_runfolder.py` line 97: +```python +bi.conf.conf["balancenml"]["suppression_mode"] = False +``` +`suppression_mode` is independent of logging — keep it unchanged. + +**Step 4: Run golden record test locally (if possible)** + +Run: `make test` +Expected: All tests pass including golden record. + +**Step 5: Commit** + +``` +git commit -am "fix(test): update golden record and Python interface for new IO variables" +``` + +--- + +## Task 8: Final Verification and Cleanup + +**Step 1: Full clean build** + +Run: `make clean && make all` +Expected: Build succeeds with no warnings related to unused variables. + +**Step 2: Run all tests** + +Run: `make test` +Expected: All tests pass. + +**Step 3: Verify no old variable references remain** + +Run these greps — all should return no matches (except comments): +```bash +grep -rn 'fdebug\|fstatus\|fdiagnostics' KIM/src/ --include='*.f90' +grep -rn 'debug_mode\|diagnostics_output' QL-Balance/src/ --include='*.f90' +grep -rn 'debug_mode\|diagnostics_output' python/ --include='*.py' +``` + +**Step 4: Verify logger is the only console output path** + +Run: `grep -rn 'write(\*' KIM/src/ QL-Balance/src/base/ --include='*.f90' | grep -v '!' | wc -l` +Expected: Zero or near-zero (only file I/O to specific units should remain, no `write(*,*)` to stdout). + +**Step 5: Commit any final cleanup** + +``` +git commit -am "chore: final cleanup of IO refactor" +``` From ff025d420bc7d1b8c49559184662c03f2533eda4 Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Wed, 25 Mar 2026 14:21:08 +0100 Subject: [PATCH 03/11] feat: add shared logger module with leveled output and format helpers New common/logger/logger_m.f90 provides: - Log levels: SILENT, RESULT, ERROR, WARNING, INFO, DEBUG, TRACE - Leveled output: log_error, log_warning, log_info, log_debug, log_trace - Format helpers: fmt_val overloaded for real, integer, logical, string Co-Authored-By: Claude Opus 4.6 (1M context) --- common/logger/CMakeLists.txt | 16 +++++ common/logger/logger_m.f90 | 124 +++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 common/logger/CMakeLists.txt create mode 100644 common/logger/logger_m.f90 diff --git a/common/logger/CMakeLists.txt b/common/logger/CMakeLists.txt new file mode 100644 index 00000000..2e58241b --- /dev/null +++ b/common/logger/CMakeLists.txt @@ -0,0 +1,16 @@ +set(LOGGER_MODULE_DIR ${CMAKE_BINARY_DIR}/modules/logger) +file(MAKE_DIRECTORY ${LOGGER_MODULE_DIR}) + +add_library(kamel_logger STATIC + ${CMAKE_CURRENT_SOURCE_DIR}/logger_m.f90 +) + +set_target_properties(kamel_logger PROPERTIES + POSITION_INDEPENDENT_CODE ON + Fortran_MODULE_DIRECTORY ${LOGGER_MODULE_DIR} + LINKER_LANGUAGE Fortran +) + +target_include_directories(kamel_logger + PUBLIC ${LOGGER_MODULE_DIR} +) diff --git a/common/logger/logger_m.f90 b/common/logger/logger_m.f90 new file mode 100644 index 00000000..e7515668 --- /dev/null +++ b/common/logger/logger_m.f90 @@ -0,0 +1,124 @@ +module logger_m + implicit none + private + + integer, parameter :: dp = kind(1.0d0) + integer, parameter :: FMT_LEN = 256 + + ! Log levels + integer, public, parameter :: LVL_SILENT = -1 + integer, public, parameter :: LVL_RESULT = 0 + integer, public, parameter :: LVL_ERROR = 1 + integer, public, parameter :: LVL_WARNING = 2 + integer, public, parameter :: LVL_INFO = 3 + integer, public, parameter :: LVL_DEBUG = 4 + integer, public, parameter :: LVL_TRACE = 5 + + integer :: current_level = LVL_INFO + + public :: set_log_level, get_log_level + public :: log_error, log_warning, log_info, log_debug, log_trace, log_result + + interface fmt_val + module procedure fmt_val_real, fmt_val_int, fmt_val_logical, fmt_val_str + end interface fmt_val + public :: fmt_val + +contains + + subroutine set_log_level(level) + integer, intent(in) :: level + current_level = max(LVL_SILENT, min(LVL_TRACE, level)) + end subroutine set_log_level + + function get_log_level() result(level) + integer :: level + level = current_level + end function get_log_level + + subroutine log_error(msg) + character(*), intent(in) :: msg + write(0, '(A)') '[ERROR] ' // trim(msg) + error stop + end subroutine log_error + + subroutine log_warning(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_WARNING) write(0, '(A)') '[WARN ] ' // trim(msg) + end subroutine log_warning + + subroutine log_info(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_INFO) write(6, '(A)') '[INFO ] ' // trim(msg) + end subroutine log_info + + subroutine log_debug(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_DEBUG) write(6, '(A)') '[DEBUG] ' // trim(msg) + end subroutine log_debug + + subroutine log_trace(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_TRACE) write(6, '(A)') '[TRACE] ' // trim(msg) + end subroutine log_trace + + subroutine log_result(msg) + character(*), intent(in) :: msg + if (current_level >= LVL_RESULT) write(6, '(A)') trim(msg) + end subroutine log_result + + ! --- Format helpers --- + + function fmt_val_real(label, value, unit) result(s) + character(*), intent(in) :: label + real(dp), intent(in) :: value + character(*), intent(in), optional :: unit + character(len=FMT_LEN) :: s + character(len=20) :: vbuf + write(vbuf, '(ES15.8)') value + if (present(unit)) then + s = trim(label) // ' = ' // trim(adjustl(vbuf)) // ' ' // trim(unit) + else + s = trim(label) // ' = ' // trim(adjustl(vbuf)) + end if + end function fmt_val_real + + function fmt_val_int(label, value, unit) result(s) + character(*), intent(in) :: label + integer, intent(in) :: value + character(*), intent(in), optional :: unit + character(len=FMT_LEN) :: s + character(len=20) :: vbuf + write(vbuf, '(I0)') value + if (present(unit)) then + s = trim(label) // ' = ' // trim(adjustl(vbuf)) // ' ' // trim(unit) + else + s = trim(label) // ' = ' // trim(adjustl(vbuf)) + end if + end function fmt_val_int + + function fmt_val_logical(label, value, unit) result(s) + character(*), intent(in) :: label + logical, intent(in) :: value + character(*), intent(in), optional :: unit + character(len=FMT_LEN) :: s + if (present(unit)) then + s = trim(label) // ' = ' // merge('T', 'F', value) // ' ' // trim(unit) + else + s = trim(label) // ' = ' // merge('T', 'F', value) + end if + end function fmt_val_logical + + function fmt_val_str(label, value, unit) result(s) + character(*), intent(in) :: label + character(*), intent(in) :: value + character(*), intent(in), optional :: unit + character(len=FMT_LEN) :: s + if (present(unit)) then + s = trim(label) // ' = ' // trim(value) // ' ' // trim(unit) + else + s = trim(label) // ' = ' // trim(value) + end if + end function fmt_val_str + +end module logger_m From f69210fb7e6ed47a693ae81cca02bef3cef7fd12 Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Wed, 25 Mar 2026 14:24:47 +0100 Subject: [PATCH 04/11] build: wire kamel_logger into KIM and QL-Balance Co-Authored-By: Claude Opus 4.6 (1M context) --- CMakeLists.txt | 1 + KIM/src/CMakeLists.txt | 1 + QL-Balance/CMakeLists.txt | 1 + 3 files changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c2e7f39e..7d1daed0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,7 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) # Unified build: add subprojects for KiLCA, KIM, and QL-Balance add_subdirectory(common/math) +add_subdirectory(common/logger) add_subdirectory(common/hdf5_tools) add_subdirectory(common/equil) add_subdirectory(KiLCA) diff --git a/KIM/src/CMakeLists.txt b/KIM/src/CMakeLists.txt index a733e5f2..7b1d49bb 100644 --- a/KIM/src/CMakeLists.txt +++ b/KIM/src/CMakeLists.txt @@ -150,6 +150,7 @@ target_link_libraries(KIM_lib PUBLIC hdf5::hdf5_hl hdf5::hdf5_hl_fortran kamel_hdf5_tools + kamel_logger kamel_equil cerf ddeabm diff --git a/QL-Balance/CMakeLists.txt b/QL-Balance/CMakeLists.txt index e899a1bb..e42b5212 100644 --- a/QL-Balance/CMakeLists.txt +++ b/QL-Balance/CMakeLists.txt @@ -157,6 +157,7 @@ target_link_libraries(ql-balance_lib PUBLIC hdf5::hdf5_hl hdf5::hdf5_hl_fortran kamel_hdf5_tools + kamel_logger KIM_lib kilca_lib lapack From d1cbf8d5e0fcac6988fd3e4ee852cbed528267ed Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Wed, 25 Mar 2026 14:26:36 +0100 Subject: [PATCH 05/11] feat(KIM): replace fdebug/fstatus/fdiagnostics with log_level and data_verbosity Co-Authored-By: Claude Opus 4.6 (1M context) --- KIM/nmls/KIM_config.nml | 5 ++--- KIM/src/general/read_config.f90 | 5 ++++- KIM/src/setup/config_mod.f90 | 3 ++- KIM/src/util/IO_collection.f90 | 10 ++++------ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/KIM/nmls/KIM_config.nml b/KIM/nmls/KIM_config.nml index 44867421..41f564b1 100644 --- a/KIM/nmls/KIM_config.nml +++ b/KIM/nmls/KIM_config.nml @@ -31,9 +31,8 @@ output_path = './out/' hdf5_input = .false. hdf5_output = .false. - fdebug = 1 - fstatus = 1 - fdiagnostics = 0 + log_level = 3 + data_verbosity = 1 calculate_asymptotics = .true. ! enable/disable asymptotic (WKB) calculations h5_out_file = '' / diff --git a/KIM/src/general/read_config.f90 b/KIM/src/general/read_config.f90 index 3841ad5c..bb12918b 100644 --- a/KIM/src/general/read_config.f90 +++ b/KIM/src/general/read_config.f90 @@ -6,6 +6,7 @@ subroutine kim_read_config use grid_m use poisson_solver_m, only: solve_poisson use config_display_m, only: display_kim_configuration + use logger_m, only: set_log_level implicit none @@ -25,7 +26,7 @@ subroutine kim_read_config WKB_root_tolerance, WKB_verbose namelist /KIM_IO/ profile_location, hdf5_input, hdf5_output, & - fdebug, fstatus, output_path, calculate_asymptotics, fdiagnostics, & + log_level, data_verbosity, output_path, calculate_asymptotics, & h5_out_file namelist /KIM_SETUP/ btor, R0, m_mode, n_mode, omega, spline_base, & @@ -68,6 +69,8 @@ subroutine kim_read_config read(unit = 77, nml = KIM_PROFILES) close(unit = 77) + call set_log_level(log_level) + ! Map single-switch theta_integration to adaptive backend; allow users to omit theta_integration_method select case (trim(theta_integration)) case ('RKF45') diff --git a/KIM/src/setup/config_mod.f90 b/KIM/src/setup/config_mod.f90 index d16e18ad..2bcfce44 100644 --- a/KIM/src/setup/config_mod.f90 +++ b/KIM/src/setup/config_mod.f90 @@ -31,7 +31,8 @@ module config_m character(256) :: dispersion_output_path ! path to dispersion output subdirectory character(256) :: h5_out_file ! file name of the hdf5 output file logical :: hdf5_input, hdf5_output - integer :: fdebug, fstatus, fdiagnostics + integer :: log_level = 3 ! maps to LVL_INFO + integer :: data_verbosity = 1 ! standard output logical :: calculate_asymptotics ! enable/disable asymptotic calculations character(256) :: nml_config_path = "./KIM_config.nml" ! path to the namelist file diff --git a/KIM/src/util/IO_collection.f90 b/KIM/src/util/IO_collection.f90 index 7cbbc5b3..9ecae37f 100644 --- a/KIM/src/util/IO_collection.f90 +++ b/KIM/src/util/IO_collection.f90 @@ -120,16 +120,14 @@ subroutine write_io_namelist_to_hdf5() 'Logical switch for HDF5 input.', 'true/false') call h5_add(h5grpid, 'hdf5_output', hdf5_output, & 'Logical switch for HDF5 output.', 'true/false') - call h5_add(h5grpid, 'fdebug', fdebug, & - 'Logical switch for debug output.', 'true/false') - call h5_add(h5grpid, 'fstatus', fstatus, & - 'Logical switch for status output.', 'true/false') + call h5_add(h5grpid, 'log_level', log_level, & + 'Log verbosity level', 'i') + call h5_add(h5grpid, 'data_verbosity', data_verbosity, & + 'Data output verbosity', 'i') call h5_add(h5grpid, 'output_path', trim(output_path), & 'Path for output files.', 'str') call h5_add(h5grpid, 'calculate_asymptotics', calculate_asymptotics, & 'Logical switch to calculate asymptotics.', 'true/false') - call h5_add(h5grpid, 'fdiagnostics', fdiagnostics, & - 'Diagnostics output level.', 'integer') call h5_add(h5grpid, 'h5_out_file', trim(h5_out_file), & 'Name of the HDF5 output file.', 'str') From 251bf8bb580eda84576038aeb8757d3d550f4076 Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Wed, 25 Mar 2026 14:26:42 +0100 Subject: [PATCH 06/11] feat(QL-Balance): replace debug_mode/diagnostics_output with log_level and data_verbosity WIP: source files still reference old variables, will be migrated next. Co-Authored-By: Claude Opus 4.6 (1M context) --- QL-Balance/namelists/balance_conf.nml | 4 ++-- QL-Balance/src/base/control_mod.f90 | 4 ++-- QL-Balance/src/base/read_config.f90 | 13 ++++++++----- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/QL-Balance/namelists/balance_conf.nml b/QL-Balance/namelists/balance_conf.nml index 029059bc..c99b7c7e 100644 --- a/QL-Balance/namelists/balance_conf.nml +++ b/QL-Balance/namelists/balance_conf.nml @@ -38,12 +38,12 @@ timstep_min = 1.d-30 , paramscan = .false. , save_prof_time_step = 10 , ! save the profile every "save_prov_time_step"th step - diagnostics_output = .false. , + data_verbosity = 1 , ! The Br stopping criterion checks the discrepancy between the Br value ! and a linear regression thereof br_stopping = .true. , suppression_mode = .true. , - debug_mode = .false. , + log_level = 3 , readfromtimestep = 0 , path2time = ' ' , ramp_up_mode = 0, ! ramp up mode, if 0 no faster ramp up diff --git a/QL-Balance/src/base/control_mod.f90 b/QL-Balance/src/base/control_mod.f90 index 53e6ce7b..9c2f58ec 100644 --- a/QL-Balance/src/base/control_mod.f90 +++ b/QL-Balance/src/base/control_mod.f90 @@ -15,11 +15,11 @@ module control_mod integer :: ihdf5IO ! added: Markus Markl logical :: paramscan ! added: Markus Markl, 03.03.2021 logical :: timing_mode ! added by Markus Markl 06.04.2021 - logical :: debug_mode + integer :: log_level = 3 ! maps to LVL_INFO logical :: suppression_mode ! added by Markus Markl 13.04.2021 logical :: misalign_diffusion ! trigger the calculation and addition of the diffusion due to misaligned equipotentials and flux surfaces character(len=32) :: jpar_method = 'conductivity' ! 'conductivity' or 'curlB' - logical :: diagnostics_output + integer :: data_verbosity = 1 ! standard output logical :: write_gyro_current integer :: irf integer :: readfromtimestep ! added by Markus Markl 02.06.2021. Reads the background profiles from hdf5 file in which profiles of a ql time evolution are stored. diff --git a/QL-Balance/src/base/read_config.f90 b/QL-Balance/src/base/read_config.f90 index 1d00e717..d0de3def 100644 --- a/QL-Balance/src/base/read_config.f90 +++ b/QL-Balance/src/base/read_config.f90 @@ -1,6 +1,6 @@ subroutine read_config use baseparam_mod, only: btor, rtor, rsepar, dperp, Z_i, am, urelax - use control_mod, only: eps, paramscan, diagnostics_output, suppression_mode, debug_mode, & + use control_mod, only: eps, paramscan, data_verbosity, suppression_mode, log_level, & readfromtimestep, temperature_limit, gyro_current_study, & misalign_diffusion, equil_path, ihdf5IO, wave_code, & kim_config_path, kim_profiles_from_balance, & @@ -12,6 +12,7 @@ subroutine read_config use paramscan_mod, only: viscosity_factor use time_evolution use wave_code_data, only: flre_path, vac_path, antenna_factor, I_par_toroidal + use logger_m, only: set_log_level implicit none @@ -23,8 +24,8 @@ subroutine read_config namelist /BALANCENML/ flre_path, vac_path, btor, rtor, rmin, rmax, rsepar, npoimin, gg_factor, & gg_width, gg_r_res, Nstorage, tmax_factor, antenna_factor, iboutype, eps, dperp, Z_i, am, & rb_cut_in, re_cut_in, rb_cut_out, re_cut_out, stop_time_step, path2inp, path2out, & - timstep_min, paramscan, save_prof_time_step, diagnostics_output, br_stopping, & - suppression_mode, debug_mode, readfromtimestep, path2time, ramp_up_mode, t_max_ramp_up, & + timstep_min, paramscan, save_prof_time_step, data_verbosity, br_stopping, & + suppression_mode, log_level, readfromtimestep, path2time, ramp_up_mode, t_max_ramp_up, & temperature_limit, antenna_max_stopping, gyro_current_study, viscosity_factor, & misalign_diffusion, equil_path, ihdf5IO, type_of_run, wave_code, & set_constant_time_step, constant_time_step, urelax, kim_config_path, & @@ -38,6 +39,8 @@ subroutine read_config if (ios /= 0) error stop "Failed to read namelist" close (u) + call set_log_level(log_level) + write (*, *) "" write (*, *) "=================================================================================" write (*, "(A,A)") " Type of Run: ", type_of_run @@ -69,9 +72,9 @@ subroutine read_config write (*, "(A,A)") " path2inp = ", trim(adjustl(path2inp)) write (*, "(A,A)") " path2out = ", trim(adjustl(path2out)) write (*, "(A,L0)") " paramscan = ", paramscan - write (*, "(A,L0)") " diagnostics_output = ", diagnostics_output + write (*, "(A,I0)") " data_verbosity = ", data_verbosity write (*, "(A,L0)") " br_stopping = ", br_stopping - write (*, "(A,L0)") " debug_mode = ", debug_mode + write (*, "(A,I0)") " log_level = ", log_level write (*, "(A,I0)") " readfromtimestep = ", readfromtimestep write (*, "(A,L0)") " suppression_mode = ", suppression_mode write (*, "(A,I0)") " ramp_up_mode = ", ramp_up_mode From fa29eb22323418040070c5fc856ab6244f046fd2 Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Wed, 25 Mar 2026 16:50:06 +0100 Subject: [PATCH 07/11] refactor(KIM): migrate all IO to shared logger module Convert write/print statements across 9 KIM source files to use logger_m calls. Replace fdebug/fstatus guards with log_info/log_debug/ log_trace, fdiagnostics guards with data_verbosity checks. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../calculate_equil.f90 | 17 +- .../background_equilibrium/species_mod.f90 | 175 ++++++++---------- .../electromagnetic_solver.f90 | 101 +++++----- .../electrostatic_poisson/solve_poisson.f90 | 23 ++- KIM/src/general/config_display.f90 | 45 +++-- KIM/src/grid/gengrid.f90 | 19 +- KIM/src/grid/grid_mod.f90 | 14 +- KIM/src/kernels/kernel.f90 | 140 ++++++++------ KIM/src/math/quadpack_integration_m.f90 | 110 +++++------ 9 files changed, 340 insertions(+), 304 deletions(-) diff --git a/KIM/src/background_equilibrium/calculate_equil.f90 b/KIM/src/background_equilibrium/calculate_equil.f90 index f9b8396e..b04e0bd3 100644 --- a/KIM/src/background_equilibrium/calculate_equil.f90 +++ b/KIM/src/background_equilibrium/calculate_equil.f90 @@ -44,7 +44,8 @@ subroutine calculate_equil(write_out) use species_m, only: plasma, calc_plasma_parameter_derivs use constants_m, only: ev, pi, sol use setup_m, only: btor, R0, m_mode, n_mode - use config_m + use config_m, only: number_of_ion_species, output_path, hdf5_output + use logger_m, only: log_info, log_warning implicit none @@ -71,7 +72,7 @@ subroutine calculate_equil(write_out) equil_grid = plasma%r_grid ! for future modifications - if (fstatus == 1) write(*,*) 'Status: Calculating equilibrium, write_out=', write_out + call log_info('Calculating equilibrium') if (.not. allocated(plasma%spec(0)%dndr)) then call calc_plasma_parameter_derivs end if @@ -106,7 +107,14 @@ subroutine calculate_equil(write_out) call ddeabm(dudr, ineq, radius0, u0, r1, info, rtol, atol, idid, rwork, lrw, & iwork, liw, rpar, ipar) - if (idid .lt. 1) write(*,*) 'Warning: calculate_equil: r=', r1, ' idid=', idid + if (idid .lt. 1) then + block + character(len=100) :: wbuf + write(wbuf, '(A,ES12.5,A,I0)') & + 'calculate_equil: r=', r1, ' idid=', idid + call log_warning(trim(wbuf)) + end block + end if u(i) = u0 info(1) = 1 @@ -177,12 +185,11 @@ subroutine dudr(r, u, du) subroutine write_equil - use config_m, only: output_path, hdf5_output, fstatus use IO_collection_m, only: write_profile implicit none - if(fstatus == 1) write(*,*) 'Status: Writing equilibrium' + call log_info('Writing equilibrium') call write_profile(equil_grid, B0z, size(equil_grid), 'backs/B0z', & 'z component of equilibrium magnetic field', 'G') diff --git a/KIM/src/background_equilibrium/species_mod.f90 b/KIM/src/background_equilibrium/species_mod.f90 index e560da1c..3984910b 100644 --- a/KIM/src/background_equilibrium/species_mod.f90 +++ b/KIM/src/background_equilibrium/species_mod.f90 @@ -91,6 +91,7 @@ module species_m subroutine init_plasma(plasma_in) use config_m, only: read_species_from_namelist, plasma_type + use logger_m, only: log_error implicit none @@ -105,8 +106,7 @@ subroutine init_plasma(plasma_in) else if (plasma_type == 'D') then call init_deuterium_plasma(plasma_in) else - print *, "Error: Unknown plasma type. Please choose 'H' or 'D'." - stop + call log_error("Unknown plasma type. Please choose 'H' or 'D'.") end if !call init_deuterium_plasma(plasma_in) end if @@ -146,10 +146,11 @@ subroutine read_species_from_nml(plasma_in) read(unit=77, nml=KIM_species) close(unit=77) - print *, "Reading species from namelist:" - print *, "Number of ion species: ", number_of_ion_species - print *, "Mass numbers: ", ai(1:number_of_ion_species) - print *, "Charge numbers: ", zi(1:number_of_ion_species) + block + use logger_m, only: log_info, fmt_val + call log_info('Reading species from namelist') + call log_info(fmt_val('Number of ion species', number_of_ion_species)) + end block do i = 1, number_of_ion_species plasma_in%spec(i)%Aspec = ai(i) @@ -542,11 +543,10 @@ subroutine calculate_plasma_backs(plasma_in) end do if (rescale_density .eqv. .true.) then - print *, " " - print *, " ! ! ! " - print *, " ! ! ! Rescaling density (after collision frequency calculation) ! ! !" - print *, " ! ! ! " - print *, " " + block + use logger_m, only: log_warning + call log_warning('Rescaling density (after collision frequency calculation)') + end block do sp = 0, plasma_in%n_species-1 do i = 1, plasma_in%grid_size ! density rescaling only affects lambda_D (in A_1 the rescaling cancels out) @@ -920,24 +920,31 @@ subroutine check_quasineutrality(plasma_in) logical :: check_succeeded = .true. integer :: i, sp - print *, "Checking quasineutrality..." - do i = 1, size(plasma_in%spec(0)%n) - n_zero = plasma_in%spec(0)%n(i) - do sp=1, number_of_ion_species - n_zero = n_zero - plasma_in%spec(sp)%Zspec * plasma_in%spec(sp)%n(i) + block + use logger_m, only: log_info, log_warning + character(len=120) :: qbuf + + call log_info('Checking quasineutrality...') + do i = 1, size(plasma_in%spec(0)%n) + n_zero = plasma_in%spec(0)%n(i) + do sp=1, number_of_ion_species + n_zero = n_zero - plasma_in%spec(sp)%Zspec * plasma_in%spec(sp)%n(i) + end do + if (.not. (abs(n_zero) <1.0)) then + check_succeeded = .false. + write(qbuf, '(A,ES12.5,A,ES12.5)') & + 'Quasineutrality check failed for r = ', & + plasma_in%r_grid(i), ' with n_zero = ', n_zero + call log_warning(trim(qbuf)) + end if end do - if (.not. (abs(n_zero) <1.0)) then - check_succeeded = .false. - print *, "Warning: quasineutality check failed for r = ", plasma_in%r_grid(i), & - " with n_zero = ", n_zero - end if - end do - if (check_succeeded) then - print *, "Quasineutrality check succeeded." - else - print *, "Quasineutrality check failed. Please check your profiles." - end if + if (check_succeeded) then + call log_info('Quasineutrality check succeeded.') + else + call log_warning('Quasineutrality check failed. Please check your profiles.') + end if + end block end subroutine @@ -1168,7 +1175,8 @@ end subroutine deallocate_plasma_derived subroutine read_from_text - use config_m, only: number_of_ion_species, profile_location, fstatus + use config_m, only: number_of_ion_species, profile_location + use logger_m, only: log_info, log_error use KIM_kinds_m, only: dp use setup_m, only: set_profiles_constant use grid_m, only: r_plas @@ -1181,7 +1189,7 @@ subroutine read_from_text integer :: total_Z real(dp) :: r_temp - if (fstatus == 1) write(*,*) 'Status: Reading profiles from text files' + call log_info('Reading profiles from text files') ! find profile length plasma%grid_size = 0 @@ -1200,7 +1208,7 @@ subroutine read_from_text ierr = 0 if (.not. allocated(plasma%r_grid)) allocate(plasma%r_grid(plasma%grid_size), stat=ierr) - if (ierr /= 0) print *, "array: Allocation request denied" + if (ierr /= 0) call log_error('array: Allocation request denied') do sigma = 0, number_of_ion_species allocate(plasma%spec(sigma)%n(plasma%grid_size),& @@ -1254,7 +1262,7 @@ subroutine read_from_text end do if (set_profiles_constant == 1) then - write(*,*) 'Info: Setting profiles to constant values' + call log_info('Setting profiles to constant values') plasma%Er(:) = plasma%Er(1) do sigma = 0, number_of_ion_species plasma%spec(sigma)%n(:) = plasma%spec(sigma)%n(1) @@ -1263,7 +1271,7 @@ subroutine read_from_text end if if (set_profiles_constant == 2) then - write(*,*) 'Info: Setting profiles to constant values' + call log_info('Setting profiles to constant values (T only)') do sigma = 0, number_of_ion_species plasma%spec(sigma)%T(:) = plasma%spec(sigma)%T(1) end do @@ -1272,7 +1280,7 @@ subroutine read_from_text ! Validate units - density should be in CGS (1/cm^3), typically 10^12 to 10^15 call validate_profile_units(plasma) - if (fstatus == 1) write(*,*) 'Status: Finished reading profiles from text files' + call log_info('Finished reading profiles from text files') end subroutine @@ -1282,87 +1290,52 @@ subroutine validate_profile_units(plasma) !> Temperature: eV, typically 10 to 20000 eV !> Also checks q vs m_mode sign consistency use setup_m, only: m_mode + use logger_m, only: log_error, log_warning, fmt_val implicit none type(plasma_t), intent(in) :: plasma real(dp) :: n_max, T_max, q_mean integer :: sigma + character(len=120) :: vbuf ! Check electron density n_max = maxval(plasma%spec(0)%n) if (n_max > 1.0d17) then - write(*,*) '' - write(*,*) '╔══════════════════════════════════════════════════════════════════╗' - write(*,*) '║ ERROR: DENSITY UNITS ║' - write(*,*) '╠══════════════════════════════════════════════════════════════════╣' - write(*,*) '║ Density appears to be in SI units (1/m^3) instead of CGS! ║' - write(*,*) '╚══════════════════════════════════════════════════════════════════╝' - write(*,*) '' - write(*,*) ' Maximum density found: ', n_max, ' 1/cm^3' - write(*,*) ' Expected range (CGS): 1e12 to 1e15 1/cm^3' - write(*,*) '' - write(*,*) ' Your density values suggest SI units (1/m^3).' - write(*,*) ' Please convert to CGS by dividing by 1e6.' - write(*,*) '' - write(*,*) ' Example: n_SI = 4.67e19 1/m^3 --> n_CGS = 4.67e13 1/cm^3' - write(*,*) '' - stop 1 + call log_error( & + 'Density appears to be in SI units (1/m^3) instead of CGS! ' // & + 'Please convert to CGS by dividing by 1e6. ' // & + 'Example: n_SI = 4.67e19 1/m^3 --> n_CGS = 4.67e13 1/cm^3') else if (n_max < 1.0d10) then - write(*,*) '' - write(*,*) 'WARNING: Density values appear very low' - write(*,*) ' Maximum density: ', n_max, ' 1/cm^3' - write(*,*) ' Expected range: 1e12 to 1e15 1/cm^3' - write(*,*) '' + call log_warning(trim(fmt_val( & + 'Density values appear very low. Max density', n_max, '1/cm^3'))) end if ! Check temperatures (should be in eV) - ! Note: spec array is 0:n_species-1 but read_profiles uses number_of_ion_species from config do sigma = 0, min(plasma%n_species, size(plasma%spec)-1) if (.not. allocated(plasma%spec(sigma)%T)) cycle T_max = maxval(plasma%spec(sigma)%T) if (T_max > 1.0d6) then - write(*,*) '' - write(*,*) 'WARNING: Temperature appears very high' - write(*,*) ' Species ', sigma, ' max T = ', T_max, ' eV' - write(*,*) ' Expected range: 10 to 20000 eV' - write(*,*) ' Check if temperature is in Kelvin instead of eV' - write(*,*) '' + write(vbuf, '(A,I0,A,ES12.5,A)') & + 'Temperature appears very high: species ', sigma, & + ' max T = ', T_max, ' eV. Check if in Kelvin instead of eV' + call log_warning(trim(vbuf)) end if end do ! Check q vs m_mode sign consistency - ! For positive q, m should be negative (and vice versa) for proper helicity if (allocated(plasma%q) .and. size(plasma%q) > 0) then q_mean = sum(plasma%q) / size(plasma%q) if (q_mean > 0.0_dp .and. m_mode > 0) then - write(*,*) '' - write(*,*) '╔══════════════════════════════════════════════════════════════════╗' - write(*,*) '║ WARNING: q AND m_mode SIGN MISMATCH ║' - write(*,*) '╠══════════════════════════════════════════════════════════════════╣' - write(*,*) '║ Safety factor q > 0 typically requires m < 0 for resonance ║' - write(*,*) '╚══════════════════════════════════════════════════════════════════╝' - write(*,*) '' - write(*,*) ' Mean safety factor q = ', q_mean - write(*,*) ' Poloidal mode number m = ', m_mode - write(*,*) '' - write(*,*) ' No resonant surfaces will be found with this configuration.' - write(*,*) ' For resonant behavior, use m = ', -abs(m_mode) - write(*,*) '' + write(vbuf, '(A,ES12.5,A,I0,A,I0)') & + 'q and m_mode sign mismatch: q_mean = ', q_mean, & + ', m = ', m_mode, '. For resonance, use m = ', -abs(m_mode) + call log_warning(trim(vbuf)) else if (q_mean < 0.0_dp .and. m_mode < 0) then - write(*,*) '' - write(*,*) '╔══════════════════════════════════════════════════════════════════╗' - write(*,*) '║ WARNING: q AND m_mode SIGN MISMATCH ║' - write(*,*) '╠══════════════════════════════════════════════════════════════════╣' - write(*,*) '║ Safety factor q < 0 typically requires m > 0 for resonance ║' - write(*,*) '╚══════════════════════════════════════════════════════════════════╝' - write(*,*) '' - write(*,*) ' Mean safety factor q = ', q_mean - write(*,*) ' Poloidal mode number m = ', m_mode - write(*,*) '' - write(*,*) ' No resonant surfaces will be found with this configuration.' - write(*,*) ' For resonant behavior, use m = ', abs(m_mode) - write(*,*) '' + write(vbuf, '(A,ES12.5,A,I0,A,I0)') & + 'q and m_mode sign mismatch: q_mean = ', q_mean, & + ', m = ', m_mode, '. For resonance, use m = ', abs(m_mode) + call log_warning(trim(vbuf)) end if end if @@ -1370,11 +1343,11 @@ end subroutine validate_profile_units subroutine read_from_hdf5 - use config_m, only: fstatus + use logger_m, only: log_info implicit none - if (fstatus == 1) write(*,*) 'Status: Reading profiles from hdf5 file' + call log_info('Reading profiles from hdf5 file') end subroutine @@ -1426,8 +1399,10 @@ subroutine read_and_interpolate_profile(filename, target_grid, profile_out, n_ta close(iunit) if (n_src == 0) then - write(*,*) 'ERROR: Empty profile file: ', trim(filename) - stop 1 + block + use logger_m, only: log_error + call log_error('Empty profile file: ' // trim(filename)) + end block end if ! Allocate and read source data @@ -1453,9 +1428,19 @@ subroutine read_and_interpolate_profile(filename, target_grid, profile_out, n_ta profile_out(1:n_target) = val_src(1:n_target) else ! Grids don't match - interpolate - write(*,*) 'Note: Interpolating ', trim(filename), ' to match grid' - write(*,*) ' Source: ', n_src, ' points, r = [', r_src(1), ', ', r_src(n_src), ']' - write(*,*) ' Target: ', n_target, ' points, r = [', target_grid(1), ', ', target_grid(n_target), ']' + block + use logger_m, only: log_info + character(len=200) :: ibuf + call log_info('Interpolating ' // trim(filename) // ' to match grid') + write(ibuf, '(A,I0,A,ES12.5,A,ES12.5,A)') & + ' Source: ', n_src, ' points, r = [', r_src(1), & + ', ', r_src(n_src), ']' + call log_info(trim(ibuf)) + write(ibuf, '(A,I0,A,ES12.5,A,ES12.5,A)') & + ' Target: ', n_target, ' points, r = [', target_grid(1), & + ', ', target_grid(n_target), ']' + call log_info(trim(ibuf)) + end block do i = 1, n_target r_temp = target_grid(i) diff --git a/KIM/src/electromagnetic/electromagnetic_solver.f90 b/KIM/src/electromagnetic/electromagnetic_solver.f90 index 95cef097..20c0a329 100644 --- a/KIM/src/electromagnetic/electromagnetic_solver.f90 +++ b/KIM/src/electromagnetic/electromagnetic_solver.f90 @@ -33,7 +33,10 @@ subroutine init_electromagnetic(this) call set_plasma_quantities(plasma) call interpolate_equil(rg_grid%xb) - print *, "..."//trim(this%run_type)//" model initialized." + block + use logger_m, only: log_info + call log_info('...' // trim(this%run_type) // ' model initialized.') + end block end subroutine @@ -44,7 +47,7 @@ subroutine run_electromagnetic(this) use grid_m, only: xl_grid, calc_mass_matrix, M_mat, theta_integration use IO_collection_m, only: write_complex_profile_abs use poisson_solver_m, only: prepare_Laplace_matrix - use config_m, only: output_path, collision_model, fstatus, fdebug + use config_m, only: output_path, collision_model use fields_m, only: EBdat, postprocess_electric_field, & calculate_charge_density, calculate_current_density use ampere_matrices_m, only: interpolate_equil_to_xl @@ -52,11 +55,13 @@ subroutine run_electromagnetic(this) use constants_m, only: pi, sol, com_unit use KIM_kinds_m, only: dp use species_m, only: plasma + use logger_m, only: log_info, log_debug, log_error implicit none class(electromagnetic_t), intent(inout) :: this + character(len=200) :: lbuf type(kernel_spl_t) :: kernel_rho_phi_llp type(kernel_spl_t) :: kernel_rho_B_llp type(kernel_spl_t) :: kernel_j_phi_llp @@ -86,10 +91,8 @@ subroutine run_electromagnetic(this) ! Validate collision model if (trim(collision_model) /= "FokkerPlanck") then - print *, "Error: electromagnetic run type requires & - &collision_model = FokkerPlanck" - print *, "Current collision_model: ", trim(collision_model) - error stop + call log_error('Electromagnetic run type requires ' // & + 'collision_model = FokkerPlanck, got: ' // trim(collision_model)) end if ! Validate boundary condition type @@ -97,9 +100,9 @@ subroutine run_electromagnetic(this) case (0, 2, 3) ! supported: 0/2 = Dirichlet Phi=0, 3 = zero-misalignment case default - print *, "Error: electromagnetic solver does not & - &support bc_type =", bc_type - error stop + write(lbuf, '(A,I0)') & + 'Electromagnetic solver does not support bc_type = ', bc_type + call log_error(trim(lbuf)) end select N = xl_grid%npts_b @@ -114,7 +117,7 @@ subroutine run_electromagnetic(this) ! Fill kernels call date_and_time(date, time, zone, values) - write(*,*) "Start filling kernel at ", date, " ", time, " ..." + call log_info('Start filling kernel at ' // trim(date) // ' ' // trim(time)) select case (trim(theta_integration)) case ("GaussLegendre") @@ -205,10 +208,7 @@ subroutine run_electromagnetic(this) b_block(N+1) = cmplx(0.0d0, 0.0d0, dp) if (abs(alpha(N)) < 1.0d-30) then - print *, "Error: alpha(r) ~ 0 at right boundary; & - &cannot set A_par BC" - print *, "|alpha(N)| =", abs(alpha(N)) - error stop + call log_error('alpha(r) ~ 0 at right boundary; cannot set A_par BC') end if A_block(2*N, :) = cmplx(0.0d0, 0.0d0, dp) A_block(2*N, 2*N) = cmplx(1.0d0, 0.0d0, dp) @@ -219,44 +219,53 @@ subroutine run_electromagnetic(this) call apply_zero_misalignment_bc(A_block, b_block, N, Br_boundary) end if - if (fstatus >= 1) write(*,*) & - 'Status: solving coupled Poisson-Ampere for & - &(Phi, A_par) (2N =', 2*N, ')' + write(lbuf, '(A,I0,A)') & + 'Solving coupled Poisson-Ampere for (Phi, A_par) (2N = ', 2*N, ')' + call log_info(trim(lbuf)) ! Diagnostics: boundary conditions before solve - write(*,*) '--- EM solver diagnostics (before solve) ---' - write(*,*) ' N (grid points) = ', N - write(*,*) ' alpha(1) = ', alpha(1) - write(*,*) ' alpha(N) = ', alpha(N) - write(*,*) ' Br_boundary = ', Br_boundary - write(*,*) ' Br_bnd/alpha(N) = ', Br_boundary / alpha(N) - write(*,*) ' A_block(1,1) = ', A_block(1,1) - write(*,*) ' A_block(N,N) = ', A_block(N,N) - write(*,*) ' A_block(N+1,N+1) = ', A_block(N+1,N+1) - write(*,*) ' A_block(2N,2N) = ', A_block(2*N,2*N) - write(*,*) ' b_block(1) = ', b_block(1), ' (Phi left BC)' - write(*,*) ' b_block(N) = ', b_block(N), ' (Phi right BC)' - write(*,*) ' b_block(N+1) = ', b_block(N+1), ' (Apar left BC)' - write(*,*) ' b_block(2N) = ', b_block(2*N), ' (Apar right BC)' + call log_debug('--- EM solver diagnostics (before solve) ---') + write(lbuf, '(A,I0)') ' N (grid points) = ', N + call log_debug(trim(lbuf)) + write(lbuf, '(A,2ES15.8)') ' alpha(1) = ', real(alpha(1)), aimag(alpha(1)) + call log_debug(trim(lbuf)) + write(lbuf, '(A,2ES15.8)') ' alpha(N) = ', real(alpha(N)), aimag(alpha(N)) + call log_debug(trim(lbuf)) + write(lbuf, '(A,2ES15.8)') ' Br_boundary = ', real(Br_boundary), aimag(Br_boundary) + call log_debug(trim(lbuf)) + write(lbuf, '(A,2ES15.8)') ' Br_bnd/alpha(N) = ', & + real(Br_boundary / alpha(N)), aimag(Br_boundary / alpha(N)) + call log_debug(trim(lbuf)) ! Solve using LAPACK ZGESV (dense direct solver, fast for 2N ~ 400) allocate(ipiv(2*N)) call zgesv(2*N, 1, A_block, 2*N, ipiv, b_block, 2*N, lapack_info) if (lapack_info /= 0) then - write(*,*) 'Error: ZGESV failed with info = ', lapack_info - error stop + write(lbuf, '(A,I0)') 'ZGESV failed with info = ', lapack_info + call log_error(trim(lbuf)) end if - write(*,*) ' ZGESV solve succeeded (2N =', 2*N, ')' + write(lbuf, '(A,I0,A)') ' ZGESV solve succeeded (2N = ', 2*N, ')' + call log_info(trim(lbuf)) deallocate(ipiv) ! Diagnostics: solution at boundaries after solve - write(*,*) '--- EM solver diagnostics (after solve) ---' - write(*,*) ' Phi(1) = ', b_block(1), ' (should be 0)' - write(*,*) ' Phi(N) = ', b_block(N), ' (should be 0)' - write(*,*) ' Apar(1) = ', b_block(N+1), ' (should be 0)' - write(*,*) ' Apar(N) = ', b_block(2*N), ' (should be Br_bnd/alpha(N))' - write(*,*) ' max|Phi| = ', maxval(abs(b_block(1:N))) - write(*,*) ' max|Apar|= ', maxval(abs(b_block(N+1:2*N))) + call log_debug('--- EM solver diagnostics (after solve) ---') + write(lbuf, '(A,2ES15.8,A)') ' Phi(1) = ', & + real(b_block(1)), aimag(b_block(1)), ' (should be 0)' + call log_debug(trim(lbuf)) + write(lbuf, '(A,2ES15.8,A)') ' Phi(N) = ', & + real(b_block(N)), aimag(b_block(N)), ' (should be 0)' + call log_debug(trim(lbuf)) + write(lbuf, '(A,2ES15.8,A)') ' Apar(1) = ', & + real(b_block(N+1)), aimag(b_block(N+1)), ' (should be 0)' + call log_debug(trim(lbuf)) + write(lbuf, '(A,2ES15.8,A)') ' Apar(N) = ', & + real(b_block(2*N)), aimag(b_block(2*N)), ' (should be Br_bnd/alpha(N))' + call log_debug(trim(lbuf)) + write(lbuf, '(A,ES15.8)') ' max|Phi| = ', maxval(abs(b_block(1:N))) + call log_debug(trim(lbuf)) + write(lbuf, '(A,ES15.8)') ' max|Apar|= ', maxval(abs(b_block(N+1:2*N))) + call log_debug(trim(lbuf)) ! Extract solution: solve gives (Phi, A_par), recover Br = alpha * A_par allocate(EBdat%Phi(N), EBdat%Apar(N), EBdat%Br(N), EBdat%r_grid(N)) @@ -345,11 +354,11 @@ subroutine apply_zero_misalignment_bc(A_block, b_block, N, Br_boundary) B0_right = sum(coef(0,:) * plasma%B0(ibeg:iend)) if (abs(B0_right * kp_right) < 1.0d-30) then - print *, "Error: B0*kp ~ 0 at right boundary; & - &cannot compute zero-misalignment BC" - print *, "B0_right =", B0_right, & - " kp_right =", kp_right - error stop + block + use logger_m, only: log_error + call log_error('B0*kp ~ 0 at right boundary; ' // & + 'cannot compute zero-misalignment BC') + end block end if phi_right = -com_unit * Er_right * Br_boundary & / (B0_right * kp_right) diff --git a/KIM/src/electrostatic_poisson/solve_poisson.f90 b/KIM/src/electrostatic_poisson/solve_poisson.f90 index 995abbe0..51fb28c5 100644 --- a/KIM/src/electrostatic_poisson/solve_poisson.f90 +++ b/KIM/src/electrostatic_poisson/solve_poisson.f90 @@ -8,9 +8,9 @@ module poisson_solver_m ! using sparse matrix solver subroutine solve_poisson(K_rho_phi, K_rho_B, phi_sol) - use config_m, only: fstatus, fdebug + use config_m, only: data_verbosity, output_path + use logger_m, only: log_info, log_trace use sparse_mod, only: sp2fullComplex, sparse_solveComplex_b1, sparse_solve_method, sparse_talk - use config_m, only: output_path use constants_m, only: pi use grid_m, only: xl_grid, calc_mass_matrix, M_mat use setup_m, only: type_br_field @@ -31,8 +31,8 @@ subroutine solve_poisson(K_rho_phi, K_rho_B, phi_sol) integer :: i, j integer :: sparse_solver_option - if (fstatus >= 1) write(*,*) 'Status: solve poisson equation' - if (fdebug < 2) sparse_talk = .false. ! turn off sparse solver output for low fdebug + call log_info('Solving Poisson equation') + sparse_talk = .false. allocate(A_mat(xl_grid%npts_b, xl_grid%npts_b)) @@ -48,7 +48,7 @@ subroutine solve_poisson(K_rho_phi, K_rho_B, phi_sol) A_mat = (A_mat + 4.0d0 * pi * K_rho_phi) - if (fdebug == 3) then + if (data_verbosity >= 3) then call write_A_matrix_sparse_check_to_file end if @@ -77,7 +77,7 @@ subroutine write_A_matrix_sparse_check_to_file complex(dp), dimension(:,:), allocatable :: A_sparse_check ! A matrix reconfigured from sparse matrix - write(*,*) 'Debug: writing A matrix after sparse' + call log_trace('Writing A matrix after sparse') call sp2fullComplex(irow, pcol, A_nz, nrow, ncol, A_sparse_check) open(unit=77, file=trim(output_path)//'kernel/A_sparse_check_re.dat') open(unit=78, file=trim(output_path)//'kernel/A_sparse_check_im.dat') @@ -165,7 +165,7 @@ subroutine prepare_Laplace_matrix(A_mat) subroutine impose_bc_on_matrix_and_rhs(A_mat, b_vec, K_rho_phi, K_rho_B) - use config_m, only: fdebug + use logger_m, only: log_debug use grid_m, only: xl_grid use KIM_kinds_m, only: dp use setup_m, only: bc_type @@ -177,6 +177,7 @@ subroutine impose_bc_on_matrix_and_rhs(A_mat, b_vec, K_rho_phi, K_rho_B) complex(dp), intent(inout) :: A_mat(:,:), b_vec(:) complex(dp), intent(in) :: K_rho_phi(:,:), K_rho_B(:,:) complex(dp) :: phi_boundary_left, phi_boundary_right + character(len=200) :: buf if(bc_type == 3) then ! zero misalignment field at boundaries @@ -185,8 +186,12 @@ subroutine impose_bc_on_matrix_and_rhs(A_mat, b_vec, K_rho_phi, K_rho_B) phi_boundary_left = - EBdat%phi_aligned(1) phi_boundary_right = - EBdat%phi_aligned(xl_grid%npts_b) - if (fdebug == 1) print *, "Imposing BC of zero misalignment field: Phi_left = ", & - phi_boundary_left, ", Phi_right = ", phi_boundary_right + write(buf, '(A,2ES15.8,A,2ES15.8)') & + 'Imposing BC of zero misalignment field: Phi_left = ', & + real(phi_boundary_left), aimag(phi_boundary_left), & + ', Phi_right = ', & + real(phi_boundary_right), aimag(phi_boundary_right) + call log_debug(trim(buf)) b_vec(2:xl_grid%npts_b-1) = b_vec(2:xl_grid%npts_b-1) & - A_mat(2:xl_grid%npts_b-1,1) * phi_boundary_left & diff --git a/KIM/src/general/config_display.f90 b/KIM/src/general/config_display.f90 index d1a16f66..4121f0a0 100644 --- a/KIM/src/general/config_display.f90 +++ b/KIM/src/general/config_display.f90 @@ -116,9 +116,8 @@ subroutine display_kim_configuration() call print_config_line('Output Path', trim(output_path), width) call print_bool_line('HDF5 Input', hdf5_input, width) call print_bool_line('HDF5 Output', hdf5_output, width) - call print_config_line('Debug Level', get_debug_string(fdebug), width) - call print_config_line('Status Level', get_status_string(fstatus), width) - call print_config_line('Diagnostics Level', get_status_string(fdiagnostics), width) + call print_config_line('Log Level', get_log_level_string(log_level), width) + call print_config_line('Data Verbosity', get_data_verbosity_string(data_verbosity), width) ! Display Physics Configuration call print_section_header('PHYSICS CONFIGURATION', width) @@ -335,43 +334,53 @@ end subroutine print_species_table ! Helper functions - function get_debug_string(level) result(str) + function get_log_level_string(level) result(str) + use logger_m, only: LVL_SILENT, LVL_RESULT, LVL_ERROR, LVL_WARNING, & + LVL_INFO, LVL_DEBUG, LVL_TRACE implicit none integer, intent(in) :: level character(len=20) :: str select case(level) - case(0) - str = 'Off' - case(1) - str = 'Basic' - case(2) - str = 'Detailed' - case(3) - str = 'Verbose' + case(LVL_SILENT) + str = 'Silent' + case(LVL_RESULT) + str = 'Result' + case(LVL_ERROR) + str = 'Error' + case(LVL_WARNING) + str = 'Warning' + case(LVL_INFO) + str = 'Info' + case(LVL_DEBUG) + str = 'Debug' + case(LVL_TRACE) + str = 'Trace' case default write(str, '(A,I0)') 'Level ', level end select - end function get_debug_string + end function get_log_level_string - function get_status_string(level) result(str) + function get_data_verbosity_string(level) result(str) implicit none integer, intent(in) :: level character(len=20) :: str select case(level) case(0) - str = 'Silent' + str = 'Minimal' case(1) - str = 'Normal' + str = 'Standard' case(2) - str = 'Verbose' + str = 'Detailed' + case(3) + str = 'Full' case default write(str, '(A,I0)') 'Level ', level end select - end function get_status_string + end function get_data_verbosity_string function get_grid_type(gtype) result(str) implicit none diff --git a/KIM/src/grid/gengrid.f90 b/KIM/src/grid/gengrid.f90 index 0a967e6b..ed5d46fa 100644 --- a/KIM/src/grid/gengrid.f90 +++ b/KIM/src/grid/gengrid.f90 @@ -3,7 +3,7 @@ subroutine generate_grids use grid_m, only: rg_grid, xl_grid, rg_space_dim, l_space_dim, grid_spacing_rg, grid_spacing_xl, & r_min, r_plas use species_m, only: plasma - use config_m, only: fdebug + use logger_m, only: log_debug, fmt_val use IO_collection_m, only: write_profile implicit none @@ -34,13 +34,16 @@ subroutine generate_grids call xl_grid%grid_generate() end select - if (fdebug == 1) then - write(*,*) " Generated Grid number of points:" - write(*,*) ' Nrg = ', rg_grid%npts_b, ", Nl = ", xl_grid%npts_b - write(*,*) " rg grid h = ", minval(rg_grid%xb(2:rg_grid%npts_b) - rg_grid%xb(1:rg_grid%npts_b-1)) - write(*,*) " xl grid h = ", minval(xl_grid%xb(2:xl_grid%npts_b) - xl_grid%xb(1:xl_grid%npts_b-1)) - write(*,*) '' - end if + block + character(len=100) :: gbuf + call log_debug('Generated Grid number of points:') + write(gbuf, '(A,I0,A,I0)') ' Nrg = ', rg_grid%npts_b, ', Nl = ', xl_grid%npts_b + call log_debug(trim(gbuf)) + call log_debug(trim(fmt_val(' rg grid h', & + minval(rg_grid%xb(2:rg_grid%npts_b) - rg_grid%xb(1:rg_grid%npts_b-1)), 'cm'))) + call log_debug(trim(fmt_val(' xl grid h', & + minval(xl_grid%xb(2:xl_grid%npts_b) - xl_grid%xb(1:xl_grid%npts_b-1)), 'cm'))) + end block call write_profile(xl_grid%xb, xl_grid%xb, xl_grid%npts_b, 'grid/'//trim(xl_grid%name)//'_xb', & 'Cell boundary points of grid', 'cm') diff --git a/KIM/src/grid/grid_mod.f90 b/KIM/src/grid/grid_mod.f90 index 21c4f9c3..bc29e5dd 100644 --- a/KIM/src/grid/grid_mod.f90 +++ b/KIM/src/grid/grid_mod.f90 @@ -194,7 +194,8 @@ subroutine grid_init(this, npts, min_val, max_val, name) subroutine grid_generate(this) use kim_resonances_m, only: r_res, index_rg_res - use config_m, only: fdebug, output_path + use config_m, only: output_path + use logger_m, only: log_error implicit none @@ -229,8 +230,7 @@ subroutine grid_generate(this) call binsrc(abs(this%xb), 1, this%npts_b, abs(r_res), index_rg_res) if(npoi_der .gt. this%npts_c) then - write(*,*) '! Error : not enough grid points for derivatives' - stop + call log_error('Not enough grid points for derivatives') endif if (allocated(this%deriv_coef)) deallocate(this%deriv_coef) @@ -271,7 +271,8 @@ end subroutine grid_generate subroutine grid_generate_equidistant(this) use kim_resonances_m, only: r_res, index_rg_res - use config_m, only: fdebug, output_path + use config_m, only: output_path + use logger_m, only: log_debug, log_error, fmt_val implicit none @@ -286,7 +287,7 @@ subroutine grid_generate_equidistant(this) allocate(this%xb(this%npts_b), this%xc(this%npts_c)) h = (this%max_val - this%min_val) / this%npts_b - print *, "Equidistant grid spacing h = ", h + call log_debug(trim(fmt_val('Equidistant grid spacing h', h, 'cm'))) this%xb(1) = this%min_val do ipoib=2, this%npts_b @@ -302,8 +303,7 @@ subroutine grid_generate_equidistant(this) call binsrc(abs(this%xb), 1, this%npts_b, abs(r_res), index_rg_res) if(npoi_der .gt. this%npts_c) then - write(*,*) '! Error : not enough grid points for derivatives' - stop + call log_error('Not enough grid points for derivatives') endif if (allocated(this%deriv_coef)) deallocate(this%deriv_coef) diff --git a/KIM/src/kernels/kernel.f90 b/KIM/src/kernels/kernel.f90 index b7417eb7..61c31f60 100644 --- a/KIM/src/kernels/kernel.f90 +++ b/KIM/src/kernels/kernel.f90 @@ -77,7 +77,7 @@ subroutine compute_cc_prefactors use FP_kernel_plasma_prefacs_m, only: FP_G1_rho_phi, FP_G2_rho_phi, FP_G3_rho_phi, & FP_G1_rho_B, FP_G2_rho_B, FP_G3_rho_B, FP_G1_j_phi, FP_G2_j_phi, FP_G3_j_phi, & FP_G1_j_B, FP_G2_j_B, FP_G3_j_B, FP_G0_rho_phi - use config_m, only: fdiagnostics + use config_m, only: data_verbosity use setup_m, only: mphi_max implicit none @@ -126,7 +126,7 @@ subroutine compute_cc_prefactors pref_ready = .true. - if (fdiagnostics == 3) then + if (data_verbosity >= 3) then call write_cc_prefactors end if @@ -202,6 +202,7 @@ subroutine Krook_fill_kernel_phi(K_rho_phi_llp, K_rho_B_llp) use KIM_kinds_m, only: dp use integrals_gauss_m, only: gauss_config_t, init_gauss_int use grid_m, only: gauss_int_nodes_Ntheta, gauss_int_nodes_Nx, gauss_int_nodes_Nxp + use logger_m, only: log_info, log_error implicit none @@ -216,7 +217,7 @@ subroutine Krook_fill_kernel_phi(K_rho_phi_llp, K_rho_B_llp) gauss_conf%Ntheta = gauss_int_nodes_Ntheta call init_gauss_int(gauss_conf) - write(*,*) 'Filling Krook collision kernels...' + call log_info('Filling Krook collision kernels...') !$omp parallel do collapse(1) private(l,lp, k_rho_phi, k_rho_B) do l = 1, K_rho_phi_llp%npts_l @@ -227,14 +228,10 @@ subroutine Krook_fill_kernel_phi(K_rho_phi_llp, K_rho_B_llp) K_rho_B_llp%Kllp(l, lp) = k_rho_B if (isnan(real(k_rho_phi))) then - print *, "semi analytical kernel_llp is NaN for l = ", l, " lp = ", lp - print *, "semi analytical kernel_llp = ", k_rho_phi - stop + call log_error('Semi analytical kernel_llp is NaN') end if if (isnan(real(k_rho_B))) then - print *, "semi analytical k_rho_B is NaN for l = ", l, " lp = ", lp - print *, "semi analytical k_rho_B = ", k_rho_B - stop + call log_error('Semi analytical k_rho_B is NaN') end if K_rho_phi_llp%Kllp(lp, l) = K_rho_phi_llp%Kllp(l, lp) @@ -244,16 +241,28 @@ subroutine Krook_fill_kernel_phi(K_rho_phi_llp, K_rho_B_llp) end do !$omp end parallel do - write(*,*) '======== Kernel Distance Diagnostics (Krook) ========' - write(*,'(A,F12.6)') ' Maximum |xl - xlp| distance: ', max_distance_xl_xlp - write(*,'(A,I6,A,I6)') ' Occurred at l = ', max_dist_l, ', lp = ', max_dist_lp - write(*,'(A,F12.6)') ' Minimum |xl - xlp| distance: ', min_distance_xl_xlp - write(*,'(A,I6,A,I6)') ' Occurred at l = ', min_dist_l, ', lp = ', min_dist_lp - write(*,'(A,I6)') ' Maximum index distance |l - lp|: ', max_index_distance - write(*,'(A,I6,A,I6)') ' Occurred at l = ', max_idx_l, ', lp = ', max_idx_lp - write(*,'(A,I6)') ' Minimum index distance |l - lp|: ', min_index_distance - write(*,'(A,I6,A,I6)') ' Occurred at l = ', min_idx_l, ', lp = ', min_idx_lp - write(*,*) '====================================================' + block + use logger_m, only: log_debug + character(len=100) :: dbuf + call log_debug('======== Kernel Distance Diagnostics (Krook) ========') + write(dbuf, '(A,F12.6)') ' Maximum |xl - xlp| distance: ', max_distance_xl_xlp + call log_debug(trim(dbuf)) + write(dbuf, '(A,I6,A,I6)') ' Occurred at l = ', max_dist_l, ', lp = ', max_dist_lp + call log_debug(trim(dbuf)) + write(dbuf, '(A,F12.6)') ' Minimum |xl - xlp| distance: ', min_distance_xl_xlp + call log_debug(trim(dbuf)) + write(dbuf, '(A,I6,A,I6)') ' Occurred at l = ', min_dist_l, ', lp = ', min_dist_lp + call log_debug(trim(dbuf)) + write(dbuf, '(A,I6)') ' Maximum index distance |l - lp|: ', max_index_distance + call log_debug(trim(dbuf)) + write(dbuf, '(A,I6,A,I6)') ' Occurred at l = ', max_idx_l, ', lp = ', max_idx_lp + call log_debug(trim(dbuf)) + write(dbuf, '(A,I6)') ' Minimum index distance |l - lp|: ', min_index_distance + call log_debug(trim(dbuf)) + write(dbuf, '(A,I6,A,I6)') ' Occurred at l = ', min_idx_l, ', lp = ', min_idx_lp + call log_debug(trim(dbuf)) + call log_debug('====================================================') + end block end subroutine @@ -369,8 +378,9 @@ subroutine FP_fill_kernels(K_rho_phi_llp, K_rho_B_llp, K_j_phi_llp, K_j_B_llp) use grid_m, only: Larmor_skip_factor, gauss_int_nodes_Ntheta, gauss_int_nodes_Nx, gauss_int_nodes_Nxp, & kernel_taper_skip_threshold, rg_grid, xl_grid use species_m, only: plasma - use config_m, only: output_path, artificial_debye_case, fstatus, turn_off_ions, & + use config_m, only: output_path, artificial_debye_case, turn_off_ions, & turn_off_electrons + use logger_m, only: log_info, log_debug, fmt_val implicit none @@ -384,6 +394,7 @@ subroutine FP_fill_kernels(K_rho_phi_llp, K_rho_B_llp, K_j_phi_llp, K_j_B_llp) integer :: sigma integer :: total_iterations, current_iteration integer(kind=8) :: start_count, count_rate, count_max + character(len=100) :: kbuf if (turn_off_electrons .and. turn_off_ions) then error stop 'Cannot turn off both electrons and ions!' @@ -470,23 +481,31 @@ subroutine FP_fill_kernels(K_rho_phi_llp, K_rho_B_llp, K_j_phi_llp, K_j_B_llp) end block end do current_iteration = 0 - if (fstatus >= 1) write(*,*) 'Total band-limited iterations: ', total_iterations - if (fstatus >= 1) write(*,*) 'dmax_global: ', dmax_global, ' cm' - if (fstatus >= 2 .and. artificial_debye_case /= 1) then - write(*,*) '======== Kernel Distance Diagnostics (Fokker-Planck) ========' - write(*,'(A,F12.6)') ' Maximum |xl - xlp| distance: ', max_distance_xl_xlp - write(*,'(A,I6,A,I6)') ' Occurred at l = ', max_dist_l, ', lp = ', max_dist_lp - write(*,'(A,F12.6)') ' Minimum |xl - xlp| distance: ', min_distance_xl_xlp - write(*,'(A,I6,A,I6)') ' Occurred at l = ', min_dist_l, ', lp = ', min_dist_lp - write(*,'(A,I6)') ' Maximum index distance |l - lp|: ', max_index_distance - write(*,'(A,I6,A,I6)') ' Occurred at l = ', max_idx_l, ', lp = ', max_idx_lp - write(*,'(A,I6)') ' Minimum index distance |l - lp|: ', min_index_distance - write(*,'(A,I6,A,I6)') ' Occurred at l = ', min_idx_l, ', lp = ', min_idx_lp - write(*,*) '=============================================================' + call log_info(trim(fmt_val('Total band-limited iterations', total_iterations))) + call log_info(trim(fmt_val('dmax_global', dmax_global, 'cm'))) + if (artificial_debye_case /= 1) then + call log_debug('======== Kernel Distance Diagnostics (Fokker-Planck) ========') + write(kbuf, '(A,F12.6)') ' Maximum |xl - xlp| distance: ', max_distance_xl_xlp + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6,A,I6)') ' Occurred at l = ', max_dist_l, ', lp = ', max_dist_lp + call log_debug(trim(kbuf)) + write(kbuf, '(A,F12.6)') ' Minimum |xl - xlp| distance: ', min_distance_xl_xlp + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6,A,I6)') ' Occurred at l = ', min_dist_l, ', lp = ', min_dist_lp + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6)') ' Maximum index distance |l - lp|: ', max_index_distance + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6,A,I6)') ' Occurred at l = ', max_idx_l, ', lp = ', max_idx_lp + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6)') ' Minimum index distance |l - lp|: ', min_index_distance + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6,A,I6)') ' Occurred at l = ', min_idx_l, ', lp = ', min_idx_lp + call log_debug(trim(kbuf)) + call log_debug('=============================================================') end if - write(*,*) 'Filling Fokker-Planck collision kernels (Gauss)...' + call log_info('Filling Fokker-Planck collision kernels (Gauss)...') call system_clock(start_count, count_rate, count_max) !$omp parallel do schedule(dynamic) default(shared) private(l,lp) @@ -571,21 +590,23 @@ subroutine FP_fill_kernels(K_rho_phi_llp, K_rho_B_llp, K_j_phi_llp, K_j_B_llp) K_j_B_llp%Kllp = K_j_B_llp%Kllp + K_j_B_llp%Kllp_i(:,:,sp) end do - write(*,*) - write(*,*) 'Finished filling kernels.' + call log_info('Finished filling kernels.') end subroutine subroutine check_is_nan(value, name, l, lp) use KIM_kinds_m, only: dp + use logger_m, only: log_error implicit none complex(dp), intent(in) :: value character(len=*), intent(in) :: name integer, intent(in) :: l, lp + character(len=100) :: nbuf if (isnan(real(value))) then - print *, trim(name)//' is NaN for l = ', l, ' lp = ', lp - stop + write(nbuf, '(A,A,I0,A,I0)') & + trim(name), ' is NaN for l = ', l, ' lp = ', lp + call log_error(trim(nbuf)) end if end subroutine check_is_nan @@ -844,9 +865,10 @@ subroutine FP_fill_kernels_flr2_benchmark(K_rho_phi_llp, K_rho_B_llp, K_j_phi_ll use grid_m, only: Larmor_skip_factor, gauss_int_nodes_Ntheta, gauss_int_nodes_Nx, gauss_int_nodes_Nxp, & kernel_taper_skip_threshold, rg_grid, xl_grid use species_m, only: plasma - use config_m, only: output_path, artificial_debye_case, fstatus, turn_off_ions, & + use config_m, only: output_path, artificial_debye_case, turn_off_ions, & turn_off_electrons use constants_m, only: pi + use logger_m, only: log_info, log_debug, fmt_val implicit none @@ -860,6 +882,7 @@ subroutine FP_fill_kernels_flr2_benchmark(K_rho_phi_llp, K_rho_B_llp, K_j_phi_ll integer :: sigma integer :: total_iterations, current_iteration integer(kind=8) :: start_count, count_rate, count_max + character(len=100) :: kbuf if (turn_off_electrons .and. turn_off_ions) then error stop 'Cannot turn off both electrons and ions!' @@ -944,23 +967,31 @@ subroutine FP_fill_kernels_flr2_benchmark(K_rho_phi_llp, K_rho_B_llp, K_j_phi_ll end block end do current_iteration = 0 - if (fstatus >= 1) write(*,*) 'Total band-limited iterations: ', total_iterations - if (fstatus >= 1) write(*,*) 'dmax_global: ', dmax_global, ' cm' - if (fstatus >= 1 .and. artificial_debye_case /= 1) then - write(*,*) '======== Kernel Distance Diagnostics (Fokker-Planck) ========' - write(*,'(A,F12.6)') ' Maximum |xl - xlp| distance: ', max_distance_xl_xlp - write(*,'(A,I6,A,I6)') ' Occurred at l = ', max_dist_l, ', lp = ', max_dist_lp - write(*,'(A,F12.6)') ' Minimum |xl - xlp| distance: ', min_distance_xl_xlp - write(*,'(A,I6,A,I6)') ' Occurred at l = ', min_dist_l, ', lp = ', min_dist_lp - write(*,'(A,I6)') ' Maximum index distance |l - lp|: ', max_index_distance - write(*,'(A,I6,A,I6)') ' Occurred at l = ', max_idx_l, ', lp = ', max_idx_lp - write(*,'(A,I6)') ' Minimum index distance |l - lp|: ', min_index_distance - write(*,'(A,I6,A,I6)') ' Occurred at l = ', min_idx_l, ', lp = ', min_idx_lp - write(*,*) '=============================================================' + call log_info(trim(fmt_val('Total band-limited iterations', total_iterations))) + call log_info(trim(fmt_val('dmax_global', dmax_global, 'cm'))) + if (artificial_debye_case /= 1) then + call log_debug('======== Kernel Distance Diagnostics (Fokker-Planck) ========') + write(kbuf, '(A,F12.6)') ' Maximum |xl - xlp| distance: ', max_distance_xl_xlp + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6,A,I6)') ' Occurred at l = ', max_dist_l, ', lp = ', max_dist_lp + call log_debug(trim(kbuf)) + write(kbuf, '(A,F12.6)') ' Minimum |xl - xlp| distance: ', min_distance_xl_xlp + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6,A,I6)') ' Occurred at l = ', min_dist_l, ', lp = ', min_dist_lp + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6)') ' Maximum index distance |l - lp|: ', max_index_distance + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6,A,I6)') ' Occurred at l = ', max_idx_l, ', lp = ', max_idx_lp + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6)') ' Minimum index distance |l - lp|: ', min_index_distance + call log_debug(trim(kbuf)) + write(kbuf, '(A,I6,A,I6)') ' Occurred at l = ', min_idx_l, ', lp = ', min_idx_lp + call log_debug(trim(kbuf)) + call log_debug('=============================================================') end if - write(*,*) 'Filling Fokker-Planck collision kernels (Gauss)...' + call log_info('Filling Fokker-Planck collision kernels (Gauss)...') call system_clock(start_count, count_rate, count_max) !$omp parallel do schedule(dynamic) default(shared) private(l,lp) @@ -1045,8 +1076,7 @@ subroutine FP_fill_kernels_flr2_benchmark(K_rho_phi_llp, K_rho_B_llp, K_j_phi_ll K_j_B_llp%Kllp = K_j_B_llp%Kllp + K_j_B_llp%Kllp_i(:,:,sp) end do - write(*,*) - write(*,*) 'Finished filling kernels.' + call log_info('Finished filling kernels.') contains diff --git a/KIM/src/math/quadpack_integration_m.f90 b/KIM/src/math/quadpack_integration_m.f90 index b1b139a9..de6aff9d 100644 --- a/KIM/src/math/quadpack_integration_m.f90 +++ b/KIM/src/math/quadpack_integration_m.f90 @@ -201,7 +201,7 @@ subroutine quadpack_integrate_F1(result, epsabs, epsrel, context, & theta_min, theta_max, use_u_substitution) ! Integrate F1 using QUADPACK use grid_m, only: quadpack_key, quadpack_limit, quadpack_algorithm - use config_m, only: fdebug + use logger_m, only: log_debug, log_error, log_warning implicit none real(dp), intent(out) :: result @@ -260,31 +260,27 @@ subroutine quadpack_integrate_F1(result, epsabs, epsrel, context, & result, abserr, neval, ier, limit, lenw, last, iwork_tl, work_tl) end if case default - print *, 'QUADPACK Error: Unsupported algorithm for finite-interval theta integrals: ', trim(quadpack_algorithm) - print *, 'Supported: QAG, QAGS' - error stop 'Invalid QUADPACK algorithm' + call log_error('QUADPACK: Unsupported algorithm: ' // & + trim(quadpack_algorithm) // '. Supported: QAG, QAGS') end select - ! Check for errors (throttle prints to higher debug levels) + ! Check for errors (throttle prints to debug level) if (ier /= 0) then if (ier == 6) then - print *, "QUADPACK Error: Invalid input parameters" - error stop "QUADPACK integration failed" + call log_error('QUADPACK: Invalid input parameters') else - if (fdebug >= 2) then - select case(ier) - case(1) - print *, "QUADPACK Warning: Maximum subdivisions reached" - case(2) - print *, "QUADPACK Warning: Roundoff error detected" - case(3) - print *, "QUADPACK Warning: Extremely bad integrand behavior" - case(4) - print *, "QUADPACK Warning: Roundoff error in extrapolation" - case(5) - print *, "QUADPACK Warning: Divergent integral" - end select - end if + select case(ier) + case(1) + call log_debug('QUADPACK: Maximum subdivisions reached') + case(2) + call log_debug('QUADPACK: Roundoff error detected') + case(3) + call log_debug('QUADPACK: Extremely bad integrand behavior') + case(4) + call log_debug('QUADPACK: Roundoff error in extrapolation') + case(5) + call log_debug('QUADPACK: Divergent integral') + end select end if end if @@ -296,7 +292,7 @@ subroutine quadpack_integrate_F2(result, epsabs, epsrel, context, & theta_min, theta_max, use_u_substitution) ! Integrate F2 using QUADPACK use grid_m, only: quadpack_key, quadpack_limit, quadpack_algorithm - use config_m, only: fdebug + use logger_m, only: log_debug, log_error, log_warning implicit none real(dp), intent(out) :: result @@ -354,31 +350,27 @@ subroutine quadpack_integrate_F2(result, epsabs, epsrel, context, & result, abserr, neval, ier, limit, lenw, last, iwork_tl, work_tl) end if case default - print *, 'QUADPACK Error: Unsupported algorithm for finite-interval theta integrals: ', trim(quadpack_algorithm) - print *, 'Supported: QAG, QAGS' - error stop 'Invalid QUADPACK algorithm' + call log_error('QUADPACK: Unsupported algorithm: ' // & + trim(quadpack_algorithm) // '. Supported: QAG, QAGS') end select ! Check for errors (same as F1) if (ier /= 0) then if (ier == 6) then - print *, "QUADPACK Error: Invalid input parameters" - error stop "QUADPACK integration failed" + call log_error('QUADPACK: Invalid input parameters') else - if (fdebug >= 2) then - select case(ier) - case(1) - print *, "QUADPACK Warning: Maximum subdivisions reached" - case(2) - print *, "QUADPACK Warning: Roundoff error detected" - case(3) - print *, "QUADPACK Warning: Extremely bad integrand behavior" - case(4) - print *, "QUADPACK Warning: Roundoff error in extrapolation" - case(5) - print *, "QUADPACK Warning: Divergent integral" - end select - end if + select case(ier) + case(1) + call log_debug('QUADPACK: Maximum subdivisions reached') + case(2) + call log_debug('QUADPACK: Roundoff error detected') + case(3) + call log_debug('QUADPACK: Extremely bad integrand behavior') + case(4) + call log_debug('QUADPACK: Roundoff error in extrapolation') + case(5) + call log_debug('QUADPACK: Divergent integral') + end select end if end if @@ -390,7 +382,7 @@ subroutine quadpack_integrate_F3(result, epsabs, epsrel, context, & theta_min, theta_max, use_u_substitution) ! Integrate F3 using QUADPACK use grid_m, only: quadpack_key, quadpack_limit, quadpack_algorithm - use config_m, only: fdebug + use logger_m, only: log_debug, log_error, log_warning implicit none real(dp), intent(out) :: result @@ -448,31 +440,27 @@ subroutine quadpack_integrate_F3(result, epsabs, epsrel, context, & result, abserr, neval, ier, limit, lenw, last, iwork_tl, work_tl) end if case default - print *, 'QUADPACK Error: Unsupported algorithm for finite-interval theta integrals: ', trim(quadpack_algorithm) - print *, 'Supported: QAG, QAGS' - error stop 'Invalid QUADPACK algorithm' + call log_error('QUADPACK: Unsupported algorithm: ' // & + trim(quadpack_algorithm) // '. Supported: QAG, QAGS') end select ! Check for errors (same as F1) if (ier /= 0) then if (ier == 6) then - print *, "QUADPACK Error: Invalid input parameters" - error stop "QUADPACK integration failed" + call log_error('QUADPACK: Invalid input parameters') else - if (fdebug >= 2) then - select case(ier) - case(1) - print *, "QUADPACK Warning: Maximum subdivisions reached" - case(2) - print *, "QUADPACK Warning: Roundoff error detected" - case(3) - print *, "QUADPACK Warning: Extremely bad integrand behavior" - case(4) - print *, "QUADPACK Warning: Roundoff error in extrapolation" - case(5) - print *, "QUADPACK Warning: Divergent integral" - end select - end if + select case(ier) + case(1) + call log_debug('QUADPACK: Maximum subdivisions reached') + case(2) + call log_debug('QUADPACK: Roundoff error detected') + case(3) + call log_debug('QUADPACK: Extremely bad integrand behavior') + case(4) + call log_debug('QUADPACK: Roundoff error in extrapolation') + case(5) + call log_debug('QUADPACK: Divergent integral') + end select end if end if From 7730a025dda91888e39f1df007caeece00da10cb Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Thu, 26 Mar 2026 07:17:46 +0100 Subject: [PATCH 08/11] refactor(QL-Balance): migrate all IO to shared logger module Convert write/print statements across 16 QL-Balance source files to use logger_m calls. Replace debug_mode guards with log_debug, diagnostics_output guards with data_verbosity checks. Convert read_config.f90 display block to fmt_val calls. Co-Authored-By: Claude Opus 4.6 (1M context) --- QL-Balance/src/base/SingleStep.f90 | 26 ++--- .../src/base/balance_eqs_source_terms.f90 | 16 +-- .../src/base/calc_current_densities.f90 | 28 ++--- QL-Balance/src/base/diff_coeffs.f90 | 2 +- QL-Balance/src/base/gengrid.f90 | 20 ++-- QL-Balance/src/base/get_dql.f90 | 24 ++-- QL-Balance/src/base/h5mod.f90 | 3 +- QL-Balance/src/base/paramscan.f90 | 30 ++--- QL-Balance/src/base/plasma_parameters.f90 | 9 +- QL-Balance/src/base/ramp_coil.f90 | 60 +++++----- QL-Balance/src/base/read_config.f90 | 109 +++++++++--------- QL-Balance/src/base/time_evolution.f90 | 60 ++++------ QL-Balance/src/base/wave_code_data_64bit.f90 | 57 ++++----- QL-Balance/src/base/writeData.f90 | 37 +++--- .../balance_eqs_source_terms_stell.f90 | 13 ++- .../src/stellarator/time_evol_stell.f90 | 22 ++-- 16 files changed, 260 insertions(+), 256 deletions(-) diff --git a/QL-Balance/src/base/SingleStep.f90 b/QL-Balance/src/base/SingleStep.f90 index 634523d6..84265384 100644 --- a/QL-Balance/src/base/SingleStep.f90 +++ b/QL-Balance/src/base/SingleStep.f90 @@ -20,8 +20,9 @@ subroutine initSingleStep(this) use grid_mod, only: mwind, set_boundary_condition, npoib, rb use KAMEL_hdf5_tools, only: h5overwrite use h5mod, only: mode_m, mode_n - use control_mod, only: gyro_current_study, write_gyro_current, debug_mode, & + use control_mod, only: gyro_current_study, write_gyro_current, & ihdf5IO + use logger_m, only: log_debug use wave_code_data, only: m_vals, n_vals use plasma_parameters, only: write_initial_parameters, alloc_hold_parameters, & init_background_profiles @@ -49,7 +50,7 @@ subroutine initSingleStep(this) mode_m = m_vals(1) mode_n = n_vals(1) - if (debug_mode) write(*,*) 'Debug: mode_m = ', mode_m, 'mode_n = ', mode_n + call log_debug('mode_m/mode_n set') !call allocate_prev_variables if (ihdf5IO .eq. 1) then call create_group_structure_singlestep @@ -65,7 +66,7 @@ subroutine runSingleStep(this) use transp_coeffs_mod, only: rescale_transp_coeffs_by_ant_fac, & compute_antenna_factor_from_Ipar - use control_mod, only: debug_mode + use logger_m, only: log_debug implicit none @@ -75,9 +76,9 @@ subroutine runSingleStep(this) call initialize_get_dql - if (debug_mode) write(*,*) "Debug: before get_dql" + call log_debug("before get_dql") call get_dql - if (debug_mode) write(*,*) "Debug: after get_dql" + call log_debug("after get_dql") call compute_antenna_factor_from_Ipar call rescale_transp_coeffs_by_ant_fac @@ -170,12 +171,11 @@ subroutine create_group_structure_singlestep use wave_code_data, only: m_vals, n_vals use resonances_mod, only: numres use h5mod + use logger_m, only: log_debug implicit none - if (debug_mode) then - print *, "Creating group structure for Single Step" - end if + call log_debug("Creating group structure for Single Step") if (numres .eq. 1) then if (m_vals(1) <= 9) then @@ -191,9 +191,7 @@ subroutine create_group_structure_singlestep CALL h5_open_rw(path2out, h5_id) if (.not. suppression_mode) then - if (debug_mode) then - write(*,*) "h5_mode_groupname ", trim(h5_mode_groupname) - end if + call log_debug("h5_mode_groupname " // trim(h5_mode_groupname)) CALL h5_create_parent_groups(h5_id, trim(h5_mode_groupname)//'/') CALL h5_create_parent_groups(h5_id, trim(h5_mode_groupname)//"/KinProfiles/") CALL h5_define_group(h5_id, trim(h5_mode_groupname)//"/LinearProfiles/", group_id_1) @@ -204,9 +202,7 @@ subroutine create_group_structure_singlestep CALL h5_close_group(group_id_2) end if else - if (debug_mode) then - write (*,*) "Debug: h5_mode_groupname: ", trim(h5_mode_groupname) - end if + call log_debug("h5_mode_groupname: " // trim(h5_mode_groupname)) CALL h5_define_group(h5_id, trim(h5_mode_groupname), group_id_2) CALL h5_close_group(group_id_2) CALL h5_obj_exists(h5_id, "/init_params", h5_exists_log) @@ -219,7 +215,7 @@ subroutine create_group_structure_singlestep CALL h5_close(h5_id) CALL h5_deinit() - if (debug_mode) write (*, *) "Debug: finished creating group structure for Single Step" + call log_debug("finished creating group structure for Single Step") end subroutine end module diff --git a/QL-Balance/src/base/balance_eqs_source_terms.f90 b/QL-Balance/src/base/balance_eqs_source_terms.f90 index e8daa884..f256f6f2 100644 --- a/QL-Balance/src/base/balance_eqs_source_terms.f90 +++ b/QL-Balance/src/base/balance_eqs_source_terms.f90 @@ -4,7 +4,8 @@ subroutine det_balance_eqs_source_terms use grid_mod, only : y, dery, dery_equisource, nbaleqs, set_boundary_condition, npoi use plasma_parameters, only: params - use control_mod, only: diagnostics_output, debug_mode + use control_mod, only: data_verbosity + use logger_m, only: log_debug use h5mod use matrix_mod use QLBalance_kinds, only: dp @@ -15,7 +16,7 @@ subroutine det_balance_eqs_source_terms integer :: ipoi, ieq, i, k real(dp) :: x - if (debug_mode) write(*,*) "Debug: Generating starting source" + call log_debug("Generating starting source") call set_boundary_condition @@ -26,11 +27,11 @@ subroutine det_balance_eqs_source_terms enddo enddo - if (debug_mode) print *, "Debug: Before initialize_rhs" + call log_debug("Before initialize_rhs") call initialize_rhs(y,dery) dery_equisource=0.d0 - if (debug_mode) print *, "Debug: Before rhs_balance" + call log_debug("Before rhs_balance") call rhs_balance(x,y,dery) do k = 1,nz @@ -39,7 +40,7 @@ subroutine det_balance_eqs_source_terms dery_equisource=dery_equisource-rhsvec - if (diagnostics_output) then + if (data_verbosity >= 2) then call write_balance_eqs_source_terms end if @@ -49,14 +50,15 @@ subroutine write_balance_eqs_source_terms use grid_mod, only : dery_equisource, npoi use h5mod - use control_mod, only: ihdf5IO, debug_mode + use control_mod, only: ihdf5IO + use logger_m, only: log_debug implicit none character(len=1024) :: tempch integer :: ipoi - if (debug_mode) write(*,*) "Debug: Writing equisource" + call log_debug("Writing equisource") if (ihdf5IO .eq. 1) then tempch = "/"//trim(h5_mode_groupname)//"/equisource.dat" diff --git a/QL-Balance/src/base/calc_current_densities.f90 b/QL-Balance/src/base/calc_current_densities.f90 index 71771e50..c518f477 100644 --- a/QL-Balance/src/base/calc_current_densities.f90 +++ b/QL-Balance/src/base/calc_current_densities.f90 @@ -4,8 +4,9 @@ subroutine calc_parallel_current_directly use grid_mod, only: npoib, rb, Ercov use plasma_parameters, only: params_b, ddr_params_nl use baseparam_mod, only: e_charge, p_mass, c, e_mass, ev - use control_mod, only: ihdf5IO, diagnostics_output, write_gyro_current, & + use control_mod, only: ihdf5IO, data_verbosity, write_gyro_current, & gyro_current_study + use logger_m, only: log_debug use h5mod use wave_code_data use QLBalance_kinds, only: dp @@ -49,7 +50,7 @@ subroutine calc_parallel_current_directly call h5_init() call h5_open_rw(path2out, h5_id) tempch = "/"//trim(h5_mode_groupname)//"/par_current_e/" - if (debug_mode) write(*,*) "Debug: In group: "//trim(tempch) + call log_debug("In group: "//trim(tempch)) call h5_obj_exists(h5_id, trim(tempch), h5_exists_log) if (.not. h5_exists_log) then @@ -65,7 +66,7 @@ subroutine calc_parallel_current_directly !x2, lbound(x2), ubound(x2)) if (write_gyro_current) then - if (debug_mode) write(*,*) "Debug: writing par_current_e.dat" + call log_debug("writing par_current_e.dat") ! Write out gyro current which is different to KiLCA current Jpe. ! The gyro current is calculated from (60) in Heyn et. al 2014 !call h5_add_double_1(h5_id, trim(tempch)//"par_current_e_real", & @@ -116,9 +117,9 @@ subroutine calc_parallel_current_directly call h5_close(h5_id) call h5_deinit() - if (diagnostics_output) then + if (data_verbosity >= 2) then if (ihdf5IO .eq. 1) then - if (debug_mode) write(*,*) "Debug: writing par_current_e.dat" + call log_debug("writing par_current_e.dat") call h5_init() call h5_open_rw(path2out, h5_id) @@ -186,7 +187,7 @@ subroutine calc_parallel_current_directly CALL h5_init() CALL h5_open_rw(path2out, h5_id) tempch = "/"//trim(h5_mode_groupname)//"/gyro_current_study/" - if (debug_mode) write(*,*) "Debug: In group: "//trim(tempch) + call log_debug("In group: "//trim(tempch)) CALL h5_define_group(h5_id, trim(tempch), group_id_1) CALL h5_close_group(group_id_1) @@ -242,7 +243,7 @@ subroutine calc_parallel_current_directly tempch = "/"//trim(h5_mode_groupname)//"/gyro_current_study/" write(tempch, "(A,i4.4,A,i4.4,A)") trim(tempch), study_i_omE, "/", & study_j_nue, "/" - if (debug_mode) write(*,*) "Debug: In group: "//trim(tempch) + call log_debug("In group: "//trim(tempch)) CALL h5_define_group(h5_id, trim(tempch), group_id_1) CALL h5_close_group(group_id_1) @@ -309,7 +310,7 @@ subroutine calc_parallel_current_directly CALL h5_init() CALL h5_open_rw(path2out, h5_id) tempch = "/"//trim(h5_mode_groupname)//"/currents/" - if (debug_mode) write(*,*) "Debug: In group: "//trim(tempch) + call log_debug("In group: "//trim(tempch)) CALL h5_define_group(h5_id, trim(tempch), group_id_1) CALL h5_close_group(group_id_1) @@ -382,7 +383,8 @@ subroutine calc_ion_parallel_current_directly use plasma_parameters, only: params_b, ddr_params_nl use baseparam_mod, only: Z_i, e_charge, p_mass, c, e_mass, ev use wave_code_data - use control_mod, only: ihdf5IO, diagnostics_output, write_gyro_current + use control_mod, only: ihdf5IO, data_verbosity, write_gyro_current + use logger_m, only: log_debug use h5mod use QLBalance_kinds, only: dp @@ -421,13 +423,13 @@ subroutine calc_ion_parallel_current_directly + vT*Br*((x1 + x2)*symbI(1, 1, :) + 0.5d0*x2*symbI(3, 1, :))) if (write_gyro_current) then - if (debug_mode) write(*,*) "Debug: writing par_current_i.dat" + call log_debug("writing par_current_i.dat") ! Write out gyro current which is different to KiLCA current Jpe. ! The gyro current is calculated from (60) in Heyn et. al 2014 call h5_init() call h5_open_rw(path2out, h5_id) tempch = "/"//trim(h5_mode_groupname)//"/par_current_i/" - if (debug_mode) write(*,*) "Debug: In group: "//trim(tempch) + call log_debug("In group: "//trim(tempch)) call h5_define_group(h5_id, trim(tempch), group_id_1) call h5_close_group(group_id_1) @@ -466,9 +468,9 @@ subroutine calc_ion_parallel_current_directly end if ! write_gyro_current - if (diagnostics_output) then + if (data_verbosity >= 2) then if (ihdf5IO .eq. 1) then - if (debug_mode) print *, "Debug: writing par_current_i.dat" + call log_debug("writing par_current_i.dat") call h5_init() call h5_open_rw(path2out, h5_id) tempch = "/"//trim(h5_mode_groupname)//"/par_current_i.dat" diff --git a/QL-Balance/src/base/diff_coeffs.f90 b/QL-Balance/src/base/diff_coeffs.f90 index 73fa7cba..be12e923 100644 --- a/QL-Balance/src/base/diff_coeffs.f90 +++ b/QL-Balance/src/base/diff_coeffs.f90 @@ -5,7 +5,7 @@ subroutine calc_equil_diffusion_coeffs use plasma_parameters, only: params_b use baseparam_mod, only: rsepar use h5mod - use control_mod, only: ihdf5IO, debug_mode + use control_mod, only: ihdf5IO use paramscan_mod, only: viscosity_factor use PolyLagrangeInterpolation use QLBalance_kinds, only: dp diff --git a/QL-Balance/src/base/gengrid.f90 b/QL-Balance/src/base/gengrid.f90 index 74e90993..83442a0d 100644 --- a/QL-Balance/src/base/gengrid.f90 +++ b/QL-Balance/src/base/gengrid.f90 @@ -7,8 +7,9 @@ subroutine gengrid use grid_mod use plasma_parameters - use control_mod, only: debug_mode, wave_code, kim_n_modes, kim_m_list, kim_n_list + use control_mod, only: wave_code, kim_n_modes, kim_m_list, kim_n_list use PolyLagrangeInterpolation + use logger_m, only: log_debug implicit none @@ -16,7 +17,7 @@ subroutine gengrid double precision :: hrmax, r, rnext, recnsp double precision, dimension(:), allocatable :: x - if (debug_mode) write(*,*) "Debug: coming in gengrid" + call log_debug("coming in gengrid") nbaleqs = 4 nder = 1 @@ -114,7 +115,7 @@ subroutine gengrid allocate(Ercov_lin(npoib)) - if (debug_mode) write(*,*) "Debug: going out in gengrid" + call log_debug("going out of gengrid") return end subroutine gengrid @@ -174,7 +175,8 @@ subroutine prepare_resonances use resonances_mod use grid_mod, only: gg_width, gg_factor,r_resonant - use control_mod, only: ihdf5IO, debug_mode, wave_code, kim_n_modes, kim_m_list, kim_n_list + use control_mod, only: ihdf5IO, wave_code, kim_n_modes, kim_m_list, kim_n_list + use logger_m, only: log_debug use h5mod implicit none @@ -206,7 +208,7 @@ subroutine prepare_resonances nr = ub else - if (debug_mode) print *, "get number of q data points" + call log_debug("get number of q data points") nr=0 open(iunit_res,file='profiles/q.dat') do @@ -217,7 +219,7 @@ subroutine prepare_resonances close(iunit_res) allocate(r(nr),q(nr)) - if (debug_mode) print *, "reading profiles/q.dat" + call log_debug("reading profiles/q.dat") open(iunit_res,file='profiles/q.dat') do i=1,nr read(iunit_res,*) r(i),q(i) @@ -231,7 +233,7 @@ subroutine prepare_resonances if (trim(wave_code) == 'KIM') then ! KIM mode: read mode list from namelist parameters numres = kim_n_modes - if (debug_mode) write(*,*) "numres = ", numres + call log_debug("numres determined") allocate(r_res(numres),width_res(numres),ampl_res(numres)) allocate(r_resonant(numres)) @@ -277,7 +279,7 @@ subroutine prepare_resonances read(iunit_res,*) read(iunit_res,*) numres close(iunit_res) - if (debug_mode) write(*,*) "numres = ", numres + call log_debug("numres determined") allocate(r_res(numres),width_res(numres),ampl_res(numres)) allocate(r_resonant(numres)) @@ -331,7 +333,7 @@ subroutine prepare_resonances enddo enddo - if (debug_mode) print *,'Debug: gengrid: number of resonance points = ',numres + call log_debug('gengrid: number of resonance points determined') do i = 1, numres ! maximum width for resonant radius is 999.999 cm with this format ! adjust if necessary diff --git a/QL-Balance/src/base/get_dql.f90 b/QL-Balance/src/base/get_dql.f90 index a69bc298..a40c8e7d 100644 --- a/QL-Balance/src/base/get_dql.f90 +++ b/QL-Balance/src/base/get_dql.f90 @@ -25,6 +25,7 @@ subroutine get_dql use QLBalance_diag, only: i_mn_loop use QLBalance_kinds, only: dp use PolyLagrangeInterpolation + use logger_m, only: log_debug implicit none @@ -240,9 +241,9 @@ subroutine get_dql ! caluclate part of perpendicular electric field perturbation that comes from if (.not. allocated(coef)) allocate(coef(0:nder,nlagr)) - if (debug_mode) write(*,*) "at r_resonant(i_mn) = ", r_resonant(i_mn) + call log_debug("at r_resonant for misalign_diffusion") call binsrc(rb, 1, npoib, r_resonant(i_mn), ibrabsres) - if (debug_mode) write(*,*) "binary search found ibrabsres = ", ibrabsres + call log_debug("binary search found ibrabsres") call get_ind_Lagr_interp(ibrabsres, ind_begin_interp, ind_end_interp) call plag_coeff(nlagr, nder, r_resonant(i_mn), rb(ind_begin_interp:ind_end_interp), coef) @@ -482,7 +483,7 @@ subroutine get_dql end if - if (debug_mode) print *, "Debug: write_fields_currs_transp_coefs_to_h5" + call log_debug("write_fields_currs_transp_coefs_to_h5") if (modulo(time_ind, save_prof_time_step) .eq. 0) then if (suppression_mode .eqv. .false.) then @@ -491,7 +492,7 @@ subroutine get_dql end if end if - if (debug_mode) write(*,*) "Debug: going out of get_dql" + call log_debug("going out of get_dql") end subroutine get_dql @@ -563,7 +564,8 @@ subroutine write_Brvac(brvac_interp) use QLBalance_kinds, only: dp use grid_mod, only: npoib, r_resonant use wave_code_data, only: Br, r - use control_mod, only: ihdf5IO + use control_mod, only: ihdf5IO, data_verbosity + use logger_m, only: log_debug implicit none @@ -572,21 +574,21 @@ subroutine write_Brvac(brvac_interp) integer :: ipoi if (ihdf5IO .eq. 1) then - if (debug_mode) print *, "Debug: Writing Brvac to hdf5 file" - if (debug_mode) write(*,*) "Debug: Brvac = ", brvac_interp, " at r_res = ", r_resonant(1) + call log_debug("Writing Brvac to hdf5 file") + call log_debug("Brvac computation complete") CALL h5_init() CALL h5_open_rw(path2out, h5_id) !call create_group_if_not_existent("/"//trim(h5_mode_groupname)) tempch = "/"//trim(h5_mode_groupname)//"/Brvac_res_real" - if (debug_mode) write(*,*) "Debug: group name: ", trim(tempch) + call log_debug("group name: " // trim(tempch)) CALL h5_add_double_0(h5_id, trim(tempch), real(brvac_interp)) tempch = "/"//trim(h5_mode_groupname)//"/Brvac_res_imag" - if (debug_mode) write(*,*) "Debug: group name: ", trim(tempch) + call log_debug("group name: " // trim(tempch)) CALL h5_add_double_0(h5_id, trim(tempch), aimag(brvac_interp)) - if (diagnostics_output) then - if (debug_mode) write (*, *) "Debug: writing Brvac.dat" + if (data_verbosity >= 2) then + call log_debug("writing Brvac.dat") tempch = "/"//trim(h5_mode_groupname)//"/Brvac.dat" CALL h5_obj_exists(h5_id, trim(tempch), h5_exists_log) if (h5_exists_log) then diff --git a/QL-Balance/src/base/h5mod.f90 b/QL-Balance/src/base/h5mod.f90 index 44cbcba5..bf2d30fe 100644 --- a/QL-Balance/src/base/h5mod.f90 +++ b/QL-Balance/src/base/h5mod.f90 @@ -3,6 +3,7 @@ module h5mod use KAMEL_hdf5_tools use control_mod + use logger_m, only: log_debug implicit none @@ -38,7 +39,7 @@ subroutine create_group_if_not_existent(group_name) character(*), intent(in) :: group_name - if (debug_mode) print *, "Creating group ", trim(group_name) + call log_debug("Creating group " // trim(group_name)) call h5_obj_exists(h5_id, trim(group_name), h5_exists_log) if (.not. h5_exists_log) then diff --git a/QL-Balance/src/base/paramscan.f90 b/QL-Balance/src/base/paramscan.f90 index ba4f80f5..35d3b701 100644 --- a/QL-Balance/src/base/paramscan.f90 +++ b/QL-Balance/src/base/paramscan.f90 @@ -4,6 +4,7 @@ module paramscan_mod use control_mod use balance_base, only: balance_t use QLBalance_kinds, only: dp + use logger_m, only: log_debug implicit none @@ -31,8 +32,9 @@ subroutine initParameterScan(this) use QLbalance_diag, only: write_diag, write_diag_b use KAMEL_hdf5_tools, only: h5overwrite use h5mod, only: mode_m, mode_n - use control_mod, only: gyro_current_study, write_gyro_current, debug_mode, & + use control_mod, only: gyro_current_study, write_gyro_current, & ihdf5IO + use logger_m, only: log_debug use wave_code_data, only: m_vals, n_vals use plasma_parameters, only: write_initial_parameters, alloc_hold_parameters, & init_background_profiles @@ -62,7 +64,7 @@ subroutine initParameterScan(this) mode_m = m_vals(1) mode_n = n_vals(1) - if (debug_mode) write(*,*) 'Debug: mode_m = ', mode_m, 'mode_n = ', mode_n + call log_debug('mode_m/mode_n set') !call allocate_prev_variables if (ihdf5IO .eq. 1) then @@ -129,9 +131,8 @@ subroutine prepare_h5_group_name call add_mode_group_to_h5_mode_groupname call determine_h5_mode_groupname_of_scan print *, "Prepare_h5_group_name : h5_mode_groupname: ", trim(h5_mode_groupname) - if (debug_mode) then - print *, "Prepare_h5_group_name : h5_mode_groupname: ", trim(h5_mode_groupname) - end if + call log_debug("Prepare_h5_group_name : h5_mode_groupname: " & + // trim(h5_mode_groupname)) end subroutine @@ -234,7 +235,7 @@ subroutine getfactors subroutine rescale_profiles use plasma_parameters, only: params, hold_n, hold_vz, hold_Te, hold_Ti, hold_dphi0 - use control_mod, only: debug_mode + use logger_m, only: log_debug use h5mod use wave_code_data, only: idPhi0 @@ -243,7 +244,7 @@ subroutine rescale_profiles double precision, dimension(:), allocatable :: ErVzfac ! factor to rescale Er integer :: lowerBound, upperBound - if (debug_mode) write(*,*) "Debug: coming into rescaling profiles" + call log_debug("coming into rescaling profiles") print *, "hold times fac" params(1, :) = hold_n * fac_n(ifac_n) @@ -253,7 +254,7 @@ subroutine rescale_profiles print *, "After hold times fac" if (fac_vz(ifac_vz) .ne. 1.d0) then - if (debug_mode) write(*,*) "Debug: fac_vz not equal 1. need to rescale Er as well" + call log_debug("fac_vz not equal 1. need to rescale Er as well") CALL h5_init() CALL h5_open_rw(path2out, h5_id) CALL h5_get_bounds_1(h5_id, '/factors/ErVzfac', lowerBound, upperBound) @@ -272,7 +273,7 @@ subroutine rescale_profiles write(*,*) "fac_Te = ", fac_Te(ifac_Te), " ", ifac_Te, " of ", size(fac_Te) write(*,*) "fac_vz = ", fac_vz(ifac_vz), " ", ifac_vz, " of ", size(fac_vz) - if (debug_mode) write(*,*) "Debug: going out of rescaling profiles" + call log_debug("going out of rescaling profiles") end subroutine !rescale_profiles @@ -309,7 +310,7 @@ subroutine interpolate_Br_Dql_at_res_parscan Ercovavg(ipoi) = 0.5d0*(Ercov(ipoi) + Ercov(ipoi + 1)) end do Er_res(ifac_n, ifac_Te, ifac_Ti, ifac_vz) = sum(coef(0, :)*Ercovavg(ind_begin_interp:ind_end_interp)) - if (debug_mode) write (*, *) "Er_res = ", Er_res(ifac_n, ifac_Te, ifac_Ti, ifac_vz) + call log_debug("Er_res computed") end if end subroutine @@ -323,11 +324,12 @@ subroutine create_group_structure_paramscan use wave_code_data, only: m_vals, n_vals use resonances_mod, only: numres use h5mod + use logger_m, only: log_debug implicit none !logical :: suppression_mode = .true. - if (debug_mode) write (*, *) "Debug: Creating group structure" + call log_debug("Creating group structure") ! if the profiles should be written out, i.e. suppression_mode = false, then an extended group ! structure is created to save them CALL h5_init() @@ -364,7 +366,7 @@ subroutine create_group_structure_paramscan ! create the groups that are furthest down: fort.1000, ! fort.5000 and init_params - if (debug_mode) write(*,*) "Debug: h5_mode_groupname ", trim(h5_mode_groupname) + call log_debug("h5_mode_groupname " // trim(h5_mode_groupname)) CALL h5_create_parent_groups(h5_id, trim(h5_mode_groupname) //'/') CALL h5_create_parent_groups(h5_id, trim(h5_mode_groupname)//"/KinProfiles/") CALL h5_create_parent_groups(h5_id, trim(h5_mode_groupname)//"/LinearProfiles/") @@ -392,7 +394,7 @@ subroutine create_group_structure_paramscan write (h5_mode_groupname, "(A)") "multi_mode" end if - if (debug_mode) write (*,*) "Debug: h5_mode_groupname: ", trim(h5_mode_groupname) + call log_debug("h5_mode_groupname: " // trim(h5_mode_groupname)) CALL h5_define_group(h5_id, trim(h5_mode_groupname), group_id_2) CALL h5_close_group(group_id_2) @@ -400,7 +402,7 @@ subroutine create_group_structure_paramscan CALL h5_close(h5_id) CALL h5_deinit() - if (debug_mode) write (*, *) "Debug: finished creating group structure" + call log_debug("finished creating group structure") end subroutine subroutine write_Br_Dql_at_res_to_hdf5 diff --git a/QL-Balance/src/base/plasma_parameters.f90 b/QL-Balance/src/base/plasma_parameters.f90 index 9f6c3bbb..2d19353f 100644 --- a/QL-Balance/src/base/plasma_parameters.f90 +++ b/QL-Balance/src/base/plasma_parameters.f90 @@ -139,11 +139,12 @@ subroutine init_background_profiles !> @date 05.10.2022 subroutine write_initial_parameters use baseparam_mod, only: ev - use control_mod, only: debug_mode, ihdf5IO + use control_mod, only: ihdf5IO use h5mod use wave_code_data, only: r, Vth, dPhi0 + use logger_m, only: log_debug - if (debug_mode) write (*, *) "Debug: writing initial background profiles" + call log_debug("writing initial background profiles") if (ihdf5IO .eq. 1) then call h5_init() ! open hdf5 file @@ -173,12 +174,12 @@ subroutine write_initial_parameters ! thermal velocity [cm/s] call h5_add_double_1(h5_id, "/init_params/Vth", Vth, lbound(Vth), ubound(Vth)) else - if (debug_mode) write (*, *) "Debug: they are already there -> skiping" + call log_debug("they are already there -> skipping") end if call h5_close(h5_id) call h5_deinit() - if (debug_mode) write (*, *) "Debug: finished writing initial background profiles" + call log_debug("finished writing initial background profiles") !stop ! for test purposes else diff --git a/QL-Balance/src/base/ramp_coil.f90 b/QL-Balance/src/base/ramp_coil.f90 index 8ce5d76f..060e837d 100644 --- a/QL-Balance/src/base/ramp_coil.f90 +++ b/QL-Balance/src/base/ramp_coil.f90 @@ -3,12 +3,12 @@ !> @date 13.03.2023 subroutine ramp_coil - use control_mod, only: debug_mode + use logger_m, only: log_debug use time_evolution, only: ramp_up_mode implicit none - if (debug_mode) write(*,*) "Debug: - - ramp up antenna_factor - -" + call log_debug("- - ramp up antenna_factor - -") select case(ramp_up_mode) case(0) @@ -42,11 +42,11 @@ subroutine ramp_up_linear use wave_code_data, only: antenna_factor use time_evolution, only: time - use control_mod, only: debug_mode + use logger_m, only: log_debug implicit none - if (debug_mode) write(*,*) "Debug: ramp-up mode linear" + call log_debug("ramp-up mode linear") ! initial ramp up. This is a linear ramp up of the antenna factor in time. antenna_factor = time**2 + 1.d-4 @@ -56,11 +56,11 @@ subroutine ramp_up_faster_1 use wave_code_data, only: antenna_factor use time_evolution, only: timstep, t_max_ramp_up, antenna_factor_max - use control_mod, only: debug_mode + use logger_m, only: log_debug implicit none - if (debug_mode) write(*,*) "Debug: ramp-up mode faster 1" + call log_debug("ramp-up mode faster 1") ! First try for faster ramp up. Is (usually) not stable. antenna_factor = antenna_factor + antenna_factor_max * (timstep/t_max_ramp_up) @@ -70,11 +70,11 @@ subroutine ramp_up_faster_2 use wave_code_data, only: antenna_factor use time_evolution, only: time, t_max_ramp_up, antenna_factor_max - use control_mod, only: debug_mode + use logger_m, only: log_debug implicit none - if (debug_mode) write(*,*) "Debug: ramp-up mode faster 2, stable" + call log_debug("ramp-up mode faster 2, stable") ! Use this for faster ramp up. Ramps up antenna factor to 100% of max value ! in t_max_ramp_up time, but ramps-up further after that. if (time .eq. 0) then @@ -89,11 +89,11 @@ subroutine ramp_up_instant use wave_code_data, only: antenna_factor use time_evolution, only: time, antenna_factor_max - use control_mod, only: debug_mode + use logger_m, only: log_debug implicit none - if (debug_mode) write(*,*) "Debug: ramp-up mode instant" + call log_debug("ramp-up mode instant") call stop_if_t_max_reached @@ -108,11 +108,11 @@ subroutine ramp_up_instant subroutine ramp_up_none use wave_code_data, only: antenna_factor - use control_mod, only: debug_mode + use logger_m, only: log_debug implicit none - if (debug_mode) write(*,*) "Debug: ramp-up mode none" + call log_debug("ramp-up mode none") call stop_if_t_max_reached antenna_factor = 0d0 @@ -123,25 +123,25 @@ subroutine ramp_up_hysteresis use time_evolution, only: time, ramp_up_down, t_hysteresis_turn, antenna_factor_max, antenna_max_stopping, & write_kin_prof_data_to_disk, write_br_dqle22_time_data use wave_code_data, only: antenna_factor - use control_mod, only: debug_mode + use logger_m, only: log_debug use h5mod implicit none - if (debug_mode) write(*,*) "Debug: ramp-up mode hysteresis" - if (debug_mode) write(*,*) "Debug: ramp_up_down = ", ramp_up_down + call log_debug("ramp-up mode hysteresis") + call log_debug("ramp_up_down processing") if (ramp_up_down .eq. 0) then ! ramp-up - if (debug_mode) write(*,*) "Ramp up ^" + call log_debug("Ramp up ^") antenna_factor = time**2 + 1.d-4 if (antenna_factor .ge. antenna_factor_max * antenna_max_stopping) then ! switch to ramp-down ramp_up_down = 1 t_hysteresis_turn = time - if (debug_mode) write(*,*) "Debug: Ramp turn at t = ", time + call log_debug("Ramp turn") end if else if (ramp_up_down .eq. 1) then !ramp down - if (debug_mode) write(*,*) "Debug: Ramp down v" + call log_debug("Ramp down v") ! get linear ramp-up in coil current (scales with sqrt of antenna_factor): antenna_factor = (sqrt(antenna_factor_max * antenna_max_stopping) - (time - t_hysteresis_turn))**2 if ((antenna_factor/antenna_factor_max * 100) .le. 1.0) then ! if antenna factor would get below some percentage of the max value @@ -158,7 +158,7 @@ subroutine ramp_up_hysteresis CALL h5_close(h5_id) CALL h5_deinit() end if - if (debug_mode) write(*,*) "Debug: Write br_time _data" + call log_debug("Write br_time_data") if (ihdf5IO .eq. 1) then CALL write_br_dqle22_time_data!, br_abs_time, br_abs_antenna_factor, br_abs, dqle22_res_time) end if @@ -174,24 +174,24 @@ subroutine ramp_up_fast_hysteresis use time_evolution, only: time, t_max_ramp_up, ramp_up_down, t_hysteresis_turn, antenna_factor_max, & antenna_max_stopping, write_kin_prof_data_to_disk, write_br_dqle22_time_data use wave_code_data, only: antenna_factor - use control_mod, only: debug_mode + use logger_m, only: log_debug use h5mod implicit none - if (debug_mode) write(*,*) "Debug: ramp-up mode fast hysteresis" - if (debug_mode) write(*,*) "Debug: ramp_up_down = ", ramp_up_down + call log_debug("ramp-up mode fast hysteresis") + call log_debug("ramp_up_down processing") if (ramp_up_down .eq. 0) then ! ramp-up - if (debug_mode) write(*,*) "Ramp up ^" + call log_debug("Ramp up ^") !antenna_factor = time**2 + 1.d-4 antenna_factor = (antenna_factor_max/t_max_ramp_up * time)**2 if (antenna_factor .ge. antenna_factor_max * antenna_max_stopping) then ! switch to ramp-down ramp_up_down = 1 t_hysteresis_turn = time - if (debug_mode) write(*,*) "Debug: Ramp turn at t = ", time + call log_debug("Ramp turn") end if else if (ramp_up_down .eq. 1) then !ramp down - if (debug_mode) write(*,*) "Debug: Ramp down v" + call log_debug("Ramp down v") ! get linear ramp-up in coil current (scales with sqrt of antenna_factor): antenna_factor = (sqrt(antenna_factor_max * antenna_max_stopping) - (time - t_hysteresis_turn) & * antenna_factor_max/t_max_ramp_up)**2 @@ -224,12 +224,13 @@ subroutine stop_if_antenna_fac_max_reached use time_evolution, only: antenna_max_stopping, antenna_factor_max, write_br_dqle22_time_data, & write_kin_prof_data_to_disk use wave_code_data, only: antenna_factor + use logger_m, only: log_debug, log_info use h5mod implicit none if (antenna_factor .gt. (antenna_factor_max * antenna_max_stopping)) then - write(*,*) 'stop: reached antenna_factor_max * ', antenna_max_stopping + call log_info('stop: reached antenna_factor_max') if (suppression_mode .eqv. .false.) then call write_kin_prof_data_to_disk @@ -244,7 +245,7 @@ subroutine stop_if_antenna_fac_max_reached CALL h5_deinit() end if - if (debug_mode) write(*,*) "Debug: Write br_time_data" + call log_debug("Write br_time_data") if (ihdf5IO .eq. 1) then CALL write_br_dqle22_time_data!, br_abs_time, br_abs_antenna_factor, br_abs, dqle22_res_time) end if @@ -337,12 +338,13 @@ subroutine stop_if_t_max_reached use time_evolution, only: time, t_max_ramp_up, write_kin_prof_data_to_disk, write_br_dqle22_time_data use control_mod, only: suppression_mode, ihdf5IO + use logger_m, only: log_debug, log_info use h5mod implicit none if (time .ge. t_max_ramp_up) then ! if max time value is reached, stop the code - write(*,*) 'stop: reached time max: ', t_max_ramp_up + call log_info('stop: reached time max') if (suppression_mode .eqv. .false.) then call write_kin_prof_data_to_disk end if @@ -357,7 +359,7 @@ subroutine stop_if_t_max_reached CALL write_br_dqle22_time_data!, br_abs_time, br_abs_antenna_factor, br_abs, dqle22_res_time) end if - if (debug_mode) write(*,*) "Debug: Write br_time _data" + call log_debug("Write br_time_data") stop end if diff --git a/QL-Balance/src/base/read_config.f90 b/QL-Balance/src/base/read_config.f90 index d0de3def..81fd81a7 100644 --- a/QL-Balance/src/base/read_config.f90 +++ b/QL-Balance/src/base/read_config.f90 @@ -12,7 +12,7 @@ subroutine read_config use paramscan_mod, only: viscosity_factor use time_evolution use wave_code_data, only: flre_path, vac_path, antenna_factor, I_par_toroidal - use logger_m, only: set_log_level + use logger_m, only: set_log_level, log_info, fmt_val implicit none @@ -41,62 +41,61 @@ subroutine read_config call set_log_level(log_level) - write (*, *) "" - write (*, *) "=================================================================================" - write (*, "(A,A)") " Type of Run: ", type_of_run - write (*, "(A,A)") " Wave Code: ", trim(adjustl(wave_code)) - write (*, *) "" - write (*, "(A,A,A)") " Parameters from ", config_file, ":" - write (*, *) " ------------------------------------------------------------------------------" - write (*, "(A,A)") " flre path: ", trim(adjustl(flre_path)) - write (*, "(A,A)") " vac path: ", trim(adjustl(vac_path)) - write (*, "(A,ES15.8,A)") " B_tor = ", btor, " G" - write (*, "(A,ES15.8,A)") " R_tor = ", rtor, " cm" - write (*, "(A,ES15.8,A)") " r_min = ", rmin, " cm" - write (*, "(A,ES15.8,A)") " r_max = ", rmax, " cm" - write (*, "(A,I0)") " npoimin = ", npoimin - write (*, "(A,ES15.8)") " gg_factor = ", gg_factor - write (*, "(A,ES15.8)") " gg_width = ", gg_width - write (*, "(A,ES15.8)") " gg_r_res = ", gg_r_res - write (*, "(A,I0)") " Nstorage = ", Nstorage - write (*, "(A,ES15.8)") " tmax_factor = ", tmax_factor - write (*, "(A,ES15.8)") " timstep_min = ", timstep_min - write (*, "(A,ES15.8)") " antenna_factor = ", antenna_factor - write (*, "(A,ES15.8)") " I_par_toroidal = ", I_par_toroidal - write (*, "(A,I0)") " iboutype = ", iboutype - write (*, "(A,ES15.8)") " eps = ", eps - write (*, "(A,ES15.8)") " dperp = ", dperp - write (*, "(A,ES15.8)") " Z_i = ", Z_i - write (*, "(A,ES15.8)") " am = ", am - write (*, "(A,ES12.4)") " stop_time_step = ", stop_time_step - write (*, "(A,A)") " path2inp = ", trim(adjustl(path2inp)) - write (*, "(A,A)") " path2out = ", trim(adjustl(path2out)) - write (*, "(A,L0)") " paramscan = ", paramscan - write (*, "(A,I0)") " data_verbosity = ", data_verbosity - write (*, "(A,L0)") " br_stopping = ", br_stopping - write (*, "(A,I0)") " log_level = ", log_level - write (*, "(A,I0)") " readfromtimestep = ", readfromtimestep - write (*, "(A,L0)") " suppression_mode = ", suppression_mode - write (*, "(A,I0)") " ramp_up_mode = ", ramp_up_mode - write (*, "(A,ES15.8,A)") " t_max_ramp_up = ", t_max_ramp_up, " s" - write (*, "(A,ES15.8,A)") " temperature_limit = ", temperature_limit, " eV" - write (*, "(A,ES15.8)") " antenna_max_stopping = ", antenna_max_stopping - write (*, "(A,I0)") " gyro_current_study = ", gyro_current_study - write (*, "(A,ES15.8)") " viscosity_factor = ", viscosity_factor - write (*, "(A,L0)") " misalign_diffusion = ", misalign_diffusion - write (*, "(A,A)") " equil_path = ", trim(adjustl(equil_path)) - write (*, "(A,I0)") " ihdf5IO = ", ihdf5IO - write (*, "(A,L0)") " set_constant_time_step = ", set_constant_time_step - write (*, "(A,ES15.8,A)") " constant_time_step = ", constant_time_step, " s" - write (*, "(A,ES15.8)") " urelax = ", urelax - write (*, "(A,A)") " jpar_method = ", trim(adjustl(jpar_method)) - write (*, "(A,A)") " kim_config_path = ", trim(adjustl(kim_config_path)) - write (*, "(A,L0)") " kim_profiles_from_balance = ", kim_profiles_from_balance - write (*, "(A,I0)") " kim_n_modes = ", kim_n_modes + call log_info("=================================================================================") + call log_info(fmt_val(" Type of Run", type_of_run)) + call log_info(fmt_val(" Wave Code", trim(adjustl(wave_code)))) + call log_info("") + call log_info(" Parameters from " // config_file // ":") + call log_info(" ------------------------------------------------------------------------------") + call log_info(fmt_val(" flre path", trim(adjustl(flre_path)))) + call log_info(fmt_val(" vac path", trim(adjustl(vac_path)))) + call log_info(fmt_val(" B_tor", btor, "G")) + call log_info(fmt_val(" R_tor", rtor, "cm")) + call log_info(fmt_val(" r_min", rmin, "cm")) + call log_info(fmt_val(" r_max", rmax, "cm")) + call log_info(fmt_val(" npoimin", npoimin)) + call log_info(fmt_val(" gg_factor", gg_factor)) + call log_info(fmt_val(" gg_width", gg_width)) + call log_info(fmt_val(" gg_r_res", gg_r_res)) + call log_info(fmt_val(" Nstorage", Nstorage)) + call log_info(fmt_val(" tmax_factor", tmax_factor)) + call log_info(fmt_val(" timstep_min", timstep_min)) + call log_info(fmt_val(" antenna_factor", antenna_factor)) + call log_info(fmt_val(" I_par_toroidal", I_par_toroidal)) + call log_info(fmt_val(" iboutype", iboutype)) + call log_info(fmt_val(" eps", eps)) + call log_info(fmt_val(" dperp", dperp)) + call log_info(fmt_val(" Z_i", Z_i)) + call log_info(fmt_val(" am", am)) + call log_info(fmt_val(" stop_time_step", stop_time_step)) + call log_info(fmt_val(" path2inp", trim(adjustl(path2inp)))) + call log_info(fmt_val(" path2out", trim(adjustl(path2out)))) + call log_info(fmt_val(" paramscan", paramscan)) + call log_info(fmt_val(" data_verbosity", data_verbosity)) + call log_info(fmt_val(" br_stopping", br_stopping)) + call log_info(fmt_val(" log_level", log_level)) + call log_info(fmt_val(" readfromtimestep", readfromtimestep)) + call log_info(fmt_val(" suppression_mode", suppression_mode)) + call log_info(fmt_val(" ramp_up_mode", ramp_up_mode)) + call log_info(fmt_val(" t_max_ramp_up", t_max_ramp_up, "s")) + call log_info(fmt_val(" temperature_limit", temperature_limit, "eV")) + call log_info(fmt_val(" antenna_max_stopping", antenna_max_stopping)) + call log_info(fmt_val(" gyro_current_study", gyro_current_study)) + call log_info(fmt_val(" viscosity_factor", viscosity_factor)) + call log_info(fmt_val(" misalign_diffusion", misalign_diffusion)) + call log_info(fmt_val(" equil_path", trim(adjustl(equil_path)))) + call log_info(fmt_val(" ihdf5IO", ihdf5IO)) + call log_info(fmt_val(" set_constant_time_step", set_constant_time_step)) + call log_info(fmt_val(" constant_time_step", constant_time_step, "s")) + call log_info(fmt_val(" urelax", urelax)) + call log_info(fmt_val(" jpar_method", trim(adjustl(jpar_method)))) + call log_info(fmt_val(" kim_config_path", trim(adjustl(kim_config_path)))) + call log_info(fmt_val(" kim_profiles_from_balance", kim_profiles_from_balance)) + call log_info(fmt_val(" kim_n_modes", kim_n_modes)) if (kim_n_modes > 0) then write (*, "(A,100I5)") " kim_m_list = ", kim_m_list(1:kim_n_modes) write (*, "(A,100I5)") " kim_n_list = ", kim_n_list(1:kim_n_modes) end if - write (*, *) "" - write (*, *) "=================================================================================" + call log_info("") + call log_info("=================================================================================") end subroutine read_config diff --git a/QL-Balance/src/base/time_evolution.f90 b/QL-Balance/src/base/time_evolution.f90 index 9c1afe68..92265788 100644 --- a/QL-Balance/src/base/time_evolution.f90 +++ b/QL-Balance/src/base/time_evolution.f90 @@ -4,6 +4,7 @@ module time_evolution use h5mod use balance_base, only: balance_t use QLBalance_kinds, only: dp + use logger_m, only: log_debug, log_info implicit none @@ -86,12 +87,13 @@ subroutine initTimeEvolution(this) use QLbalance_diag, only: write_diag, write_diag_b use KAMEL_hdf5_tools, only: h5overwrite use h5mod, only: mode_m, mode_n - use control_mod, only: gyro_current_study, write_gyro_current, debug_mode, & + use control_mod, only: gyro_current_study, write_gyro_current, & ihdf5IO use wave_code_data, only: m_vals, n_vals use plasma_parameters, only: write_initial_parameters, alloc_hold_parameters, & params, params_begbeg, init_background_profiles use resonances_mod, only: write_resonant_radii_to_hdf5 + use logger_m, only: log_debug implicit none @@ -127,7 +129,7 @@ subroutine initTimeEvolution(this) if (ihdf5IO .eq. 1) then call create_group_structure_timeevol end if - if (debug_mode) write(*,*) 'Debug: mode_m = ', mode_m, 'mode_n = ', mode_n + call log_debug('mode_m/mode_n set') call write_resonant_radii_to_hdf5 @@ -171,8 +173,8 @@ end subroutine runTimeEvolution subroutine doStep(this) use baseparam_mod, only: factolmax, factolred - use control_mod, only: debug_mode use plasma_parameters, only: params, params_beg, params_begbeg, limit_temps_from_below + use logger_m, only: log_debug use recstep_mod, only: timstep_arr use recstep_mod, only: tol use restart_mod, only: redostep @@ -197,7 +199,7 @@ subroutine doStep(this) call write_br_dqle22_time_data call message_Br_Dqle_values - if (diagnostics_output)then + if (data_verbosity >= 2) then call writefort9999 end if @@ -214,8 +216,7 @@ subroutine doStep(this) params_beg = params print *, "" - if (debug_mode) write(*, "(a, i0, a, f12.6)") & - "Debug: Timstep before evolvestep is ", timstep, " eps = " , eps + call log_debug("Timstep before evolvestep") call evolvestep(timstep, eps) @@ -232,16 +233,7 @@ subroutine doStep(this) timstep_arr = timstep_arr * factolred params = params_beg - if (debug_mode) then - print *, "Redoing step: Maxval(timscal) is not lesser than tol * factolmax" - print *, "Maxval(timscal) = ", maxval(timscal) - print *, "tol = ", tol - print *, "factolmax = ", factolmax - print *, "tol * factolmax = ", tol * factolmax - print *, "timstep_arr(1) = ", timstep_arr(1) - print *, "timstep_arr(100) = ", timstep_arr(100) - print *, "" - end if + call log_debug("Redoing step: Maxval(timscal) > tol * factolmax") if (iredo > 100) then stop "Redoing step: Maxval(timscal) is not lesser than tol * factolmax " // & "after 100 redos" @@ -260,7 +252,7 @@ subroutine doStep(this) timstep_arr = timstep time = time + timstep - if (debug_mode) call msg_time_info + call log_debug("msg_time_info") if (.not. suppression_mode) call write_kin_profile_at_time_index call set_first_iteration_true call calculate_total_toroidal_torque(time_ind) @@ -300,7 +292,7 @@ subroutine copy_kin_profs_to_yprev integer :: ipoi, ieq, k - if (debug_mode) write(*,*) 'Debug: yprev loop' + call log_debug('yprev loop') do ipoi = 1, npoi do ieq = 1, nbaleqs k = nbaleqs*(ipoi - 1) + ieq @@ -395,7 +387,7 @@ subroutine write_br_dqle22_time_data implicit none - if (debug_mode) write(*,*) "Debug: writing out br time evolution data" + call log_debug("writing out br time evolution data") if (ihdf5IO .eq. 1) then !if (.false.) then @@ -536,7 +528,7 @@ subroutine write_kin_prof_data_to_disk integer :: ipoi if (ihdf5IO .eq. 1) then - if (debug_mode) print *, "Debug: Write kinetic profiles" + call log_debug("Write kinetic profiles") do ipoi = 1, npoic sqg_bthet_overcavg(ipoi) = 0.5d0*(sqrt_g_times_B_theta_over_c(ipoi) & + sqrt_g_times_B_theta_over_c(ipoi + 1)) @@ -553,8 +545,8 @@ subroutine write_kin_prof_data_to_disk write (h5_currentgrp, "(A,A,I4,A)") trim(h5_currentgrp), & "/", 1000 + time_ind, "/" - if (debug_mode) write (*, *) "Debug: h5_currentgrp ", trim(h5_currentgrp) - if (debug_mode) write (*, *) "Debug: defining KinProfiles/1000 group ", 1000 + time_ind + call log_debug("h5_currentgrp " // trim(h5_currentgrp)) + call log_debug("defining KinProfiles/1000 group") CALL h5_obj_exists(h5_id, trim(h5_currentgrp), h5_exists_log) if (.not. h5_exists_log) then @@ -588,7 +580,7 @@ subroutine write_kin_prof_data_to_disk CALL h5_close(h5_id) CALL h5_deinit() - if (debug_mode) write (*, *) "Debug: finished writing KinProfiles" + call log_debug("finished writing KinProfiles") else do ipoi = 1, npoic @@ -609,7 +601,7 @@ subroutine write_kin_profile_at_time_index implicit none - if (debug_mode) write(*,*) "Debug: Write kinetic profiles at time index: ", time_ind + call log_debug("Write kinetic profiles at time index") if (modulo(time_ind, save_prof_time_step) .eq. 0) then call write_kin_prof_data_to_disk end if @@ -745,10 +737,7 @@ subroutine determine_timscal end if end do - if (debug_mode) then - write(*,*) "maxval(timscal) = ", maxval(timscal) - write(*,*) "tol*factolmax = ", tol*factolmax - end if + call log_debug("determine_timscal complete") end subroutine @@ -805,8 +794,7 @@ subroutine set_time_step write(*,*) "constant time step = ", timstep end if - if (debug_mode) write(*,*) 'Debug: timstep', real(timstep), ' timescale', real(timescale), & - 'tolerance', real(tol) + call log_debug('timstep set') end subroutine @@ -858,7 +846,7 @@ subroutine write_time_info_to_h5 CALL h5_open_rw(path2out, h5_id) if (.not. firstiterationdone) then - if (diagnostics_output) then + if (data_verbosity >= 2) then CALL h5_define_unlimited_matrix(h5_id, trim(h5_currentgrp), & H5T_NATIVE_DOUBLE, (/6, -1/), time_dataset_id) else @@ -872,7 +860,7 @@ subroutine write_time_info_to_h5 ! where the whole data is written at once. In the latter ! the data for one variable is saved in one row, i.e. there ! are length(variable) number of columns. - if (diagnostics_output) then + if (data_verbosity >= 2) then CALL h5_append_double_1(time_dataset_id, (/time_ind*1.d0, timstep, & timscal_dql, timscal(1), rate_dql, time/), time_ind) else @@ -946,7 +934,7 @@ subroutine create_group_structure_timeevol implicit none - if (debug_mode) write (*, *) "Debug: Creating group structure for TimeEvol" + call log_debug("Creating group structure for TimeEvol") if (numres .eq. 1) then write (h5_mode_groupname, "(A,I0,A,I0)") "f_", m_vals(1), "_", n_vals(1) @@ -958,14 +946,14 @@ subroutine create_group_structure_timeevol CALL h5_open_rw(path2out, h5_id) if (.not. suppression_mode) then - if (debug_mode) write(*,*) "Debug: h5_mode_groupname ", trim(h5_mode_groupname) + call log_debug("h5_mode_groupname " // trim(h5_mode_groupname)) CALL h5_create_parent_groups(h5_id, trim(h5_mode_groupname) //'/') CALL h5_create_parent_groups(h5_id, trim(h5_mode_groupname)//"/KinProfiles/") call create_group_if_not_existent(trim(h5_mode_groupname)//"/LinearProfiles/") call create_group_if_not_existent("/init_params") else - if (debug_mode) write (*,*) "Debug: h5_mode_groupname: ", trim(h5_mode_groupname) + call log_debug("h5_mode_groupname: " // trim(h5_mode_groupname)) call create_group_if_not_existent(trim(h5_mode_groupname)) call create_group_if_not_existent("/init_params") end if @@ -973,7 +961,7 @@ subroutine create_group_structure_timeevol CALL h5_close(h5_id) CALL h5_deinit() - if (debug_mode) write (*, *) "Debug: finished creating group structure for TimeEvol" + call log_debug("finished creating group structure for TimeEvol") end subroutine diff --git a/QL-Balance/src/base/wave_code_data_64bit.f90 b/QL-Balance/src/base/wave_code_data_64bit.f90 index df64108a..ca11f2f7 100644 --- a/QL-Balance/src/base/wave_code_data_64bit.f90 +++ b/QL-Balance/src/base/wave_code_data_64bit.f90 @@ -5,7 +5,7 @@ subroutine get_wave_code_data(imin, imax) use wave_code_data - use control_mod, only: debug_mode + use logger_m, only: log_debug implicit none @@ -13,11 +13,11 @@ subroutine get_wave_code_data(imin, imax) integer :: k do k = imin, imax - if (debug_mode) write(*,*) "Debug: in get_wave_code_data for mode ", k + call log_debug("in get_wave_code_data for mode") call clear_wave_code_data(flre_cd_ptr(k)) - if (debug_mode) write(*,*) "Debug: calc_wave_code_data_for_mode" + call log_debug("calc_wave_code_data_for_mode") call calc_wave_code_data_for_mode(flre_cd_ptr(k), trim(flre_path), len(trim(flre_path)), m_vals(k), n_vals(k)) - if (debug_mode) write(*,*) "Debug: after calc_wave_code_data_for_mode" + call log_debug("after calc_wave_code_data_for_mode") end do flre_call_ind = flre_call_ind + 1 @@ -33,10 +33,11 @@ subroutine initialize_wave_code_interface(nrad, r_grid) use wave_code_data use h5mod - use control_mod, only: readfromtimestep, debug_mode, ihdf5IO, wave_code, & + use control_mod, only: readfromtimestep, ihdf5IO, wave_code, & kim_profiles_from_balance, kim_n_modes, kim_m_list, kim_n_list, & type_of_run use kim_wave_code_adapter_m, only: kim_initialize, kim_load_vacuum_fields + use logger_m, only: log_debug, log_error implicit none @@ -45,7 +46,7 @@ subroutine initialize_wave_code_interface(nrad, r_grid) character(1024) :: profile_path = "./profiles/" integer :: k - if (debug_mode) write(*,*) "Debug: Coming into initialize_wave_code_interface" + call log_debug("Coming into initialize_wave_code_interface") select case (trim(wave_code)) case ('KiLCA') @@ -55,10 +56,10 @@ subroutine initialize_wave_code_interface(nrad, r_grid) !call read_background_profiles(path2profs); if (ihdf5IO .eq. 1) then if (readfromtimestep .eq. 0) then - if(debug_mode) write(*,*) "reading initial profiles" + call log_debug("reading initial profiles") call read_background_profiles_h5 else - if(debug_mode) write(*,*) "reading time evolved profiles" + call log_debug("reading time evolved profiles") call read_background_profiles_h5_timeevol(readfromtimestep) end if else @@ -67,14 +68,14 @@ subroutine initialize_wave_code_interface(nrad, r_grid) call interp_background_profiles() ! interpolate the initial profiles to the balance grid - if (debug_mode) write(*,*) "Debug: after interp_background_profiles" + call log_debug("after interp_background_profiles") ! vacuum fields for the whole spectrum: do k = 1, dim_mn call clear_wave_code_data(vac_cd_ptr(k)); call calc_wave_code_data_for_mode(vac_cd_ptr(k), trim(vac_path), len(trim(vac_path)), m_vals(k), n_vals(k)); end do - if (debug_mode) write(*,*) "Debug: before get_background_magnetic_fields_from_wave_code" + call log_debug("before get_background_magnetic_fields_from_wave_code") call get_background_magnetic_fields_from_wave_code(vac_cd_ptr(1), dim_r, r, B0t, B0z, B0); call get_collision_frequences_from_wave_code(vac_cd_ptr(1), dim_r, r, nui, nue); vac_call_ind = vac_call_ind + 1; @@ -121,12 +122,11 @@ subroutine initialize_wave_code_interface(nrad, r_grid) call kim_load_vacuum_fields() case default - write(*,*) "ERROR: Unknown wave_code: ", trim(wave_code) - stop 1 + call log_error("Unknown wave_code: " // trim(wave_code)) end select - if (debug_mode) write(*,*) "Debug: Going out of initialize_wave_code_interface" + call log_debug("Going out of initialize_wave_code_interface") end subroutine !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -242,7 +242,6 @@ subroutine update_background_files(path) use grid_mod, only: Ercov use plasma_parameters, only: params_b use baseparam_mod - use control_mod, only: debug_mode implicit none @@ -436,10 +435,11 @@ subroutine read_antenna_modes(path) use wave_code_data, only: dim_mn, m_vals, n_vals; use resonances_mod, only: numres - use control_mod, only: debug_mode + use logger_m, only: log_debug implicit none; character(1024) :: path; character(1024) :: buffer; + character(64) :: buf_m, buf_n integer :: l, i1, i2, i3; dim_mn = numres @@ -462,7 +462,10 @@ subroutine read_antenna_modes(path) i3 = index(buffer, ')'); read (buffer(i1 + 1:i2 - 1), *) m_vals(l); read (buffer(i2 + 1:i3 - 1), *) n_vals(l); - if (debug_mode) write(*,*) "Debug: modes.in -> m = ", m_vals(l), ", n = ", n_vals(l) + write(buf_m, '(I0)') m_vals(l) + write(buf_n, '(I0)') n_vals(l) + call log_debug("modes.in -> m = " // trim(buf_m) // & + ", n = " // trim(buf_n)) end do close (10); end subroutine @@ -472,13 +475,13 @@ subroutine read_antenna_modes(path) subroutine read_background_profiles(path) use wave_code_data, only: rq, iq, rn, in, rTi, iTi, rTe, iTe, rVth, iVth, rVz, iVz, rep, idPhi0; - use control_mod, only: debug_mode + use logger_m, only: log_debug implicit none; character(1024) :: path; character(1024) :: file; integer :: l; - if (debug_mode) write(*,*) "Debug: Read background profiles from .dat files" + call log_debug("Read background profiles from .dat files") file = trim(path)//'q.dat'; call find_file_length(file, l); @@ -525,7 +528,8 @@ subroutine read_background_profiles_h5 use h5mod use wave_code_data, only: rq, iq, rn, in, rTi, iTi, rTe, iTe, rVth, iVth, rVz, iVz, rep, idPhi0; - use control_mod, only: paramscan, debug_mode + use control_mod, only: paramscan + use logger_m, only: log_debug implicit none; character(len=*), parameter :: groupname = "/preprocprof" @@ -537,7 +541,7 @@ subroutine read_background_profiles_h5 !Er, is read from hdf5 file ! is the same for every fac_vz - if (debug_mode) write(*,*) 'Debug: Read background profiles from hdf5 file' + call log_debug('Read background profiles from hdf5 file') CALL h5_init() !CALL h5_check() @@ -587,7 +591,7 @@ subroutine read_background_profiles_h5 CALL h5_close_group(group_id_1) CALL h5_close(h5_id) CALL h5_deinit() - if (debug_mode) write (*, *) "Debug: finished reading background profiles from hdf5" + call log_debug("finished reading background profiles from hdf5") idPhi0 = -idPhi0; ! Er was loaded from Er.dat @@ -604,8 +608,9 @@ subroutine read_background_profiles_h5_timeevol(tstep) use h5mod use wave_code_data, only: rq, iq, rn, in, rTi, iTi, rTe, iTe, rVth, iVth, rVz, iVz, rep, idPhi0, m_vals, n_vals - use control_mod, only: paramscan, debug_mode + use control_mod, only: paramscan use baseparam_mod, only: rtor + use logger_m, only: log_debug, log_info, log_warning implicit none; integer, intent(in) :: tstep @@ -614,7 +619,7 @@ subroutine read_background_profiles_h5_timeevol(tstep) integer :: lb, ub; - write(*,*) 'Read time evolved background profiles from hdf5 file' + call log_info('Read time evolved background profiles from hdf5 file') write (groupname, '(A,I1,A,I1,A,I0,"/")') 'f_', m_vals(1), '_', n_vals(1), '/fort.1000/', & 1000 + tstep @@ -626,9 +631,9 @@ subroutine read_background_profiles_h5_timeevol(tstep) CALL h5_obj_exists(h5_id, trim(groupname), h5_exists_log) if (.not. h5_exists_log) then - write(*,*) "group ", trim(groupname), " does not exist." + call log_warning("group " // trim(groupname) // " does not exist.") else - write(*,*) "group ", trim(groupname), "does exist. Continue with reading" + call log_info("group " // trim(groupname) // " does exist. Continue with reading") end if ! open group where the profiles are located CALL h5_open_group(h5_id, trim(groupname), group_id_1) @@ -694,7 +699,7 @@ subroutine read_background_profiles_h5_timeevol(tstep) CALL h5_close(h5_id) CALL h5_deinit() - if (debug_mode) write (*, *) "Debug: finished reading background profiles" + call log_debug("finished reading background profiles") idPhi0 = -idPhi0; ! Er was loaded from Er.dat diff --git a/QL-Balance/src/base/writeData.f90 b/QL-Balance/src/base/writeData.f90 index 4c013734..c9729ec3 100644 --- a/QL-Balance/src/base/writeData.f90 +++ b/QL-Balance/src/base/writeData.f90 @@ -2,7 +2,8 @@ subroutine write_fields_currs_transp_coefs_to_h5 use grid_mod, only: npoib, dqle11, dqle12, dqle22, dqli11, dqli12, dqli22, & T_EM_phi_e, T_EM_phi_i use baseparam_mod, only: e_charge, p_mass, c, e_mass, ev - use control_mod, only: ihdf5IO, diagnostics_output, misalign_diffusion + use control_mod, only: ihdf5IO, data_verbosity, misalign_diffusion + use logger_m, only: log_debug use wave_code_data use QLbalance_diag, only: iunit_diag use time_evolution, only: time_ind @@ -17,7 +18,7 @@ subroutine write_fields_currs_transp_coefs_to_h5 CALL h5_init() CALL h5_open_rw(path2out, h5_id) - if (debug_mode) print *, "Debug: ", trim(h5_mode_groupname) + call log_debug(trim(h5_mode_groupname)) tempch = "/"//trim(h5_mode_groupname)//"/LinearProfiles" write (tempch, '(A,"/",I0,"/")') trim(tempch), time_ind @@ -53,7 +54,7 @@ subroutine write_fields_currs_transp_coefs_to_h5 if (misalign_diffusion .eqv. .true.) then call write_misalignment_data_to_hdf5(tempch) end if - if (diagnostics_output) then + if (data_verbosity >= 2) then call write_dql_Br_Jp_profiles_to_hdf5(tempch) end if @@ -78,7 +79,7 @@ end subroutine write_fields_currs_transp_coefs_to_h5 subroutine write_misalignment_data_to_hdf5(tempch) use h5mod - use control_mod, only: debug_mode + use logger_m, only: log_debug use grid_mod use wave_code_data @@ -86,7 +87,7 @@ subroutine write_misalignment_data_to_hdf5(tempch) character(*), intent(in) :: tempch - if (debug_mode) write(*,*) "Writing misalignment diffusion to hdf5" + call log_debug("Writing misalignment diffusion to hdf5") CALL h5_add_double_1(h5_id, trim(tempch)//"D11_MA", d11_misalign, lbound(d11_misalign), ubound(d11_misalign)) CALL h5_add_double_1(h5_id, trim(tempch)//"Es_pert_flux_real", real(Es_pert_flux), & lbound(real(Es_pert_flux)), ubound(dreal(Es_pert_flux))) @@ -102,7 +103,7 @@ subroutine write_misalignment_data_to_hdf5(tempch) dimag(Br), lbound(dimag(Br)), ubound(dimag(Br))) CALL h5_add_double_1(h5_id, trim(tempch)//"Es_imag", & dimag(Es), lbound(dimag(Es)), ubound(dimag(Es))) - if (debug_mode) write(*,*) "Carry on from writing misalignment diffusion to hdf5" + call log_debug("Carry on from writing misalignment diffusion to hdf5") end subroutine @@ -150,17 +151,21 @@ subroutine writefort9999 use QLbalance_diag, only: timscal_dql, timscal_dqli, ind_dqle, ind_dqli use time_evolution, only: dqle11_prev, dqli11_prev, determine_Dql_diagnostic use h5mod + use logger_m, only: log_debug implicit none integer :: ipoi + character(256) :: buf call determine_Dql_diagnostic - if (debug_mode) print *, 'Debug: timscal_dqle = ', sngl(timscal_dql) & - , 'timscal_dqli = ', sngl(timscal_dqli) - if (debug_mode) print *, 'Debug: maximum dqle at r = ', rc(ind_dqle(1)) & - , 'maximum dqli at r = ', rc(ind_dqli(1)) + write(buf, '(A,ES12.4,A,ES12.4)') 'timscal_dqle = ', & + sngl(timscal_dql), ' timscal_dqli = ', sngl(timscal_dqli) + call log_debug(trim(buf)) + write(buf, '(A,ES12.4,A,ES12.4)') 'maximum dqle at r = ', & + rc(ind_dqle(1)), ' maximum dqli at r = ', rc(ind_dqli(1)) + call log_debug(trim(buf)) ! Edited by Markus Markl, 26.02.2021 if (ihdf5IO .eq. 1) then ! write fort.9999 data to hdf5 file @@ -198,17 +203,21 @@ subroutine writefort9999_stellarator use QLbalance_diag, only: timscal_dql, timscal_dqli, ind_dqle, ind_dqli use time_evolution_stellarator, only: dqle11_prev, dqli11_prev, determine_Dql_diagnostic use h5mod + use logger_m, only: log_debug implicit none integer :: ipoi + character(256) :: buf call determine_Dql_diagnostic - if (debug_mode) print *, 'Debug: timscal_dqle = ', sngl(timscal_dql) & - , 'timscal_dqli = ', sngl(timscal_dqli) - if (debug_mode) print *, 'Debug: maximum dqle at r = ', rc(ind_dqle(1)) & - , 'maximum dqli at r = ', rc(ind_dqli(1)) + write(buf, '(A,ES12.4,A,ES12.4)') 'timscal_dqle = ', & + sngl(timscal_dql), ' timscal_dqli = ', sngl(timscal_dqli) + call log_debug(trim(buf)) + write(buf, '(A,ES12.4,A,ES12.4)') 'maximum dqle at r = ', & + rc(ind_dqle(1)), ' maximum dqli at r = ', rc(ind_dqli(1)) + call log_debug(trim(buf)) ! Edited by Markus Markl, 26.02.2021 if (ihdf5IO .eq. 1) then ! write fort.9999 data to hdf5 file diff --git a/QL-Balance/src/stellarator/balance_eqs_source_terms_stell.f90 b/QL-Balance/src/stellarator/balance_eqs_source_terms_stell.f90 index 4050fdae..0a0d167e 100644 --- a/QL-Balance/src/stellarator/balance_eqs_source_terms_stell.f90 +++ b/QL-Balance/src/stellarator/balance_eqs_source_terms_stell.f90 @@ -4,7 +4,8 @@ subroutine det_balance_eqs_source_terms_stell use grid_mod, only : y, dery, dery_equisource, nbaleqs, iboutype, npoic use plasma_parameters, only: params - use control_mod, only: ihdf5IO, diagnostics_output, debug_mode + use control_mod, only: ihdf5IO, data_verbosity + use logger_m, only: log_debug use h5mod use matrix_mod use time_evolution_stellarator, only: set_momentum_source_to_zero @@ -16,7 +17,7 @@ subroutine det_balance_eqs_source_terms_stell real(dp) :: x character(len=1024) :: tempch - if (debug_mode) write(*,*) "Debug: Generating starting source" + call log_debug("Generating starting source") if(iboutype.eq.1) then npoi=npoic-1 @@ -31,11 +32,11 @@ subroutine det_balance_eqs_source_terms_stell enddo enddo - if (debug_mode) print *, "Debug: Before initialize_rhs_stell" + call log_debug("Before initialize_rhs_stell") call initialize_rhs_stell(y,dery) dery_equisource=0.d0 - if (debug_mode) print *, "Debug: Before rhs_balance_stell" + call log_debug("Before rhs_balance_stell") call rhs_balance_stell(x,y,dery) do k=1,nz @@ -52,8 +53,8 @@ subroutine det_balance_eqs_source_terms_stell enddo end if - if (diagnostics_output) then - if (debug_mode) write(*,*) "Debug: Writing equisource" + if (data_verbosity >= 2) then + call log_debug("Writing equisource") if (ihdf5IO .eq. 1) then tempch = "/"//trim(h5_mode_groupname)//"/equisource.dat" diff --git a/QL-Balance/src/stellarator/time_evol_stell.f90 b/QL-Balance/src/stellarator/time_evol_stell.f90 index 79a8e288..c233e653 100644 --- a/QL-Balance/src/stellarator/time_evol_stell.f90 +++ b/QL-Balance/src/stellarator/time_evol_stell.f90 @@ -36,8 +36,9 @@ subroutine initTimeEvolution(this) use QLbalance_diag, only: write_diag, write_diag_b use KAMEL_hdf5_tools, only: h5overwrite use h5mod, only: mode_m, mode_n - use control_mod, only: gyro_current_study, write_gyro_current, debug_mode, & + use control_mod, only: gyro_current_study, write_gyro_current, & ihdf5IO + use logger_m, only: log_debug use wave_code_data, only: m_vals, n_vals use plasma_parameters, only: write_initial_parameters, alloc_hold_parameters, & params, params_begbeg, init_background_profiles @@ -82,7 +83,7 @@ subroutine initTimeEvolution(this) if (ihdf5IO .eq. 1) then call create_group_structure_timeevol end if - if (debug_mode) write(*,*) 'Debug: mode_m = ', mode_m, 'mode_n = ', mode_n + call log_debug('mode_m/mode_n set') call allocate_prev_variables call init_background_profiles @@ -146,7 +147,7 @@ subroutine runTimeEvolution(this) call write_br_dqle22_time_data call message_Br_Dqle_values - if (diagnostics_output)then + if (data_verbosity >= 2) then call writefort9999_stellarator end if @@ -162,7 +163,7 @@ subroutine runTimeEvolution(this) params_beg = params print *, "" - if (debug_mode) write(*,*) "Debug: Timstep before evolvestep is ", timstep, " eps = " , eps + call log_debug("Timstep before evolvestep") call evolvestep_stell(timstep, eps) call limit_temps_from_below @@ -178,16 +179,7 @@ subroutine runTimeEvolution(this) timstep_arr = timstep_arr * factolred params = params_beg - if (debug_mode) then - print *, "Redoing step: Maxval(timscal) is not lesser than tol * factolmax" - print *, "Maxval(timscal) = ", maxval(timscal) - print *, "tol = ", tol - print *, "factolmax = ", factolmax - print *, "tol * factolmax = ", tol * factolmax - print *, "timstep_arr(1) = ", timstep_arr(1) - print *, "timstep_arr(100) = ", timstep_arr(100) - print *, "" - end if + call log_debug("Redoing step: Maxval(timscal) > tol * factolmax") if (iredo > 300) then stop "Redoing step: Maxval(timscal) is not lesser than tol * factolmax after 100 redos" end if @@ -207,7 +199,7 @@ subroutine runTimeEvolution(this) timstep_arr = timstep time = time + timstep - if (debug_mode) call msg_time_info + call log_debug("msg_time_info") if (.not. suppression_mode) call write_kin_profile_at_time_index call set_first_iteration_true call check_linear_discr_pen_ratio From 47c6f2225b288c181afc943da51f2ebe987a734c Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Thu, 26 Mar 2026 07:18:12 +0100 Subject: [PATCH 09/11] fix(test): update golden record test for new data_verbosity variable Co-Authored-By: Claude Opus 4.6 (1M context) --- test/ql-balance/golden_record/setup_runfolder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ql-balance/golden_record/setup_runfolder.py b/test/ql-balance/golden_record/setup_runfolder.py index 66661364..c7e66f52 100755 --- a/test/ql-balance/golden_record/setup_runfolder.py +++ b/test/ql-balance/golden_record/setup_runfolder.py @@ -99,7 +99,7 @@ def setup_runfolder(run_path: str, nml_template: str = "") -> None: bi.set_config_nml() bi.conf.conf["balancenml"]["ramp_up_mode"] = 3 # instant max RMP coil current bi.conf.conf["balancenml"]["t_max_ramp_up"] = 1.2 - bi.conf.conf["balancenml"]["diagnostics_output"] = True # write diagnostic data + bi.conf.conf["balancenml"]["data_verbosity"] = 2 # write diagnostic data bi.conf.conf["balancenml"]["suppression_mode"] = False # write full LinearProfiles/KinProfiles bi.conf.conf["balancenml"]["save_prof_time_step"] = 1 # save profiles every time step bi.write_config_nml(path=os.path.join(run_path, "balance_conf.nml")) From a864edd8e7c5f9e04bf920d28d08b4f787584829 Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Thu, 26 Mar 2026 10:55:42 +0100 Subject: [PATCH 10/11] fix(test): handle both old and new namelist keys in golden record setup The golden record test uses main's namelist template (which has diagnostics_output) for the reference run, and the current branch's template (which has data_verbosity) for the comparison run. Set the correct key based on what's in the loaded template. Co-Authored-By: Claude Opus 4.6 (1M context) --- test/ql-balance/golden_record/setup_runfolder.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/ql-balance/golden_record/setup_runfolder.py b/test/ql-balance/golden_record/setup_runfolder.py index c7e66f52..4c58ceae 100755 --- a/test/ql-balance/golden_record/setup_runfolder.py +++ b/test/ql-balance/golden_record/setup_runfolder.py @@ -99,7 +99,12 @@ def setup_runfolder(run_path: str, nml_template: str = "") -> None: bi.set_config_nml() bi.conf.conf["balancenml"]["ramp_up_mode"] = 3 # instant max RMP coil current bi.conf.conf["balancenml"]["t_max_ramp_up"] = 1.2 - bi.conf.conf["balancenml"]["data_verbosity"] = 2 # write diagnostic data + # Use the correct key name depending on which template was loaded: + # main branch uses 'diagnostics_output', current branch uses 'data_verbosity' + if "data_verbosity" in bi.conf.conf["balancenml"]: + bi.conf.conf["balancenml"]["data_verbosity"] = 2 + else: + bi.conf.conf["balancenml"]["diagnostics_output"] = True bi.conf.conf["balancenml"]["suppression_mode"] = False # write full LinearProfiles/KinProfiles bi.conf.conf["balancenml"]["save_prof_time_step"] = 1 # save profiles every time step bi.write_config_nml(path=os.path.join(run_path, "balance_conf.nml")) From 5e69578b5f648c7da65beb840ca6a5bec57d60d9 Mon Sep 17 00:00:00 2001 From: Markus Markl Date: Thu, 26 Mar 2026 11:10:40 +0100 Subject: [PATCH 11/11] chore: remove IO refactor plan documents Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/plans/2026-03-25-io-refactor-design.md | 150 ----- docs/plans/2026-03-25-io-refactor-plan.md | 579 -------------------- 2 files changed, 729 deletions(-) delete mode 100644 docs/plans/2026-03-25-io-refactor-design.md delete mode 100644 docs/plans/2026-03-25-io-refactor-plan.md diff --git a/docs/plans/2026-03-25-io-refactor-design.md b/docs/plans/2026-03-25-io-refactor-design.md deleted file mode 100644 index 0087a6dd..00000000 --- a/docs/plans/2026-03-25-io-refactor-design.md +++ /dev/null @@ -1,150 +0,0 @@ -# IO Refactor Design: Shared Logger and Data Verbosity - -> **GitHub Issue:** #116 — Refactor IO in QL-Balance and KIM -> -> **Goal:** Replace ad-hoc `write(*,*)`/`print *` statements across both codes -> with a shared leveled logger module, and add an integer data-verbosity control -> for HDF5/file output. - ---- - -## 1. Logger Module - -New shared module at `common/logger/logger_m.f90`, built as a static library -(`kamel_logger`) and linked by both KIM and QL-Balance. - -### Log Levels - -| Constant | Value | Purpose | -|----------------|-------|---------------------------------------------------------------| -| `LVL_SILENT` | -1 | No output | -| `LVL_RESULT` | 0 | Final results only (banner, key computed quantities) | -| `LVL_ERROR` | 1 | Errors before `error stop` | -| `LVL_WARNING` | 2 | Warnings (sign mismatch, missing optional files, etc.) | -| `LVL_INFO` | 3 | Normal progress (**default**) — config summary, solver entry | -| `LVL_DEBUG` | 4 | Detailed diagnostics — per-resonance values, intermediates | -| `LVL_TRACE` | 5 | Everything — per-gridpoint dumps, inner-loop output | - -### API - -```fortran -! Level control (called once after namelist read) -call set_log_level(level) -integer function get_log_level() - -! Logging subroutines (string-only, level check is internal) -call log_error(msg) ! writes to stderr, then calls error stop -call log_warning(msg) ! writes to stderr -call log_info(msg) ! writes to stdout -call log_debug(msg) ! writes to stdout -call log_trace(msg) ! writes to stdout -call log_result(msg) ! writes to stdout (shown at LVL_RESULT and above) - -! Format helpers — return formatted strings, overloaded for real(dp), -! integer, logical, and character value types. -character(len=256) function fmt_val(label, value, unit) -``` - -Output format follows NEO-RT conventions: - -``` -[ERROR] message → stderr -[WARN ] message → stderr -[INFO ] message → stdout -[DEBUG] message → stdout -[TRACE] message → stdout -``` - -`log_result` prints the message without a prefix, for banners and key results. - -## 2. Data Verbosity - -A separate integer variable `data_verbosity` controlling how much HDF5/file -data gets written. Lives in each code's own config module, not in the shared -logger. - -### Levels - -| Value | Meaning | What gets written | -|-------|----------------------|----------------------------------------------------------------| -| 0 | Minimal | Final-state output only (the HDF5 downstream tools need) | -| 1 | Standard (**default**) | + per-timestep profiles, transport coefficients | -| 2 | Detailed | + per-mode fields (Es, Br), resonance diagnostics, currents | -| 3 | Full | + Jacobian data, intermediate solver states, gridpoint dumps | - -### Configuration - -Each code reads `log_level` and `data_verbosity` from its own namelist: - -- **QL-Balance:** `balance_conf.nml` → `BALANCENML` namelist -- **KIM:** `KIM_config.nml` → `KIM_CONFIG` namelist - -After reading, each code calls `set_log_level(log_level)`. - -The existing format-toggle variables (`ihdf5IO` in QL-Balance, `hdf5_output` -in KIM) are kept — they control *format*, not *amount*. - -## 3. Removed Variables (Clean Break) - -| Code | Removed | Replaced by | -|-------------|------------------------------------------------|--------------------------------| -| QL-Balance | `debug_mode` (logical) | `log_level` | -| QL-Balance | `diagnostics_output` (logical) | `data_verbosity` | -| KIM | `fdebug` (integer) | `log_level` | -| KIM | `fstatus` (integer) | `log_level` | -| KIM | `fdiagnostics` (integer) | `data_verbosity` | - -No backward-compatibility shims — old namelists must be updated. - -## 4. Migration Strategy - -### Classification of existing output (~880 statements across ~47 files) - -1. **Config display** (`read_config.f90`, `config_display.f90`) → - `log_info(fmt_val(...))` -2. **Progress/status** (`"Status: solve poisson"`) → `log_info(msg)` -3. **Warnings** (`"WARNING: ..."`) → `log_warning(msg)` -4. **Debug prints** (currently guarded by `if (debug_mode)` / `if (fdebug)`) → - `log_debug(msg)` or `log_trace(msg)` -5. **Error messages** before `error stop` → `log_error(msg)` -6. **HDF5 data writes** → add `if (data_verbosity >= N)` guards - -### What NOT to change - -- File I/O to unit numbers (namelist writes, data files) -- ASCII art banner → `log_result` (shown at verbosity 0) -- Third-party code (libcerf, ddeabm, slatec) - -### Order of work - -1. Create `common/logger/logger_m.f90` + CMake -2. Wire into both codes' CMakeLists -3. Migrate KIM (~27 files, ~565 statements) -4. Migrate QL-Balance (~20 files, ~316 statements) -5. Update namelists and Python interface (`balance_conf.py`, - `balance_interface.py`) -6. Update golden record test config - -## 5. File Changes - -### New files - -- `common/logger/logger_m.f90` -- `common/logger/CMakeLists.txt` - -### Config/build modifications - -- `CMakeLists.txt` — add `common/logger` subdirectory -- `KIM/src/CMakeLists.txt` — link `kamel_logger` -- `QL-Balance/CMakeLists.txt` — link `kamel_logger` -- `KIM/src/setup/config_mod.f90` — replace `fdebug`/`fstatus`/`fdiagnostics` -- `KIM/src/general/read_config.f90` — read new variables, call `set_log_level` -- `QL-Balance/src/base/control_mod.f90` — replace `debug_mode`/`diagnostics_output` -- `QL-Balance/src/base/read_config.f90` — read new variables, call `set_log_level` -- `QL-Balance/namelists/balance_conf.nml` -- `python/balance_interface/balance_interface.py` - -### Source migration (~47 files) - -- KIM: ~27 files -- QL-Balance: ~20 files diff --git a/docs/plans/2026-03-25-io-refactor-plan.md b/docs/plans/2026-03-25-io-refactor-plan.md deleted file mode 100644 index 8f3567c9..00000000 --- a/docs/plans/2026-03-25-io-refactor-plan.md +++ /dev/null @@ -1,579 +0,0 @@ -# IO Refactor Implementation Plan - -> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. - -**Goal:** Replace ad-hoc write/print statements in KIM and QL-Balance with a shared leveled logger module, and add integer data-verbosity control for HDF5 output. - -**Architecture:** A new `common/logger/logger_m.f90` static library provides leveled logging (SILENT..TRACE) and format helpers. Each code reads `log_level` and `data_verbosity` from its own namelist and calls `set_log_level()`. Old boolean/integer verbosity flags are removed (clean break). - -**Tech Stack:** Fortran 2008, CMake/Ninja, CTest, f90nml (Python) - -**Design document:** `docs/plans/2026-03-25-io-refactor-design.md` - ---- - -## Task 1: Create Logger Module - -**Files:** -- Create: `common/logger/logger_m.f90` -- Create: `common/logger/CMakeLists.txt` - -**Step 1: Write `common/logger/logger_m.f90`** - -```fortran -module logger_m - implicit none - private - - integer, parameter :: dp = kind(1.0d0) - integer, parameter :: FMT_LEN = 256 - - ! Log levels - integer, public, parameter :: LVL_SILENT = -1 - integer, public, parameter :: LVL_RESULT = 0 - integer, public, parameter :: LVL_ERROR = 1 - integer, public, parameter :: LVL_WARNING = 2 - integer, public, parameter :: LVL_INFO = 3 - integer, public, parameter :: LVL_DEBUG = 4 - integer, public, parameter :: LVL_TRACE = 5 - - integer :: current_level = LVL_INFO - - public :: set_log_level, get_log_level - public :: log_error, log_warning, log_info, log_debug, log_trace, log_result - - interface fmt_val - module procedure fmt_val_real, fmt_val_int, fmt_val_logical, fmt_val_str - end interface fmt_val - public :: fmt_val - -contains - - subroutine set_log_level(level) - integer, intent(in) :: level - current_level = max(LVL_SILENT, min(LVL_TRACE, level)) - end subroutine set_log_level - - function get_log_level() result(level) - integer :: level - level = current_level - end function get_log_level - - subroutine log_error(msg) - character(*), intent(in) :: msg - write(0, '(A)') '[ERROR] ' // trim(msg) - error stop - end subroutine log_error - - subroutine log_warning(msg) - character(*), intent(in) :: msg - if (current_level >= LVL_WARNING) write(0, '(A)') '[WARN ] ' // trim(msg) - end subroutine log_warning - - subroutine log_info(msg) - character(*), intent(in) :: msg - if (current_level >= LVL_INFO) write(6, '(A)') '[INFO ] ' // trim(msg) - end subroutine log_info - - subroutine log_debug(msg) - character(*), intent(in) :: msg - if (current_level >= LVL_DEBUG) write(6, '(A)') '[DEBUG] ' // trim(msg) - end subroutine log_debug - - subroutine log_trace(msg) - character(*), intent(in) :: msg - if (current_level >= LVL_TRACE) write(6, '(A)') '[TRACE] ' // trim(msg) - end subroutine log_trace - - subroutine log_result(msg) - character(*), intent(in) :: msg - if (current_level >= LVL_RESULT) write(6, '(A)') trim(msg) - end subroutine log_result - - ! --- Format helpers --- - - function fmt_val_real(label, value, unit) result(s) - character(*), intent(in) :: label - real(dp), intent(in) :: value - character(*), intent(in), optional :: unit - character(len=FMT_LEN) :: s - character(len=20) :: vbuf - write(vbuf, '(ES15.8)') value - if (present(unit)) then - s = trim(label) // ' = ' // trim(adjustl(vbuf)) // ' ' // trim(unit) - else - s = trim(label) // ' = ' // trim(adjustl(vbuf)) - end if - end function fmt_val_real - - function fmt_val_int(label, value, unit) result(s) - character(*), intent(in) :: label - integer, intent(in) :: value - character(*), intent(in), optional :: unit - character(len=FMT_LEN) :: s - character(len=20) :: vbuf - write(vbuf, '(I0)') value - if (present(unit)) then - s = trim(label) // ' = ' // trim(adjustl(vbuf)) // ' ' // trim(unit) - else - s = trim(label) // ' = ' // trim(adjustl(vbuf)) - end if - end function fmt_val_int - - function fmt_val_logical(label, value, unit) result(s) - character(*), intent(in) :: label - logical, intent(in) :: value - character(*), intent(in), optional :: unit - character(len=FMT_LEN) :: s - if (present(unit)) then - s = trim(label) // ' = ' // merge('T', 'F', value) // ' ' // trim(unit) - else - s = trim(label) // ' = ' // merge('T', 'F', value) - end if - end function fmt_val_logical - - function fmt_val_str(label, value, unit) result(s) - character(*), intent(in) :: label - character(*), intent(in) :: value - character(*), intent(in), optional :: unit - character(len=FMT_LEN) :: s - if (present(unit)) then - s = trim(label) // ' = ' // trim(value) // ' ' // trim(unit) - else - s = trim(label) // ' = ' // trim(value) - end if - end function fmt_val_str - -end module logger_m -``` - -**Step 2: Write `common/logger/CMakeLists.txt`** - -```cmake -set(LOGGER_MODULE_DIR ${CMAKE_BINARY_DIR}/modules/logger) -file(MAKE_DIRECTORY ${LOGGER_MODULE_DIR}) - -add_library(kamel_logger STATIC - ${CMAKE_CURRENT_SOURCE_DIR}/logger_m.f90 -) - -set_target_properties(kamel_logger PROPERTIES - POSITION_INDEPENDENT_CODE ON - Fortran_MODULE_DIRECTORY ${LOGGER_MODULE_DIR} - LINKER_LANGUAGE Fortran -) - -target_include_directories(kamel_logger - PUBLIC ${LOGGER_MODULE_DIR} -) -``` - -**Step 3: Build and verify** - -Run: `make clean && make all` -Expected: Build succeeds (logger is built but not yet used) - -**Step 4: Commit** - -``` -git add common/logger/ -git commit -m "feat: add shared logger module with leveled output and format helpers" -``` - ---- - -## Task 2: Wire Logger into CMake for Both Codes - -**Files:** -- Modify: `CMakeLists.txt:103-105` (add subdirectory) -- Modify: `KIM/src/CMakeLists.txt:147-156` (link library) -- Modify: `QL-Balance/CMakeLists.txt:145-167` (link library) - -**Step 1: Add `common/logger` subdirectory to top-level CMakeLists.txt** - -In `CMakeLists.txt`, after line 103 (`add_subdirectory(common/math)`), add: - -```cmake -add_subdirectory(common/logger) -``` - -So lines 103-106 become: - -```cmake -add_subdirectory(common/math) -add_subdirectory(common/logger) -add_subdirectory(common/hdf5_tools) -add_subdirectory(common/equil) -``` - -**Step 2: Link `kamel_logger` into KIM** - -In `KIM/src/CMakeLists.txt`, add `kamel_logger` to the `target_link_libraries(KIM_lib PUBLIC ...)` block (after `kamel_hdf5_tools`). - -**Step 3: Link `kamel_logger` into QL-Balance** - -In `QL-Balance/CMakeLists.txt`, add `kamel_logger` to the `target_link_libraries(ql-balance_lib PUBLIC ...)` block (after `kamel_hdf5_tools`). - -**Step 4: Build and verify** - -Run: `make all` -Expected: Build succeeds, logger library is linked into both codes. - -**Step 5: Commit** - -``` -git add CMakeLists.txt KIM/src/CMakeLists.txt QL-Balance/CMakeLists.txt -git commit -m "build: wire kamel_logger into KIM and QL-Balance" -``` - ---- - -## Task 3: Add Config Variables and Namelist Wiring for KIM - -**Files:** -- Modify: `KIM/src/setup/config_mod.f90:34` (replace fdebug/fstatus/fdiagnostics) -- Modify: `KIM/src/general/read_config.f90:27-29` (update KIM_IO namelist) -- Modify: `KIM/nmls/KIM_config.nml:34-36` (update defaults) -- Modify: `KIM/src/util/IO_collection.f90:123-131` (update HDF5 output) - -**Step 1: Update `config_mod.f90`** - -Replace the declaration at line 34: -```fortran -integer :: fdebug, fstatus, fdiagnostics -``` -with: -```fortran -integer :: log_level = 3 ! maps to LVL_INFO -integer :: data_verbosity = 1 ! standard output -``` - -**Step 2: Update `read_config.f90` namelist definition** - -In the `KIM_IO` namelist (lines 27-29), replace `fdebug, fstatus, fdiagnostics` with `log_level, data_verbosity`. - -After the namelist read (after line 69 `close(unit = 77)`), add: -```fortran -use logger_m, only: set_log_level -call set_log_level(log_level) -``` - -**Step 3: Update `KIM_config.nml`** - -Replace lines 34-36: -``` - fdebug = 1 - fstatus = 1 - fdiagnostics = 0 -``` -with: -``` - log_level = 3 - data_verbosity = 1 -``` - -**Step 4: Update `IO_collection.f90` HDF5 output** - -Replace the `fdebug`/`fstatus`/`fdiagnostics` writes (lines 123, 125, 131) with: -```fortran -call h5_add(h5grpid, 'log_level', log_level, 'Log verbosity level', 'i') -call h5_add(h5grpid, 'data_verbosity', data_verbosity, 'Data output verbosity', 'i') -``` - -**Step 5: Build and verify** - -Run: `make all` -Expected: Build succeeds. KIM reads new variables from namelist. - -**Step 6: Commit** - -``` -git commit -am "feat(KIM): replace fdebug/fstatus/fdiagnostics with log_level and data_verbosity" -``` - ---- - -## Task 4: Add Config Variables and Namelist Wiring for QL-Balance - -**Files:** -- Modify: `QL-Balance/src/base/control_mod.f90:18,22` (replace debug_mode/diagnostics_output) -- Modify: `QL-Balance/src/base/read_config.f90:3-8,23-32,37-38,72,74` (update namelist + printing) -- Modify: `QL-Balance/namelists/balance_conf.nml:41,46` (update defaults) - -**Step 1: Update `control_mod.f90`** - -Replace line 18 (`logical :: debug_mode`) with: -```fortran -integer :: log_level = 3 ! maps to LVL_INFO -``` - -Replace line 22 (`logical :: diagnostics_output`) with: -```fortran -integer :: data_verbosity = 1 ! standard output -``` - -**Step 2: Update `read_config.f90`** - -In the `use control_mod` import (lines 3-8): replace `debug_mode` and `diagnostics_output` references with `log_level, data_verbosity`. Remove `debug_mode` from the import list entirely. - -In the namelist definition (lines 23-32): replace `diagnostics_output` with `data_verbosity` and `debug_mode` with `log_level`. Remove `suppression_mode` only if it was tied to diagnostics (check first — it may be independent). - -After the namelist read (after line 38), add: -```fortran -use logger_m, only: set_log_level -call set_log_level(log_level) -``` - -Update the print statements (lines 72, 74) to use the new variable names: -```fortran -write (*, "(A,I0)") " log_level = ", log_level -write (*, "(A,I0)") " data_verbosity = ", data_verbosity -``` - -**Step 3: Update `balance_conf.nml`** - -Replace: -``` - diagnostics_output = .false. , -``` -with: -``` - data_verbosity = 1 , -``` - -Replace: -``` - debug_mode = .false. , -``` -with: -``` - log_level = 3 , -``` - -**Step 4: Build — expect errors** - -Run: `make all` -Expected: **Compilation errors** in files that still reference `debug_mode` and `diagnostics_output`. This is expected — Task 6 will fix QL-Balance source files. For now just verify the config/namelist changes compile in `control_mod.f90` and `read_config.f90` themselves. - -**Step 5: Commit (WIP)** - -``` -git commit -am "feat(QL-Balance): replace debug_mode/diagnostics_output with log_level and data_verbosity - -WIP: source files still reference old variables, will be migrated in subsequent commits" -``` - ---- - -## Task 5: Migrate KIM Source Files to Logger - -**Files to modify (~12 files with active control variable usage):** -- `KIM/src/general/config_display.f90:119-121,338-374` -- `KIM/src/kernels/kernel.f90:80,129,372,473-475,847,947-949` -- `KIM/src/electrostatic_poisson/solve_poisson.f90:11,34-35,51,168,188` -- `KIM/src/background_equilibrium/calculate_equil.f90:74,180,185` -- `KIM/src/background_equilibrium/species_mod.f90:1171,1184,1275,1373,1377` -- `KIM/src/electromagnetic/electromagnetic_solver.f90:47,222` -- `KIM/src/grid/grid_mod.f90:197,274` -- `KIM/src/grid/gengrid.f90:6,37` -- `KIM/src/math/quadpack_integration_m.f90:204,274,299,368,393,462` - -Also migrate any remaining bare `write(*,*)` and `print *` statements in these files to appropriate logger calls. - -**Migration rules:** -- `if (fstatus >= 1) write(*,*) 'Status: ...'` → `call log_info('...')` -- `if (fstatus >= 2) write(*,*) ...` → `call log_debug('...')` -- `if (fdebug == 1) ...` → `call log_debug('...')` -- `if (fdebug >= 2) ...` → `call log_debug('...')` or `call log_trace('...')` -- `if (fdebug == 3) ...` → `call log_trace('...')` -- `if (fdiagnostics == 3) ...` → `if (data_verbosity >= 3) ...` (keep as data guard, not logger) -- Bare `write(*,*) 'Warning: ...'` → `call log_warning('...')` -- Bare `write(*,*) 'Error: ...'` before `error stop` → `call log_error('...')` -- Bare `write(*,*) ...` status messages → `call log_info('...')` -- Formatted output like `write(*,"(A,ES15.8,A)") "label", val, "unit"` → `call log_info(fmt_val('label', val, 'unit'))` - -**For each file:** -1. Replace `use config_m, only: ... fdebug ...` with `use logger_m, only: log_info, log_debug, ...` (and `use config_m, only: ... data_verbosity ...` where `fdiagnostics` was used for data guards) -2. Convert write/print statements per the rules above -3. Remove bare `if (fdebug ...)` / `if (fstatus ...)` guards — the logger checks internally - -**Step 1: Migrate config_display.f90** - -Update lines 119-121 to use `log_level` and `data_verbosity` display strings. Update or remove `get_debug_string`/`get_status_string` helpers (lines 338-374) — replace with a single helper or inline. - -**Step 2: Migrate remaining KIM source files** - -Work through each file listed above, applying the migration rules. - -**Step 3: Build and verify** - -Run: `make all` -Expected: Build succeeds. No references to `fdebug`, `fstatus`, or `fdiagnostics` remain. - -**Step 4: Verify no old references remain** - -Run: `grep -rn 'fdebug\|fstatus\|fdiagnostics' KIM/src/` -Expected: No matches (except possibly comments). - -**Step 5: Run tests** - -Run: `make test` -Expected: All KIM tests pass. - -**Step 6: Commit** - -``` -git commit -am "refactor(KIM): migrate all IO to shared logger module" -``` - ---- - -## Task 6: Migrate QL-Balance Source Files to Logger - -**Files to modify (~17 files referencing debug_mode, ~9 referencing diagnostics_output):** - -Key files: -- `QL-Balance/src/base/wave_code_data_64bit.f90` (heaviest: ~20 debug_mode refs) -- `QL-Balance/src/base/ramp_coil.f90` (~25 debug_mode refs) -- `QL-Balance/src/base/paramscan.f90` (~12 debug_mode refs) -- `QL-Balance/src/base/SingleStep.f90` (~8 debug_mode refs) -- `QL-Balance/src/base/writeData.f90` (~8 debug_mode + diagnostics_output refs) -- `QL-Balance/src/base/get_dql.f90` -- `QL-Balance/src/base/diff_coeffs.f90` -- `QL-Balance/src/base/time_evolution.f90` -- `QL-Balance/src/base/calc_current_densities.f90` -- `QL-Balance/src/base/plasma_parameters.f90` -- `QL-Balance/src/base/h5mod.f90` -- `QL-Balance/src/base/balance_eqs_source_terms.f90` -- `QL-Balance/src/base/kim_wave_code_adapter.f90` -- `QL-Balance/src/base/integrate_parallel_current.f90` -- `QL-Balance/src/base/transp_coeffs_mod.f90` -- `QL-Balance/src/stellarator/balance_eqs_source_terms_stell.f90` -- `QL-Balance/src/stellarator/time_evol_stell.f90` - -**Migration rules:** -- `if (debug_mode) write(*,*) ...` → `call log_debug('...')` -- `if (debug_mode) print *, ...` → `call log_debug('...')` -- `if (diagnostics_output) call write_..._to_hdf5(...)` → `if (data_verbosity >= 2) call write_..._to_hdf5(...)` -- Bare `write(*,*) 'WARNING: ...'` → `call log_warning('...')` -- `error stop "msg"` → `call log_error('msg')` (which calls error stop internally) -- Bare status `write(*,*)` → `call log_info('...')` -- Formatted values → `call log_info(fmt_val(...))` - -**For each file:** -1. Replace `use control_mod, only: ... debug_mode ...` with `use logger_m, only: log_debug, ...` (and `use control_mod, only: ... data_verbosity ...` where `diagnostics_output` was used) -2. Convert write/print statements per the rules above -3. Remove bare `if (debug_mode)` guards — the logger checks internally - -**Step 1: Migrate files in batches** - -Start with the most-referenced files (wave_code_data_64bit, ramp_coil, paramscan) then work through the rest. - -**Step 2: Handle read_config.f90 print block (lines 41-98)** - -The large config-display block of ~50 write statements should be converted to `log_info(fmt_val(...))` calls. For example: -```fortran -! Before: -write (*, "(A,ES15.8,A)") " B_tor = ", btor, " G" -! After: -call log_info(fmt_val(' B_tor', btor, 'G')) -``` - -**Step 3: Build and verify** - -Run: `make all` -Expected: Build succeeds. No references to `debug_mode` or `diagnostics_output` remain. - -**Step 4: Verify no old references remain** - -Run: `grep -rn 'debug_mode\|diagnostics_output' QL-Balance/src/` -Expected: No matches (except possibly comments). - -**Step 5: Run tests** - -Run: `make test` -Expected: All tests pass. - -**Step 6: Commit** - -``` -git commit -am "refactor(QL-Balance): migrate all IO to shared logger module" -``` - ---- - -## Task 7: Update Python Interface and Golden Record Test - -**Files:** -- Modify: `python/balance_interface/balance_interface.py` — update any references to old namelist keys -- Modify: `test/ql-balance/golden_record/setup_runfolder.py` — update namelist key if `diagnostics_output` is set there - -**Step 1: Update `setup_runfolder.py`** - -In `setup_runfolder.py`, line 96 currently sets: -```python -bi.conf.conf["balancenml"]["diagnostics_output"] = True -``` -Replace with: -```python -bi.conf.conf["balancenml"]["data_verbosity"] = 2 -``` - -Also check if `debug_mode` is set anywhere in the test setup and replace with `log_level`. - -**Step 2: Check `balance_interface.py`** - -Search for any hardcoded references to `debug_mode` or `diagnostics_output` in namelist manipulation. The Python `debug` flag (constructor parameter) is a Python-side flag and should NOT be changed — it's independent. - -**Step 3: Update `suppression_mode` reference** - -In `setup_runfolder.py` line 97: -```python -bi.conf.conf["balancenml"]["suppression_mode"] = False -``` -`suppression_mode` is independent of logging — keep it unchanged. - -**Step 4: Run golden record test locally (if possible)** - -Run: `make test` -Expected: All tests pass including golden record. - -**Step 5: Commit** - -``` -git commit -am "fix(test): update golden record and Python interface for new IO variables" -``` - ---- - -## Task 8: Final Verification and Cleanup - -**Step 1: Full clean build** - -Run: `make clean && make all` -Expected: Build succeeds with no warnings related to unused variables. - -**Step 2: Run all tests** - -Run: `make test` -Expected: All tests pass. - -**Step 3: Verify no old variable references remain** - -Run these greps — all should return no matches (except comments): -```bash -grep -rn 'fdebug\|fstatus\|fdiagnostics' KIM/src/ --include='*.f90' -grep -rn 'debug_mode\|diagnostics_output' QL-Balance/src/ --include='*.f90' -grep -rn 'debug_mode\|diagnostics_output' python/ --include='*.py' -``` - -**Step 4: Verify logger is the only console output path** - -Run: `grep -rn 'write(\*' KIM/src/ QL-Balance/src/base/ --include='*.f90' | grep -v '!' | wc -l` -Expected: Zero or near-zero (only file I/O to specific units should remain, no `write(*,*)` to stdout). - -**Step 5: Commit any final cleanup** - -``` -git commit -am "chore: final cleanup of IO refactor" -```