I/O System Flowchart

Yambo I/O System Flowchart

High-Level I/O Workflow

┌─────────────────────────────────────────────────────────────────┐
│                    USER CODE (e.g., RT_apply.F)                 │
│                                                                 │
│  Needs to read/write database (e.g., ndb.RT_carriers)           │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                    STEP 1: io_control()                         │
│                                                                 │
│  • Set ACTION (read/write/open/close)                           │
│  • Set MODE (DUMP/VERIFY)                                       │
│  • Set COM (where to report: REP/LOG/NONE)                      │
│  • Set SEC (which sections: /1/, /1,2/, /1,2,3/)                │
│  • Set parallel permissions:                                    │
│    - COMM: MPI communicator for parallel I/O                    │
│    - DO_IT: logical flag for selective CPU I/O                  │
│                                                                 │
│  Returns: ID (database unit identifier)                         │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                    STEP 2: io_connect()                         │
│                                                                 │
│  • Build filename from descriptor (e.g., "ndb.RT_carriers")     │
│  • Search for file in multiple locations:                       │
│    1. Current job directory                                     │
│    2. SAVE directory                                            │
│    3. Alternative paths                                         │
│  • Create directories if writing                                │
│  • Open file using NetCDF/HDF5:                                 │
│    - Serial: nf90_open() / nf90_create()                        │
│    - Parallel: nf90_open_par() / nf90_create_par()              │
│                                                                 │
│  Returns: error_code (0=success, -1=not found, -6=not allowed)  │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
                    ┌────────┴────────┐
                    │                 │
                    ▼                 ▼
    ┌───────────────────────┐   ┌──────────────────────┐
    │  STEP 3a: Fragment?   │   │  STEP 3b: No Fragment│
    │                       │   │                      │
    │  io_fragment()        │   │  Direct I/O          │
    │                       │   │                      │
    │  • Opens fragment     │   │  Skip to Step 4      │
    │    file with index    │   │                      │
    │  • Returns ID_frag    │   │                      │
    └───────────┬───────────┘   └──────────┬───────────┘
                │                          │
                └──────────┬───────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                    STEP 4: Data I/O                             │
│                                                                 │
│  Choose based on data type and size:                            │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  io_elemental() - For scalars and small arrays          │    │
│  │                                                         │    │
│  │  • Integers, reals, complex, strings, logicals          │    │
│  │  • Automatic verification (CHECK, WARN)                 │    │
│  │  • Unit conversion for display                          │    │
│  │  • Error reporting (*ERR*, *WRN*)                       │    │
│  │                                                         │    │
│  │  Example:                                               │    │
│  │    call io_elemental(ID, VAR='nkpts', I0=nk)            │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                 │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │  io_bulk() - For large multi-dimensional arrays          │   │
│  │                                                          │   │
│  │  • Up to 5D arrays (I0-I5, R0-R5, C0-C5, Z0-Z5)          │   │
│  │  • HDF5 compression support                              │   │
│  │  • Partial I/O with IPOS parameter                       │   │
│  │  • Complex → real conversion for NetCDF                  │   │
│  │                                                          │   │
│  │  Example:                                                │   │
│  │    call io_bulk(ID, VAR='wavefunction', VAR_SZ=(/ng,nb/))│   │
│  │    call io_bulk(ID, C2=wf_array)                         │   │
│  └──────────────────────────────────────────────────────────┘    │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                    STEP 5: io_disconnect()                      │
│                                                                 │
│  • Close NetCDF/HDF5 file                                       │
│  • Free database unit ID                                        │
│  • Reset internal state                                         │
└─────────────────────────────────────────────────────────────────┘

Parallel I/O Decision Tree

                        START: Need to do I/O
                                 │
                                 ▼
                    ┌────────────────────────┐
                    │  How many CPUs need    │
                    │  to access the data?   │
                    └────────┬───────────────┘
                             │
              ┌──────────────┼──────────────┐
              │              │              │
              ▼              ▼              ▼
    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐
    │  Only one   │  │  Subset of  │  │  All CPUs   │
    │ CPU (master)│  │  CPUs       │  │ collectively│
    └──────┬──────┘  └──────┬──────┘  └──────┬──────┘
           │                │                │
           ▼                ▼                ▼
    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐
    │ STRATEGY 1  │  │ STRATEGY 2  │  │ STRATEGY 3  │
    │ Master-Only │  │ Selective   │  │ Parallel    │
    │             │  │ CPU I/O     │  │ HDF5        │
    └──────┬──────┘  └──────┬──────┘  └──────┬──────┘
           │                │                │
           ▼                ▼                ▼
    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐
    │ io_control( │  │ io_control( │  │ io_control( │
    │   ACTION,   │  │   ACTION,   │  │   ACTION,   │
    │   ID=ID     │  │   DO_IT=    │  │   COMM=     │
    │ )           │  │   condition,│  │   my_comm,  │
    │             │  │   ID=ID     │  │   ID=ID     │
    │ Only master │  │ )           │  │ )           │
    │ CPU does I/O│  │             │  │             │
    │             │  │ Each CPU    │  │ Requires    │
    │ Others skip │  │ with DO_IT= │  │ _PAR_IO &   │
    │             │  │ .TRUE. does │  │ _HDF5_IO    │
    │ Broadcast   │  │ I/O         │  │             │
    │ after read  │  │             │  │ Collective  │
    │             │  │ Often uses  │  │ operations  │
    │ Simple      │  │ fragments   │  │             │
    │             │  │             │  │ Single file │
    └─────────────┘  └─────────────┘  └─────────────┘

Fragment I/O Pattern

┌─────────────────────────────────────────────────────────────────┐
│                    MAIN DATABASE                                │
│                    (e.g., ndb.dipoles)                          │
│                                                                 │
│  Section 1: Header (version, serial number, parameters)         │
│  Section 2: Dimensions (nk, nb, ng, etc.)                       │
│  Section 3: → Points to fragments                               │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             │ io_fragment(ID, ID_frag, i_fragment=ik)
                             │
              ┌──────────────┼──────────────┐
              │              │              │
              ▼              ▼              ▼
    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐
    │  Fragment 1 │  │  Fragment 2 │  │  Fragment N │
    │             │  │             │  │             │
    │ ndb.dipoles │  │ ndb.dipoles │  │ ndb.dipoles │
    │ _fragment_1 │  │ _fragment_2 │  │ _fragment_N │
    │             │  │             │  │             │
    │ Data for    │  │ Data for    │  │ Data for    │
    │ k-point 1   │  │ k-point 2   │  │ k-point N   │
    └─────────────┘  └─────────────┘  └─────────────┘
          │                │                │
          │                │                │
          ▼                ▼                ▼
    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐
    │   CPU 0     │  │   CPU 1     │  │   CPU N-1   │
    │             │  │             │  │             │
    │ Reads/writes│  │ Reads/writes│  │ Reads/writes│
    │ fragment 1  │  │ fragment 2  │  │ fragment N  │
    │             │  │             │  │             │
    │ Parallel    │  │ Parallel    │  │ Parallel    │
    │ access!     │  │ access!     │  │ access!     │
    └─────────────┘  └─────────────┘  └─────────────┘

Advantages: - ✅ Multiple CPUs can read/write simultaneously - ✅ No file locking conflicts - ✅ Scales well with number of k-points - ✅ Memory efficient (load only needed fragments)

Disadvantages: - ❌ Many small files (filesystem stress) - ❌ More complex bookkeeping - ❌ Requires fragment-aware code


MPI + OpenMP Thread Model

┌─────────────────────────────────────────────────────────────────┐
│                    MPI PROCESS 0                                │
│                                                                 │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  OpenMP Thread 0 (MASTER)                              │     │
│  │                                                        │     │
│  │  • Handles all I/O operations                          │     │
│  │  • Calls io_control(), io_connect(), io_bulk()         │     │
│  │  • Protected by !$omp master / !$omp critical          │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                 │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  OpenMP Thread 1                                       │     │
│  │  • Computation only (bands, G-vectors)                 │     │
│  │  • Waits at barriers                                   │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                 │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  OpenMP Thread 2                                       │     │
│  │  • Computation only                                    │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                 │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  OpenMP Thread 3                                       │     │
│  │  • Computation only                                    │     │
│  └────────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────────┘
                             │
                             │ MPI Communication
                             │
┌─────────────────────────────────────────────────────────────────┐
│                    MPI PROCESS 1                                │
│                                                                 │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  OpenMP Thread 0 (MASTER)                              │     │
│  │  • Handles I/O for this process                        │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                 │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  OpenMP Threads 1-3                                    │     │
│  │  • Computation only                                    │     │
│  └────────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────────┘

Key Points: - NetCDF/HDF5 libraries are NOT thread-safe - Only master thread of each MPI process does I/O - Use !$omp master or !$omp critical around I/O calls - OpenMP parallelizes computation (inner loops) - MPI parallelizes data distribution (k-points, q-points)


Database Section Structure

┌─────────────────────────────────────────────────────────────────┐
│                    DATABASE FILE (e.g., ndb.dipoles)            │
├─────────────────────────────────────────────────────────────────┤
│  SECTION 1: HEADER                                              │
│  ┌───────────────────────────────────────────────────────┐      │
│  │  • Code version (major.minor.patch)                   │      │
│  │  • Code revision (devel, GPL)                         │      │
│  │  • Serial number (unique DB identifier)               │      │
│  │  • Creation date                                      │      │
│  │  • Database type and format version                   │      │
│  └───────────────────────────────────────────────────────┘      │
├─────────────────────────────────────────────────────────────────┤
│  SECTION 2: DIMENSIONS                                          │
│  ┌───────────────────────────────────────────────────────┐      │
│  │  • Number of k-points (nk)                            │      │
│  │  • Number of bands (nb)                               │      │
│  │  • Number of G-vectors (ng)                           │      │
│  │  • Number of frequencies (nw)                         │      │
│  │  • Grid specifications                                │      │
│  │  • Index ranges                                       │      │
│  └───────────────────────────────────────────────────────┘      │
├─────────────────────────────────────────────────────────────────┤
│  SECTION 3: DATA                                                │
│  ┌───────────────────────────────────────────────────────┐      │
│  │  • Physical quantities (arrays, matrices)             │      │
│  │  • May be split into fragments                        │      │
│  │  • Can be very large (GB-TB)                          │      │
│  └───────────────────────────────────────────────────────┘      │
└─────────────────────────────────────────────────────────────────┘

Access patterns:
• SEC=(/1/)      → Read only header (fast, for compatibility check)
• SEC=(/1,2/)    → Read header + dimensions (setup arrays)
• SEC=(/1,2,3/)  → Read everything (full data load)

Complete Example: Reading RT Carriers Database

! ============================================================
! Example: Read carrier occupations from RT database
! ============================================================

use IO_int,      ONLY: io_control, io_connect, io_disconnect
use IO_m,        ONLY: OP_RD_CL, VERIFY, REP, io_status, IO_NO_ERROR
use electrons,   ONLY: E  ! Electronic structure
use real_time,   ONLY: RT_carriers

integer :: ID, ierr

! ──────────────────────────────────────────────────────────
! STEP 1: Setup I/O control
! ──────────────────────────────────────────────────────────
call io_control(ACTION=OP_RD_CL,     &  ! Open, read, close
                COM=REP,              &  ! Report to report file
                SEC=(/1,2,3/),        &  ! Read all sections
                MODE=VERIFY,          &  ! Verify compatibility
                ID=ID)                   ! Returns database ID

! ──────────────────────────────────────────────────────────
! STEP 2: Connect to database file
! ──────────────────────────────────────────────────────────
ierr = io_connect(desc='ndb.RT_carriers',  &  ! Database name
                  subfolder='',             &  ! In current dir
                  ID=ID)                       ! Use this ID

if (ierr /= 0) then
  call warning('RT carriers database not found')
  return
endif

! ──────────────────────────────────────────────────────────
! STEP 3: Read data using database-specific routine
! ──────────────────────────────────────────────────────────
ierr = io_RT_components('carriers', ID)

! This routine internally calls:
!   - io_elemental() for scalars (nk, nb, time, etc.)
!   - io_bulk() for arrays (occupations, energies, etc.)

! ──────────────────────────────────────────────────────────
! STEP 4: Check status and disconnect
! ──────────────────────────────────────────────────────────
if (io_status(ID) /= IO_NO_ERROR) then
  call error('Incompatible RT carriers database')
endif

call io_disconnect(ID)

! ──────────────────────────────────────────────────────────
! STEP 5: Use the data
! ──────────────────────────────────────────────────────────
! Data is now loaded into E%f (occupations), E%E (energies), etc.
! Can proceed with calculations...

Summary Diagram: I/O System Components

┌─────────────────────────────────────────────────────────────────┐
│                    YAMBO I/O SYSTEM                             │
└─────────────────────────────────────────────────────────────────┘
                             │
        ┌────────────────────┼────────────────────┐
        │                    │                    │
        ▼                    ▼                    ▼
┌───────────────┐    ┌───────────────┐    ┌───────────────┐
│  CONTROL      │    │  CONNECTION   │    │  DATA I/O     │
│  LAYER        │    │  LAYER        │    │  LAYER        │
├───────────────┤    ├───────────────┤    ├───────────────┤
│ io_control.F  │───▶│ io_connect.F  │───▶│io_elemental.F │
│               │    │               │    │io_bulk.F      │
│ • Permissions │    │ • File search │    │io_fragment.F  │
│ • Actions     │    │ • Open/create │    │               │
│ • MPI comms   │    │ • Directories │    │ • Read/write  │
│ • CPU flags   │    │ • NetCDF/HDF5 │    │ • Verify      │
└───────────────┘    └───────────────┘    └───────────────┘
        │                    │                    │
        └────────────────────┼────────────────────┘
                             │
                             ▼
                    ┌────────────────┐
                    │  DISCONNECT    │
                    ├────────────────┤
                    │io_disconnect.F │
                    │                │
                    │ • Close files  │
                    │ • Free IDs     │
                    │ • Reset state  │
                    └────────────────┘

For more details, see: doc/doxygen/IO_System_Architecture.md


📚 Documentation Pages
⏱️ Real-Time
🔗 Code API