From 20f36a64ce7c5257ed994e270c86c32485741845 Mon Sep 17 00:00:00 2001 From: dyzheng Date: Mon, 2 Mar 2026 15:31:13 +0800 Subject: [PATCH 1/3] Feature: use new format of CSR file for out_mat_hs2 --- docs/advanced/elec_properties/hs_matrix.md | 41 +- docs/advanced/input_files/input-main.md | 8 +- docs/advanced/interface/TB2J.md | 6 +- docs/advanced/interface/deeph.md | 8 +- .../interface/migration-guide-csr-format.md | 368 ++++++++++++++++++ docs/parameters.yaml | 6 +- .../source_io/module_ctrl/ctrl_scf_lcao.cpp | 26 +- .../source_io/module_hs/output_mat_sparse.cpp | 30 +- .../source_io/module_hs/output_mat_sparse.h | 11 +- source/source_io/module_hs/write_HS_R.cpp | 282 +++++++------- source/source_io/module_hs/write_HS_R.h | 50 ++- .../source_io/module_hs/write_HS_sparse.cpp | 321 --------------- source/source_io/module_hs/write_HS_sparse.h | 10 - .../source_io/module_parameter/input_conv.cpp | 2 +- .../module_parameter/input_parameter.h | 3 +- .../source_io/module_parameter/read_input.cpp | 2 +- .../read_input_item_output.cpp | 17 +- source/source_io/test/read_input_ptest.cpp | 3 +- source/source_lcao/hamilt_lcao.cpp | 16 + source/source_lcao/hamilt_lcao.h | 5 + source/source_lcao/spar_hsr.cpp | 151 ------- source/source_lcao/spar_hsr.h | 18 - 22 files changed, 660 insertions(+), 724 deletions(-) create mode 100644 docs/advanced/interface/migration-guide-csr-format.md diff --git a/docs/advanced/elec_properties/hs_matrix.md b/docs/advanced/elec_properties/hs_matrix.md index 9e19121f00..9436b0ad7b 100644 --- a/docs/advanced/elec_properties/hs_matrix.md +++ b/docs/advanced/elec_properties/hs_matrix.md @@ -26,24 +26,47 @@ The rest of the file contains the upper triangular part of the specified matrice The output of $H(R)$ and $S(R)$ matrices is controlled by the keyword [out_mat_hs2](../input_files/input-main.md#out_mat_hs2). This functionality is not available for gamma_only calculations. To generate such matrices for gamma only calculations, users should turn off [gamma_only](../input_files/input-main.md#gamma_only), and explicitly specify that gamma point is the only k point in the KPT file. -For single-point SCF calculations, if nspin = 1 or nspin = 4, two files `hrs1_nao.csr` and `sr_nao.csr` are generated, which contain the Hamiltonian matrix $H(R)$ and overlap matrix $S(R)$ respectively. For nspin = 2, three files `hrs1_nao.csr` and `hrs2_nao.csr` and `sr_nao.csr` are created, where the first two files correspodn to $H(R)$ for spin up and spin down, respectively. +### Output Format -Each file or each section of the appended file starts with three lines, the first gives the current ion/md step, the second gives the dimension of the matrix, and the last indicates how many different `R` are in the file. +The H(R) and S(R) matrices are output in standard Compressed Sparse Row (CSR) format, matching the format used by `out_dmr`. -The rest of the files are arranged in blocks. Each block starts with a line giving the lattice vector `R` and the number of nonzero matrix elements, such as: +For single-point SCF calculations: +- **nspin = 1 or nspin = 4**: Two files `hrs1_nao.csr` and `srs1_nao.csr` are generated, containing the Hamiltonian matrix $H(R)$ and overlap matrix $S(R)$ respectively. +- **nspin = 2**: Three files `hrs1_nao.csr`, `hrs2_nao.csr`, and `srs1_nao.csr` are created, where the first two files correspond to $H(R)$ for spin up and spin down, respectively. +### File Structure + +Each file starts with a header: ``` --3 1 1 1020 + --- Ionic Step 1 --- + # print H matrix in real space H(R) + 1 # number of spin directions + 1 # spin index + 100 # number of localized basis + 50 # number of Bravais lattice vector R + +[UnitCell information] + +#----------------------------------------------------------------------# +# CSR Format # +... + 0 0 0 5 + # CSR values + 1.234e-01 2.345e-02 ... + # CSR column indices + 0 5 10 ... + # CSR row pointers + 0 3 7 ... ``` -which means there are 1020 nonzero elements in the (-3,1,1) cell. +The CSR format stores a sparse m × n matrix M in row form using three arrays (values, column indices, row pointers). According to Wikipedia: -If there is no nonzero matrix element, then the next block starts immediately on the next line. Otherwise, there will be 3 extra lines in the block, which gives the matrix in CSR format. According to Wikipedia: +- The arrays **values** and **column indices** are of length NNZ (number of nonzero entries), and contain the non-zero values and the column indices of those values respectively. +- The array **row pointers** is of length m + 1 and encodes the index where each row starts. The last element is NNZ. -The CSR format stores a sparse m × n matrix M in row form using three (one-dimensional) arrays (V, COL_INDEX, ROW_INDEX). Let NNZ denote the number of nonzero entries in M. (Note that zero-based indices shall be used here.) +### Precision Control - - The arrays V and COL_INDEX are of length NNZ, and contain the non-zero values and the column indices of those values respectively. - - The array ROW_INDEX is of length m + 1 and encodes the index in V and COL_INDEX where the given row starts. This is equivalent to ROW_INDEX[j] encoding the total number of nonzeros above row j. The last element is NNZ , i.e., the fictitious index in V immediately after the last valid index NNZ - 1. +Use `out_mat_hs2 1 12` to output with 12-digit precision (default is 8). For calculations involving ionic movements, the output frequency of the matrix is controlled by [out_freq_ion](../input_files/input-main.md#out_freq_ion) and [out_app_flag](../input_files/input-main.md#out_app_flag). diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index ca5041be81..7b718173f7 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -1916,13 +1916,15 @@ ### out_mat_hs2 -- **Type**: Boolean +- **Type**: Boolean \[Integer\](optional) - **Availability**: *Numerical atomic orbital basis (not gamma-only algorithm)* -- **Description**: Whether to print files containing the Hamiltonian matrix and overlap matrix into files in the directory OUT.${suffix}. For more information, please refer to hs_matrix.md. +- **Description**: Output Hamiltonian H(R) and overlap S(R) matrices in CSR format. Optional second parameter specifies output precision (default 8). For more information, please refer to hs_matrix.md. > Note: In the 3.10-LTS version, the file names are data-HR-sparse_SPIN0.csr and data-SR-sparse_SPIN0.csr, etc. -- **Default**: False +- **Default**: False [8] - **Unit**: Ry +- **Output files**: `hrs1_nao.csr`, `hrs2_nao.csr` (if nspin=2), `srs1_nao.csr` +- **Format**: Standard CSR format with UnitCell header, compatible with `out_dmr` format ### out_mat_tk diff --git a/docs/advanced/interface/TB2J.md b/docs/advanced/interface/TB2J.md index 2848d4b573..774c109170 100644 --- a/docs/advanced/interface/TB2J.md +++ b/docs/advanced/interface/TB2J.md @@ -122,7 +122,9 @@ After the key parameter `out_mat_hs2` is turned on, the Hamiltonian matrix $H(R) suffix Fe ``` -specifies the suffix of the output, in this calculation, we set the path to the directory of the DFT calculation, which is the current directory (".") and the suffix to Fe. +specifies the suffix of the output, in this calculation, we set the path to the directory of the DFT calculation, which is the current directory (".") and the suffix to Fe. + +> **Note (ABACUS v3.9.0.25+):** Starting from ABACUS v3.9.0.25, the output format has changed to standard CSR format with filenames `hrs1_nao.csr`, `hrs2_nao.csr` (for nspin=2), and `srs1_nao.csr`. The parameter `out_mat_hs2` now supports optional precision control: `out_mat_hs2 1 8` (default 8 digits). TB2J v0.9.0+ is required to read the new format. For older TB2J versions, please use ABACUS v3.8.x or earlier. #### 2. Perform TB2J calculation: @@ -130,7 +132,7 @@ specifies the suffix of the output, in this calculation, we set the path to the abacus2J.py --path . --suffix Fe --elements Fe --kmesh 7 7 7 ``` -This first read the atomic structures from th `STRU` file, then read the Hamiltonian and the overlap matrices stored in the files named starting from `data-HR-*` and `data-SR-*` files. It also read the fermi energy from the `OUT.Fe/running_scf.log` file. +This first reads the atomic structures from the `STRU` file, then reads the Hamiltonian and overlap matrices. For ABACUS v3.9.0.25+, the matrices are stored in `hrs1_nao.csr`, `hrs2_nao.csr` (nspin=2), and `srs1_nao.csr` files. For older versions, they are in `data-HR-*` and `data-SR-*` files. It also reads the fermi energy from the `OUT.Fe/running_scf.log` file. With the command above, we can calculate the $J$ with a $7 \times 7 \times 7$ k-point grid. This allows for the calculation of exchange between spin pairs between $7 \times 7 \times 7$ supercell. Note: the kmesh is not dense enough for a practical calculation. For a very dense k-mesh, the `--rcut` option can be used to set the maximum distance of the magnetic interactions and thus reduce the computation cost. But be sure that the cutoff is not too small. diff --git a/docs/advanced/interface/deeph.md b/docs/advanced/interface/deeph.md index 02d627272b..aa60ab6de5 100644 --- a/docs/advanced/interface/deeph.md +++ b/docs/advanced/interface/deeph.md @@ -16,7 +16,13 @@ The first stage is during the data preparation phase, where we need to run a ser out_mat_hs2 1 ``` -Files named data-HR-sparse_SPIN`${x}`.csr and data-SR-sparse_SPIN`${x}`.csr will be generated, which contain the Hamiltonian and overlap matrices respectively in csr format. `${x}` takes value of 0 or 1, based on the spin component. More details on this keyword can be found in the [list of input keywords](../input_files/input-main.md#out_mat_hs2). +**For ABACUS v3.9.0.25+:** Files named `hrs1_nao.csr`, `hrs2_nao.csr` (for nspin=2), and `srs1_nao.csr` will be generated in `OUT.${suffix}/` directory, containing the Hamiltonian and overlap matrices in standard CSR format. You can optionally specify precision: `out_mat_hs2 1 8` (default 8 digits). + +**For ABACUS v3.8.x and earlier:** Files named `data-HR-sparse_SPIN${x}.csr` and `data-SR-sparse_SPIN${x}.csr` will be generated, where `${x}` takes value of 0 or 1 based on the spin component. + +> **Note:** DeepH v1.0.0+ is required to read the new CSR format from ABACUS v3.9.0.25+. For older DeepH versions, please use ABACUS v3.8.x or earlier. + +More details on this keyword can be found in the [list of input keywords](../input_files/input-main.md#out_mat_hs2). The second stage is during the inference phase. After DeepH training completes, we can apply the model to predict the Hamiltonian on other systems. For that purpose, we also need the overlap matrices from the new systems, but no SCF calculation is required. diff --git a/docs/advanced/interface/migration-guide-csr-format.md b/docs/advanced/interface/migration-guide-csr-format.md new file mode 100644 index 0000000000..b93b02c2d0 --- /dev/null +++ b/docs/advanced/interface/migration-guide-csr-format.md @@ -0,0 +1,368 @@ +# Migration Guide: New CSR Format for H(R) and S(R) Matrices + +## Overview + +Starting from ABACUS v3.9.0.25, the output format for Hamiltonian H(R) and overlap S(R) matrices has been unified to use standard CSR (Compressed Sparse Row) format, matching the format used by `out_dmr` for density matrices. + +This change affects downstream tools that read H(R) and S(R) matrices, including: +- TB2J (magnetic exchange parameters) +- DeepH (machine learning Hamiltonian) +- pyATB (tight-binding analysis) +- Custom analysis scripts + +## What Changed + +### File Names + +**Old format (ABACUS ≤ v3.8.x):** +``` +OUT.${suffix}/data-HR-sparse_SPIN0.csr +OUT.${suffix}/data-HR-sparse_SPIN1.csr (nspin=2 only) +OUT.${suffix}/data-SR-sparse_SPIN0.csr +``` + +**New format (ABACUS ≥ v3.9.0.25):** +``` +OUT.${suffix}/hrs1_nao.csr +OUT.${suffix}/hrs2_nao.csr (nspin=2 only) +OUT.${suffix}/srs1_nao.csr +``` + +### File Format + +Both old and new formats use CSR structure, but with different headers and metadata. + +#### Old Format Header +``` +STEP: 0 +Matrix Dimension of H(R): 26 +Matrix number of H(R): 183 +0 0 0 41 +[sparse data] +``` + +#### New Format Header +``` + --- Ionic Step 1 --- + # print H matrix in real space H(R) + 1 # number of spin directions + 1 # spin index + 26 # number of localized basis + 183 # number of Bravais lattice vector R + + user_defined_lattice + 5.39761 + 0 0.5 0.5 + 0.5 0 0.5 + 0.5 0.5 0 + Si + 2 + Direct + 0 0 0 + 0.25 0.25 0.25 + + #----------------------------------------------------------------------# + # CSR Format # + # The outer loop corresponds to the number of Bravais lattice vectors. # + # The first line contains the index of the Bravais lattice vector # + # (Rx, Ry, Rz), followed by the number of non-zero elements. # + # The subsequent lines consist of three blocks of data, which are # + # values, column indices, row pointers. # + #----------------------------------------------------------------------# + + 0 0 0 41 + # CSR values + [values] + # CSR column indices + [indices] + # CSR row pointers + [pointers] +``` + +### Key Differences + +1. **UnitCell Information**: New format includes complete unit cell information (lattice vectors, atomic positions) +2. **Header Format**: New format uses descriptive comments with `#` prefix +3. **Section Labels**: New format explicitly labels CSR sections ("# CSR values", "# CSR column indices", "# CSR row pointers") +4. **Ionic Step**: New format uses "Ionic Step N" instead of "STEP: N" +5. **Precision Control**: New format supports optional precision parameter: `out_mat_hs2 1 12` (default 8) + +## Migration Steps for Tool Developers + +### 1. Detect Format Version + +```python +def detect_format_version(filename): + """Detect whether file uses old or new CSR format.""" + with open(filename, 'r') as f: + first_line = f.readline().strip() + if first_line.startswith('---'): + return 'new' # v3.9.0.25+ + elif first_line.startswith('STEP:'): + return 'old' # v3.8.x and earlier + else: + raise ValueError(f"Unknown format in {filename}") +``` + +### 2. Parse New Format + +```python +def parse_new_csr_format(filename): + """Parse new CSR format (ABACUS v3.9.0.25+).""" + with open(filename, 'r') as f: + lines = f.readlines() + + # Parse header + ionic_step = None + nspin = None + ispin = None + nbasis = None + nR = None + + i = 0 + while i < len(lines): + line = lines[i].strip() + + # Parse ionic step + if line.startswith('---') and 'Ionic Step' in line: + ionic_step = int(line.split()[-2]) + + # Parse metadata + elif '#' in line: + parts = line.split('#') + if len(parts) == 2: + value_str = parts[0].strip() + comment = parts[1].strip() + + if 'number of spin directions' in comment: + nspin = int(value_str) + elif 'spin index' in comment: + ispin = int(value_str) + elif 'number of localized basis' in comment: + nbasis = int(value_str) + elif 'number of Bravais lattice vector R' in comment: + nR = int(value_str) + + # Parse unit cell (optional, can be skipped if not needed) + elif line == 'user_defined_lattice': + # Read lattice constant and vectors + i += 1 + lat0 = float(lines[i].strip()) + latvec = [] + for j in range(3): + i += 1 + latvec.append([float(x) for x in lines[i].split()]) + # Continue parsing atomic positions if needed... + + # Start of CSR data + elif line.startswith('#------') and 'CSR Format' in line: + i += 1 + break + + i += 1 + + # Parse R vectors and CSR data + R_vectors = [] + HR_data = {} + + while i < len(lines): + line = lines[i].strip() + + # R vector line: Rx Ry Rz nnz + if line and not line.startswith('#') and len(line.split()) == 4: + parts = [int(x) for x in line.split()] + Rx, Ry, Rz, nnz = parts + R_key = (Rx, Ry, Rz) + R_vectors.append(R_key) + + # Read CSR values + i += 1 + while lines[i].strip().startswith('#'): + i += 1 + values = [] + while i < len(lines) and not lines[i].strip().startswith('#'): + values.extend([float(x) for x in lines[i].split()]) + i += 1 + if len(values) >= nnz: + break + + # Read column indices + while lines[i].strip().startswith('#'): + i += 1 + col_indices = [] + while i < len(lines) and not lines[i].strip().startswith('#'): + col_indices.extend([int(x) for x in lines[i].split()]) + i += 1 + if len(col_indices) >= nnz: + break + + # Read row pointers + while lines[i].strip().startswith('#'): + i += 1 + row_ptrs = [] + while i < len(lines) and lines[i].strip(): + parts = lines[i].split() + if len(parts) == 4 and all(x.isdigit() or x.lstrip('-').isdigit() for x in parts[:3]): + # Next R vector + break + row_ptrs.extend([int(x) for x in parts]) + i += 1 + if len(row_ptrs) >= nbasis + 1: + break + + HR_data[R_key] = { + 'values': values[:nnz], + 'col_indices': col_indices[:nnz], + 'row_ptrs': row_ptrs[:nbasis+1] + } + else: + i += 1 + + return { + 'ionic_step': ionic_step, + 'nspin': nspin, + 'ispin': ispin, + 'nbasis': nbasis, + 'nR': nR, + 'R_vectors': R_vectors, + 'data': HR_data + } +``` + +### 3. Backward Compatibility + +To support both old and new formats: + +```python +def read_hamiltonian(filename): + """Read Hamiltonian matrix supporting both old and new formats.""" + format_version = detect_format_version(filename) + + if format_version == 'new': + return parse_new_csr_format(filename) + else: + return parse_old_csr_format(filename) # Your existing parser +``` + +## Tool-Specific Updates + +### TB2J + +**Required version:** TB2J v0.9.0+ + +**Changes needed:** +- Update file name detection to look for `hrs*_nao.csr` and `srs*_nao.csr` +- Update parser to handle new header format with UnitCell information +- Update parser to skip comment lines starting with `#` + +**Example:** +```python +# In abacus2J.py or relevant parser +def find_hr_files(path, suffix): + """Find HR files supporting both old and new formats.""" + import os + import glob + + # Try new format first (v3.9.0.25+) + new_pattern = os.path.join(path, f"OUT.{suffix}", "hrs*_nao.csr") + hr_files = glob.glob(new_pattern) + + if hr_files: + return sorted(hr_files), 'new' + + # Fall back to old format + old_pattern = os.path.join(path, f"OUT.{suffix}", "data-HR-sparse_SPIN*.csr") + hr_files = glob.glob(old_pattern) + + return sorted(hr_files), 'old' +``` + +### DeepH + +**Required version:** DeepH v1.0.0+ + +**Changes needed:** +- Update `parse_abacus.py` to handle new file names +- Update CSR parser to skip UnitCell section +- Update parser to handle comment lines with `#` prefix + +### pyATB + +**Changes needed:** +- Update file I/O module to detect and parse new format +- Add format version detection +- Maintain backward compatibility with old format + +## Testing Your Migration + +### 1. Generate Test Files + +Run ABACUS with both old and new versions: + +```bash +# Old version (v3.8.x) +abacus_old > log_old + +# New version (v3.9.0.25+) +abacus_new > log_new +``` + +### 2. Verify Numerical Equivalence + +The CSR data (values, indices, pointers) should be numerically identical between old and new formats, only the header differs. + +```python +def compare_csr_data(old_file, new_file): + """Verify that CSR data is numerically equivalent.""" + old_data = parse_old_csr_format(old_file) + new_data = parse_new_csr_format(new_file) + + import numpy as np + + for R in old_data['R_vectors']: + old_vals = np.array(old_data['data'][R]['values']) + new_vals = np.array(new_data['data'][R]['values']) + + assert np.allclose(old_vals, new_vals, rtol=1e-10), \ + f"Values differ for R={R}" + + assert old_data['data'][R]['col_indices'] == new_data['data'][R]['col_indices'], \ + f"Column indices differ for R={R}" + + assert old_data['data'][R]['row_ptrs'] == new_data['data'][R]['row_ptrs'], \ + f"Row pointers differ for R={R}" + + print("✓ CSR data is numerically equivalent") +``` + +## Additional Features + +### Precision Control + +The new format supports precision control via the second parameter: + +``` +out_mat_hs2 1 8 # 8 digits (default) +out_mat_hs2 1 12 # 12 digits (higher precision) +out_mat_hs2 1 5 # 5 digits (lower precision, smaller files) +``` + +This affects the output format of floating-point values in the CSR data. + +## Support and Resources + +- **ABACUS Documentation:** [https://abacus.deepmodeling.com/](https://abacus.deepmodeling.com/) +- **GitHub Issues:** [https://github.com/deepmodeling/abacus-develop/issues](https://github.com/deepmodeling/abacus-develop/issues) +- **Design Document:** `docs/plans/2026-02-28-unify-out-mat-hs2-design.md` +- **Implementation Plan:** `docs/plans/2026-02-28-unify-out-mat-hs2-plan.md` + +## Summary + +The new CSR format provides: +- ✅ Unified interface with `out_dmr` output +- ✅ Complete UnitCell information in output files +- ✅ Precision control for output values +- ✅ Better documentation with inline comments +- ✅ Clearer section labels for easier parsing + +Tool developers should update their parsers to support the new format while maintaining backward compatibility with the old format for users running older ABACUS versions. diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 1e8f2be296..f7aa4abbcc 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -2982,12 +2982,12 @@ parameters: availability: Numerical atomic orbital basis - name: out_mat_hs2 category: Output information - type: Boolean + type: "Boolean \\[Integer\\](optional)" description: | - Whether to print files containing the Hamiltonian matrix and overlap matrix into files in the directory OUT.${suffix}. For more information, please refer to hs_matrix.md. + Output H(R) and S(R) matrices in CSR format with optional precision. Optional second parameter specifies output precision (default 8). For more information, please refer to hs_matrix.md. [NOTE] In the 3.10-LTS version, the file names are data-HR-sparse_SPIN0.csr and data-SR-sparse_SPIN0.csr, etc. - default_value: "False" + default_value: "False [8]" unit: Ry availability: Numerical atomic orbital basis (not gamma-only algorithm) - name: out_mat_tk diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index 3c074fab57..6af849824d 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -10,6 +10,7 @@ #include "../module_unk/berryphase.h" // use berryphase #include "../module_hs/cal_pLpR.h" // use AngularMomentumCalculator() #include "source_io/module_hs/output_mat_sparse.h" // use ModuleIO::output_mat_sparse() +#include "../module_hs/write_HS_R.h" // use ModuleIO::write_hsr() #include "../module_mulliken/output_mulliken.h" // use cal_mag() #include "../module_wannier/to_wannier90_lcao.h" // use toWannier90_LCAO #include "../module_wannier/to_wannier90_lcao_in_pw.h" // use toWannier90_LCAO_IN_PW @@ -213,13 +214,30 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, #endif //------------------------------------------------------------------ - //! 7) Output matrices, where O can be chosen as - //! H, S, dH, dS, T, r. The format is CSR format. + //! 7a) Output H(R) and S(R) matrices in CSR format + //------------------------------------------------------------------ + if (inp.out_mat_hs2[0]) + { + const int precision = inp.out_mat_hs2[1]; + std::vector*> hr_vec = p_hamilt->getHR_vector(); + const hamilt::HContainer* sr = p_hamilt->getSR(); + + ModuleIO::write_hsr(hr_vec, sr, &ucell, precision, pv, + out_app_flag, ucell.get_iat2iwt(), ucell.nat, istep); + + // nspin=2: getHR_vector() returns new'd temporary objects + if (PARAM.inp.nspin == 2) + { + for (auto* p : hr_vec) { delete p; } + } + } + + //------------------------------------------------------------------ + //! 7b) Output dH, dS, T, r matrices (old sparse path, without H/S) //------------------------------------------------------------------ hamilt::Hamilt* p_ham_tk = static_cast*>(p_hamilt); - ModuleIO::output_mat_sparse(inp.out_mat_hs2, - inp.out_mat_dh, + ModuleIO::output_mat_sparse(inp.out_mat_dh, inp.out_mat_ds, inp.out_mat_t, inp.out_mat_r, diff --git a/source/source_io/module_hs/output_mat_sparse.cpp b/source/source_io/module_hs/output_mat_sparse.cpp index 4f8b04ec29..9f31352b43 100644 --- a/source/source_io/module_hs/output_mat_sparse.cpp +++ b/source/source_io/module_hs/output_mat_sparse.cpp @@ -6,8 +6,7 @@ namespace ModuleIO { template -void output_mat_sparse(const bool& out_mat_hsR, - const bool& out_mat_dh, +void output_mat_sparse(const bool& out_mat_dh, const bool& out_mat_ds, const bool& out_mat_t, const bool& out_mat_r, @@ -24,12 +23,6 @@ void output_mat_sparse(const bool& out_mat_hsR, { LCAO_HS_Arrays HS_Arrays; // store sparse arrays - //! generate a file containing the Hamiltonian and S(overlap) matrices - if (out_mat_hsR) - { - output_HSR(ucell, istep, pv, HS_Arrays, grid, kv, *p_dftu, p_ham); - } - //! generate a file containing the kinetic energy matrix if (out_mat_t) { @@ -44,10 +37,10 @@ void output_mat_sparse(const bool& out_mat_hsR, ucell, pv, HS_Arrays, - grid, // mohan add 2024-04-06 + grid, two_center_bundle, orb, - kv); // LiuXh add 2019-07-15 + kv); } //! generate a file containing the derivatives of the overlap matrix (in Ry/Bohr) if (out_mat_ds) @@ -56,7 +49,7 @@ void output_mat_sparse(const bool& out_mat_hsR, ucell, pv, HS_Arrays, - grid, // mohan add 2024-04-06 + grid, two_center_bundle, orb, kv); @@ -67,21 +60,13 @@ void output_mat_sparse(const bool& out_mat_hsR, { cal_r_overlap_R r_matrix; r_matrix.init(ucell, pv, orb); - if (out_mat_hsR) - { - r_matrix.out_rR_other(ucell, istep, HS_Arrays.output_R_coor); - } - else - { - r_matrix.out_rR(ucell, grid, istep); - } + r_matrix.out_rR(ucell, grid, istep); } return; } -template void output_mat_sparse(const bool& out_mat_hsR, - const bool& out_mat_dh, +template void output_mat_sparse(const bool& out_mat_dh, const bool& out_mat_ds, const bool& out_mat_t, const bool& out_mat_r, @@ -96,8 +81,7 @@ template void output_mat_sparse(const bool& out_mat_hsR, hamilt::Hamilt* p_ham, Plus_U* p_dftu); -template void output_mat_sparse>(const bool& out_mat_hsR, - const bool& out_mat_dh, +template void output_mat_sparse>(const bool& out_mat_dh, const bool& out_mat_ds, const bool& out_mat_t, const bool& out_mat_r, diff --git a/source/source_io/module_hs/output_mat_sparse.h b/source/source_io/module_hs/output_mat_sparse.h index ec9af7af72..028211cf78 100644 --- a/source/source_io/module_hs/output_mat_sparse.h +++ b/source/source_io/module_hs/output_mat_sparse.h @@ -10,10 +10,9 @@ namespace ModuleIO { -/// @brief the output interface to write the sparse matrix of H, S, T, and r -template -void output_mat_sparse(const bool& out_mat_hsR, - const bool& out_mat_dh, +/// @brief the output interface to write the sparse matrix of dH, dS, T, and r +template +void output_mat_sparse(const bool& out_mat_dh, const bool& out_mat_ds, const bool& out_mat_t, const bool& out_mat_r, @@ -23,10 +22,10 @@ void output_mat_sparse(const bool& out_mat_hsR, const TwoCenterBundle& two_center_bundle, const LCAO_Orbitals& orb, UnitCell& ucell, - const Grid_Driver& grid, // mohan add 2024-04-06 + const Grid_Driver& grid, const K_Vectors& kv, hamilt::Hamilt* p_ham, - Plus_U* p_dftu); // mohan add 20251107 + Plus_U* p_dftu); } // namespace ModuleIO #endif // OUTPUT_MAT_SPARSE_H diff --git a/source/source_io/module_hs/write_HS_R.cpp b/source/source_io/module_hs/write_HS_R.cpp index 521d3f5475..d065c07cae 100644 --- a/source/source_io/module_hs/write_HS_R.cpp +++ b/source/source_io/module_hs/write_HS_R.cpp @@ -12,112 +12,6 @@ // The 'sparse_thr' is the accuracy of the sparse matrix. // If the absolute value of the matrix element is less than or equal to the // 'sparse_thr', it will be ignored. -template -void ModuleIO::output_HSR(const UnitCell& ucell, - const int& istep, - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const Grid_Driver& grid, // mohan add 2024-04-06 - const K_Vectors& kv, - Plus_U &dftu, // mohan add 20251107 - hamilt::Hamilt* p_ham, -#ifdef __EXX - const std::vector>>>* Hexxd, - const std::vector>>>>* Hexxc, -#endif - const std::string& SR_filename, - const std::string& HR_filename_up, - const std::string HR_filename_down, - const bool& binary, - const double& sparse_thr) -{ - - ModuleBase::TITLE("ModuleIO", "output_HSR"); - ModuleBase::timer::tick("ModuleIO", "output_HSR"); - - GlobalV::ofs_running << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; - GlobalV::ofs_running << " | |" << std::endl; - GlobalV::ofs_running << " | #Print out Hamiltonian matrix H(R) or overlap matrix S(R)# |" << std::endl; - GlobalV::ofs_running << " | Use numerical atomic orbitals basis. Here R is the Bravis lattice |" << std::endl; - GlobalV::ofs_running << " | |" << std::endl; - GlobalV::ofs_running << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; - - const int nspin = PARAM.inp.nspin; - - if (nspin == 1 || nspin == 4) - { - const int spin_now = 0; - // jingan add 2021-6-4, modify 2021-12-2 - sparse_format::cal_HSR(ucell, - dftu, // mohan add 20251107 - pv, - HS_Arrays, - grid, - spin_now, - sparse_thr, - kv.nmp, - p_ham -#ifdef __EXX - , - Hexxd, - Hexxc -#endif - ); - } - else if (nspin == 2) - { - int spin_now = 1; - - // save HR of spin down first (the current spin always be down) - sparse_format::cal_HSR(ucell, - dftu, - pv, - HS_Arrays, - grid, - spin_now, - sparse_thr, - kv.nmp, - p_ham -#ifdef __EXX - , - Hexxd, - Hexxc -#endif - ); - - // cal HR of the spin up - if (PARAM.inp.vl_in_h) - { - const int ik = 0; - p_ham->refresh(); - p_ham->updateHk(ik); - spin_now = 0; - } - - sparse_format::cal_HSR(ucell, - dftu, - pv, - HS_Arrays, - grid, - spin_now, - sparse_thr, - kv.nmp, - p_ham -#ifdef __EXX - , - Hexxd, - Hexxc -#endif - ); - } - - ModuleIO::save_HSR_sparse(istep, pv, HS_Arrays, sparse_thr, binary, SR_filename, HR_filename_up, HR_filename_down); - - sparse_format::destroy_HS_R_sparse(HS_Arrays); - - ModuleBase::timer::tick("ModuleIO", "output_HSR"); - return; -} void ModuleIO::output_dSR(const int& istep, const UnitCell& ucell, @@ -300,44 +194,6 @@ void ModuleIO::output_TR(const int istep, return; } -template void ModuleIO::output_HSR( - const UnitCell& ucell, - const int& istep, - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const Grid_Driver& grid, - const K_Vectors& kv, - Plus_U &dftu, // mohan add 20251107 - hamilt::Hamilt* p_ham, -#ifdef __EXX - const std::vector>>>* Hexxd, - const std::vector>>>>* Hexxc, -#endif - const std::string& SR_filename, - const std::string& HR_filename_up, - const std::string HR_filename_down, - const bool& binary, - const double& sparse_thr); - -template void ModuleIO::output_HSR>( - const UnitCell& ucell, - const int& istep, - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const Grid_Driver& grid, - const K_Vectors& kv, - Plus_U &dftu, // mohan add 20251107 - hamilt::Hamilt>* p_ham, -#ifdef __EXX - const std::vector>>>* Hexxd, - const std::vector>>>>* Hexxc, -#endif - const std::string& SR_filename, - const std::string& HR_filename_up, - const std::string HR_filename_down, - const bool& binary, - const double& sparse_thr); - template void ModuleIO::output_SR(Parallel_Orbitals& pv, const Grid_Driver& grid, hamilt::Hamilt* p_ham, @@ -350,3 +206,141 @@ template void ModuleIO::output_SR>(Parallel_Orbitals& pv, const std::string& SR_filename, const bool& binary, const double& sparse_thr); + +#include "source_lcao/module_hcontainer/hcontainer_funcs.h" +#include "source_lcao/module_hcontainer/output_hcontainer.h" +#include "source_io/module_output/ucell_io.h" + +std::string ModuleIO::hsr_gen_fname(const std::string& prefix, + const int ispin, + const bool append, + const int istep) +{ + if (!append && istep >= 0) + { + return prefix + std::to_string(ispin + 1) + "g" + std::to_string(istep + 1) + "_nao.csr"; + } + else + { + return prefix + std::to_string(ispin + 1) + "_nao.csr"; + } +} + +template +void ModuleIO::write_hcontainer_csr(const std::string& fname, + const UnitCell* ucell, + const int precision, + hamilt::HContainer* mat_serial, + const int istep, + const int ispin, + const int nspin, + const std::string& label) +{ + std::ofstream ofs; + if (istep <= 0) + { + ofs.open(fname); + } + else + { + ofs.open(fname, std::ios::app); + } + + ofs << " --- Ionic Step " << istep + 1 << " ---" << std::endl; + ofs << " # print " << label << " matrix in real space " << label << "(R)" << std::endl; + ofs << " " << nspin << " # number of spin directions" << std::endl; + ofs << " " << ispin + 1 << " # spin index" << std::endl; + ofs << " " << mat_serial->get_nbasis() << " # number of localized basis" << std::endl; + ofs << " " << mat_serial->size_R_loop() << " # number of Bravais lattice vector R" << std::endl; + ofs << std::endl; + + ModuleIO::UcellIO::write_ucell(ofs, ucell); + ofs << std::endl; + + const double sparse_threshold = 1e-10; + hamilt::Output_HContainer out(mat_serial, ofs, sparse_threshold, precision); + out.write(); + ofs.close(); +} + +template +void ModuleIO::write_hsr(const std::vector*>& hr_vec, + const hamilt::HContainer* sr, + const UnitCell* ucell, + const int precision, + const Parallel_2D& paraV, + const bool append, + const int* iat2iwt, + const int nat, + const int istep) +{ + const int nspin = hr_vec.size(); + assert(nspin > 0); + + // Output HR (one file per spin) + for (int ispin = 0; ispin < nspin; ispin++) + { + const int nbasis = hr_vec[ispin]->get_nbasis(); + +#ifdef __MPI + Parallel_Orbitals serialV; + serialV.init(nbasis, nbasis, nbasis, paraV.comm()); + serialV.set_serial(nbasis, nbasis); + serialV.set_atomic_trace(iat2iwt, nat, nbasis); + hamilt::HContainer hr_serial(&serialV); + hamilt::gatherParallels(*hr_vec[ispin], &hr_serial, 0); +#else + hamilt::HContainer hr_serial(*hr_vec[ispin]); +#endif + + if (GlobalV::MY_RANK == 0) + { + std::string fname = PARAM.globalv.global_out_dir + + hsr_gen_fname("hrs", ispin, append, istep); + write_hcontainer_csr(fname, ucell, precision, &hr_serial, istep, ispin, nspin, "H"); + } + } + + // Output SR (single file) + { + const int nbasis = sr->get_nbasis(); + +#ifdef __MPI + Parallel_Orbitals serialV; + serialV.init(nbasis, nbasis, nbasis, paraV.comm()); + serialV.set_serial(nbasis, nbasis); + serialV.set_atomic_trace(iat2iwt, nat, nbasis); + hamilt::HContainer sr_serial(&serialV); + hamilt::gatherParallels(*sr, &sr_serial, 0); +#else + hamilt::HContainer sr_serial(*sr); +#endif + + if (GlobalV::MY_RANK == 0) + { + std::string fname = PARAM.globalv.global_out_dir + + hsr_gen_fname("srs", 0, append, istep); + write_hcontainer_csr(fname, ucell, precision, &sr_serial, istep, 0, 1, "S"); + } + } +} + +// Explicit instantiations +template void ModuleIO::write_hcontainer_csr( + const std::string&, const UnitCell*, const int, + hamilt::HContainer*, const int, const int, const int, const std::string&); +template void ModuleIO::write_hcontainer_csr>( + const std::string&, const UnitCell*, const int, + hamilt::HContainer>*, const int, const int, const int, const std::string&); + +template void ModuleIO::write_hsr( + const std::vector*>&, + const hamilt::HContainer*, + const UnitCell*, const int, const Parallel_2D&, + const bool, const int*, const int, const int); +template void ModuleIO::write_hsr>( + const std::vector>*>&, + const hamilt::HContainer>*, + const UnitCell*, const int, const Parallel_2D&, + const bool, const int*, const int, const int); + diff --git a/source/source_io/module_hs/write_HS_R.h b/source/source_io/module_hs/write_HS_R.h index fcd2dd1172..5bcdea4718 100644 --- a/source/source_io/module_hs/write_HS_R.h +++ b/source/source_io/module_hs/write_HS_R.h @@ -15,26 +15,6 @@ namespace ModuleIO { -using TAC = std::pair>; -template -void output_HSR(const UnitCell& ucell, - const int& istep, - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const Grid_Driver& grid, // mohan add 2024-04-06 - const K_Vectors& kv, - Plus_U &dftu, // mohan add 20251107 - hamilt::Hamilt* p_ham, -#ifdef __EXX - const std::vector>>>* Hexxd = nullptr, - const std::vector>>>>* Hexxc = nullptr, -#endif - const std::string& SR_filename = "srs1_nao.csr", - const std::string& HR_filename_up = "hrs1_nao.csr", - const std::string HR_filename_down = "hrs2_nao.csr", - const bool& binary = false, - const double& sparse_threshold = 1e-10); // LiuXh add 2019-07-15, modify in 2021-12-3 - void output_dHR(const int& istep, const ModuleBase::matrix& v_eff, const UnitCell& ucell, @@ -76,6 +56,36 @@ void output_SR(Parallel_Orbitals& pv, const std::string& SR_filename = "srs1_nao.csr", const bool& binary = false, const double& sparse_threshold = 1e-10); + +/// Generate filename for HR/SR CSR output. +std::string hsr_gen_fname(const std::string& prefix, + const int ispin, + const bool append, + const int istep); + +/// Write a single HContainer to CSR file with header. +template +void write_hcontainer_csr(const std::string& fname, + const UnitCell* ucell, + const int precision, + hamilt::HContainer* mat_serial, + const int istep, + const int ispin, + const int nspin, + const std::string& label); + +/// Write H(R) and S(R) in CSR format, unified with write_dmr interface. +template +void write_hsr(const std::vector*>& hr_vec, + const hamilt::HContainer* sr, + const UnitCell* ucell, + const int precision, + const Parallel_2D& paraV, + const bool append, + const int* iat2iwt, + const int nat, + const int istep); + } // namespace ModuleIO #endif diff --git a/source/source_io/module_hs/write_HS_sparse.cpp b/source/source_io/module_hs/write_HS_sparse.cpp index 382ece5a03..ea61d18b89 100644 --- a/source/source_io/module_hs/write_HS_sparse.cpp +++ b/source/source_io/module_hs/write_HS_sparse.cpp @@ -6,327 +6,6 @@ #include "source_lcao/module_rt/td_info.h" #include "single_R_io.h" -void ModuleIO::save_HSR_sparse(const int& istep, - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const double& sparse_thr, - const bool& binary, - const std::string& SR_filename, - const std::string& HR_filename_up, - const std::string& HR_filename_down = "") { - ModuleBase::TITLE("ModuleIO", "save_HSR_sparse"); - ModuleBase::timer::tick("ModuleIO", "save_HSR_sparse"); - - auto& all_R_coor_ptr = HS_Arrays.all_R_coor; - auto& output_R_coor_ptr = HS_Arrays.output_R_coor; - auto& HR_sparse_ptr = HS_Arrays.HR_sparse; - auto& SR_sparse_ptr = HS_Arrays.SR_sparse; - auto& HR_soc_sparse_ptr = HS_Arrays.HR_soc_sparse; - auto& SR_soc_sparse_ptr = HS_Arrays.SR_soc_sparse; - - int total_R_num = all_R_coor_ptr.size(); - int output_R_number = 0; - int* H_nonzero_num[2] = {nullptr, nullptr}; - int* S_nonzero_num = nullptr; - int step = istep; - - S_nonzero_num = new int[total_R_num]; - ModuleBase::GlobalFunc::ZEROS(S_nonzero_num, total_R_num); - - int spin_loop = 1; - if (PARAM.inp.nspin == 2) { - spin_loop = 2; - } - - for (int ispin = 0; ispin < spin_loop; ++ispin) { - H_nonzero_num[ispin] = new int[total_R_num]; - ModuleBase::GlobalFunc::ZEROS(H_nonzero_num[ispin], total_R_num); - } - - int count = 0; - for (auto& R_coor: all_R_coor_ptr) { - if (PARAM.inp.nspin != 4) { - for (int ispin = 0; ispin < spin_loop; ++ispin) { - if (PARAM.inp.esolver_type == "tddft" && PARAM.inp.td_stype == 1) { - auto iter - = TD_info::td_vel_op->HR_sparse_td_vel[ispin].find( - R_coor); - if (iter - != TD_info::td_vel_op->HR_sparse_td_vel[ispin] - .end()) { - for (auto& row_loop: iter->second) { - H_nonzero_num[ispin][count] - += row_loop.second.size(); - } - } - } else { - auto iter = HR_sparse_ptr[ispin].find(R_coor); - if (iter != HR_sparse_ptr[ispin].end()) { - for (auto& row_loop: iter->second) { - H_nonzero_num[ispin][count] - += row_loop.second.size(); - } - } - } - } - - auto iter = SR_sparse_ptr.find(R_coor); - if (iter != SR_sparse_ptr.end()) { - for (auto& row_loop: iter->second) { - S_nonzero_num[count] += row_loop.second.size(); - } - } - } else { - auto iter = HR_soc_sparse_ptr.find(R_coor); - if (iter != HR_soc_sparse_ptr.end()) { - for (auto& row_loop: iter->second) { - H_nonzero_num[0][count] += row_loop.second.size(); - } - } - - iter = SR_soc_sparse_ptr.find(R_coor); - if (iter != SR_soc_sparse_ptr.end()) { - for (auto& row_loop: iter->second) { - S_nonzero_num[count] += row_loop.second.size(); - } - } - } - - count++; - } - - Parallel_Reduce::reduce_all(S_nonzero_num, total_R_num); - for (int ispin = 0; ispin < spin_loop; ++ispin) { - Parallel_Reduce::reduce_all(H_nonzero_num[ispin], total_R_num); - } - - if (PARAM.inp.nspin == 2) { - for (int index = 0; index < total_R_num; ++index) { - if (H_nonzero_num[0][index] != 0 || H_nonzero_num[1][index] != 0 - || S_nonzero_num[index] != 0) { - output_R_number++; - } - } - } else { - for (int index = 0; index < total_R_num; ++index) { - if (H_nonzero_num[0][index] != 0 || S_nonzero_num[index] != 0) { - output_R_number++; - } - } - } - - std::stringstream ssh[2]; - std::stringstream sss; - if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) { - ssh[0] << PARAM.globalv.global_matrix_dir << step << "_" << HR_filename_up; - ssh[1] << PARAM.globalv.global_matrix_dir << step << "_" << HR_filename_down; - sss << PARAM.globalv.global_matrix_dir << step << "_" << SR_filename; - } else { - ssh[0] << PARAM.globalv.global_out_dir << HR_filename_up; - ssh[1] << PARAM.globalv.global_out_dir << HR_filename_down; - sss << PARAM.globalv.global_out_dir << SR_filename; - } - - GlobalV::ofs_running << " The output filename is " << ssh[0].str() << std::endl; - GlobalV::ofs_running << " The output filename is " << ssh[1].str() << std::endl; - GlobalV::ofs_running << " The output filename is " << sss.str() << std::endl; - - std::ofstream g1[2]; - std::ofstream g2; - - if (GlobalV::DRANK == 0) { - if (binary) { - int nlocal = PARAM.globalv.nlocal; - for (int ispin = 0; ispin < spin_loop; ++ispin) { - if (PARAM.inp.calculation == "md" && PARAM.inp.out_app_flag - && step) { - g1[ispin].open(ssh[ispin].str().c_str(), - std::ios::binary | std::ios::app); - } else { - g1[ispin].open(ssh[ispin].str().c_str(), std::ios::binary); - } - g1[ispin].write(reinterpret_cast(&step), sizeof(int)); - g1[ispin].write(reinterpret_cast(&nlocal), - sizeof(int)); - g1[ispin].write(reinterpret_cast(&output_R_number), - sizeof(int)); - } - - if (PARAM.inp.calculation == "md" && PARAM.inp.out_app_flag && step) { - g2.open(sss.str().c_str(), std::ios::binary | std::ios::app); - } else { - g2.open(sss.str().c_str(), std::ios::binary); - } - g2.write(reinterpret_cast(&step), sizeof(int)); - g2.write(reinterpret_cast(&nlocal), sizeof(int)); - g2.write(reinterpret_cast(&output_R_number), sizeof(int)); - } else { - for (int ispin = 0; ispin < spin_loop; ++ispin) { - if (PARAM.inp.calculation == "md" && PARAM.inp.out_app_flag - && step) { - g1[ispin].open(ssh[ispin].str().c_str(), std::ios::app); - } else { - g1[ispin].open(ssh[ispin].str().c_str()); - } - g1[ispin] << "STEP: " << step << std::endl; - g1[ispin] << "Matrix Dimension of H(R): " << PARAM.globalv.nlocal - << std::endl; - g1[ispin] << "Matrix number of H(R): " << output_R_number - << std::endl; - } - - if (PARAM.inp.calculation == "md" && PARAM.inp.out_app_flag && step) { - g2.open(sss.str().c_str(), std::ios::app); - } else { - g2.open(sss.str().c_str()); - } - g2 << "STEP: " << step << std::endl; - g2 << "Matrix Dimension of S(R): " << PARAM.globalv.nlocal << std::endl; - g2 << "Matrix number of S(R): " << output_R_number << std::endl; - } - } - - output_R_coor_ptr.clear(); - - count = 0; - for (auto& R_coor: all_R_coor_ptr) { - int dRx = R_coor.x; - int dRy = R_coor.y; - int dRz = R_coor.z; - - if (PARAM.inp.nspin == 2) { - if (H_nonzero_num[0][count] == 0 && H_nonzero_num[1][count] == 0 - && S_nonzero_num[count] == 0) { - count++; - continue; - } - } else { - if (H_nonzero_num[0][count] == 0 && S_nonzero_num[count] == 0) { - count++; - continue; - } - } - - output_R_coor_ptr.insert(R_coor); - - if (GlobalV::DRANK == 0) { - if (binary) { - for (int ispin = 0; ispin < spin_loop; ++ispin) { - g1[ispin].write(reinterpret_cast(&dRx), sizeof(int)); - g1[ispin].write(reinterpret_cast(&dRy), sizeof(int)); - g1[ispin].write(reinterpret_cast(&dRz), sizeof(int)); - g1[ispin].write( - reinterpret_cast(&H_nonzero_num[ispin][count]), - sizeof(int)); - } - - g2.write(reinterpret_cast(&dRx), sizeof(int)); - g2.write(reinterpret_cast(&dRy), sizeof(int)); - g2.write(reinterpret_cast(&dRz), sizeof(int)); - g2.write(reinterpret_cast(&S_nonzero_num[count]), - sizeof(int)); - } else { - for (int ispin = 0; ispin < spin_loop; ++ispin) { - g1[ispin] << dRx << " " << dRy << " " << dRz << " " - << H_nonzero_num[ispin][count] << std::endl; - } - g2 << dRx << " " << dRy << " " << dRz << " " - << S_nonzero_num[count] << std::endl; - } - } - - for (int ispin = 0; ispin < spin_loop; ++ispin) { - if (H_nonzero_num[ispin][count] == 0) { - // if (GlobalV::DRANK == 0) - // { - // if (!binary) - // { - // g1[ispin] << std::endl; - // g1[ispin] << std::endl; - // for (int index = 0; index < PARAM.globalv.nlocal+1; - // ++index) - // { - // g1[ispin] << 0 << " "; - // } - // g1[ispin] << std::endl; - // } - // } - } else { - if (PARAM.inp.nspin != 4) { - if (PARAM.inp.esolver_type == "tddft" && PARAM.inp.td_stype == 1) { - output_single_R(g1[ispin], - TD_info::td_vel_op - ->HR_sparse_td_vel[ispin][R_coor], - sparse_thr, - binary, - pv); - } else { - output_single_R(g1[ispin], - HR_sparse_ptr[ispin][R_coor], - sparse_thr, - binary, - pv); - } - } else { - output_single_R(g1[ispin], - HR_soc_sparse_ptr[R_coor], - sparse_thr, - binary, - pv); - } - } - } - - if (S_nonzero_num[count] == 0) { - // if (!binary) - // { - // if (GlobalV::DRANK == 0) - // { - // g2 << std::endl; - // g2 << std::endl; - // for (int index = 0; index < PARAM.globalv.nlocal+1; ++index) - // { - // g2 << 0 << " "; - // } - // g2 << std::endl; - // } - // } - } else { - if (PARAM.inp.nspin != 4) { - output_single_R(g2, - SR_sparse_ptr[R_coor], - sparse_thr, - binary, - pv); - } else { - output_single_R(g2, - SR_soc_sparse_ptr[R_coor], - sparse_thr, - binary, - pv); - } - } - - count++; - } - - if (GlobalV::DRANK == 0) { - for (int ispin = 0; ispin < spin_loop; ++ispin) { - g1[ispin].close(); - } - g2.close(); - } - - for (int ispin = 0; ispin < spin_loop; ++ispin) { - delete[] H_nonzero_num[ispin]; - H_nonzero_num[ispin] = nullptr; - } - delete[] S_nonzero_num; - S_nonzero_num = nullptr; - - ModuleBase::timer::tick("ModuleIO", "save_HSR_sparse"); - return; -} void ModuleIO::save_dH_sparse(const int& istep, const Parallel_Orbitals& pv, diff --git a/source/source_io/module_hs/write_HS_sparse.h b/source/source_io/module_hs/write_HS_sparse.h index 9f451de67c..f2e4560369 100644 --- a/source/source_io/module_hs/write_HS_sparse.h +++ b/source/source_io/module_hs/write_HS_sparse.h @@ -11,16 +11,6 @@ namespace ModuleIO { -// jingan add 2021-6-4, modify 2021-12-2 -void save_HSR_sparse(const int& istep, - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const double& sparse_thr, - const bool& binary, - const std::string& SR_filename, - const std::string& HR_filename_up, - const std::string& HR_filename_down); - void save_dH_sparse(const int& istep, const Parallel_Orbitals& pv, LCAO_HS_Arrays& HS_Arrays, diff --git a/source/source_io/module_parameter/input_conv.cpp b/source/source_io/module_parameter/input_conv.cpp index c83b46ecd6..62217790de 100644 --- a/source/source_io/module_parameter/input_conv.cpp +++ b/source/source_io/module_parameter/input_conv.cpp @@ -64,7 +64,7 @@ std::vector Input_Conv::convert_units(std::string params, double c) { void Input_Conv::read_td_efield() { elecstate::H_TDDFT_pw::stype = PARAM.inp.td_stype; - if (PARAM.inp.out_mat_hs2 == 1) + if (PARAM.inp.out_mat_hs2[0] == 1) { TD_info::out_mat_R = true; } else { diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index 9a5638ff8b..155d40c4d0 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -386,8 +386,7 @@ struct Input_para std::vector out_mat_hs = {0, 8}; ///< output H matrix and S matrix in local basis. std::vector out_mat_tk = {0, 8}; ///< output T(k) matrix in local basis. std::vector out_mat_l = {0, 8}; ///< output L matrix in local basis. - bool out_mat_hs2 = false; ///< LiuXh add 2019-07-16, output H(R) matrix and - ///< S(R) matrix in local basis. + std::vector out_mat_hs2 = {0, 8}; ///< output H(R) and S(R) matrix with precision bool out_mat_dh = false; bool out_mat_ds = false; bool out_mat_xc = false; ///< output exchange-correlation matrix in diff --git a/source/source_io/module_parameter/read_input.cpp b/source/source_io/module_parameter/read_input.cpp index 4dc09c4c65..95029ebe90 100644 --- a/source/source_io/module_parameter/read_input.cpp +++ b/source/source_io/module_parameter/read_input.cpp @@ -253,7 +253,7 @@ void ReadInput::create_directory(const Parameter& param) //---------------------------------------------------------- bool out_dir = false; if (!param.input.out_app_flag - && (param.input.out_mat_hs2 || param.input.out_mat_r || param.input.out_mat_t || param.input.out_mat_dh || param.input.out_mat_ds)) + && (param.input.out_mat_hs2[0] || param.input.out_mat_r || param.input.out_mat_t || param.input.out_mat_dh || param.input.out_mat_ds)) { out_dir = true; } diff --git a/source/source_io/module_parameter/read_input_item_output.cpp b/source/source_io/module_parameter/read_input_item_output.cpp index 4ffd6160cb..11b69f3acf 100644 --- a/source/source_io/module_parameter/read_input_item_output.cpp +++ b/source/source_io/module_parameter/read_input_item_output.cpp @@ -487,19 +487,28 @@ Also controled by out_freq_ion and out_app_flag. Input_Item item("out_mat_hs2"); item.annotation = "output H(R) and S(R) matrix"; item.category = "Output information"; - item.type = "Boolean"; + item.type = R"(Boolean \[Integer\](optional))"; item.description = "Whether to print files containing the Hamiltonian matrix and overlap matrix into files in the directory OUT.${suffix}. For more information, please refer to hs_matrix.md." "\n\n[NOTE] In the 3.10-LTS version, the file names are data-HR-sparse_SPIN0.csr and data-SR-sparse_SPIN0.csr, etc."; - item.default_value = "False"; + item.default_value = "False [8]"; item.unit = "Ry"; item.availability = "Numerical atomic orbital basis (not gamma-only algorithm)"; - read_sync_bool(input.out_mat_hs2); + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + if (count < 1) ModuleBase::WARNING_QUIT("ReadInput", "out_mat_hs2 needs at least 1 value"); + para.input.out_mat_hs2[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_hs2[1] = 8; + if (count >= 2) try { para.input.out_mat_hs2[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument&) { /* do nothing */ } + catch (const std::out_of_range&) {/* do nothing */} + }; item.check_value = [](const Input_Item& item, const Parameter& para) { if (para.input.out_mat_r && para.sys.gamma_only_local) { ModuleBase::WARNING_QUIT("ReadInput", "out_mat_r is not available for gamma only calculations"); } }; + sync_intvec(input.out_mat_hs2, 2, 0); this->add_item(item); } { @@ -536,7 +545,7 @@ Also controled by out_freq_ion and out_app_flag. item.availability = "Numerical atomic orbital basis (not gamma-only algorithm)"; read_sync_bool(input.out_mat_r); item.check_value = [](const Input_Item& item, const Parameter& para) { - if ((para.inp.out_mat_r || para.inp.out_mat_hs2 || para.inp.out_mat_t || para.inp.out_mat_dh + if ((para.inp.out_mat_r || para.inp.out_mat_hs2[0] || para.inp.out_mat_t || para.inp.out_mat_dh || para.inp.dm_to_rho) && para.sys.gamma_only_local) { diff --git a/source/source_io/test/read_input_ptest.cpp b/source/source_io/test/read_input_ptest.cpp index b723f4362c..dda864580a 100644 --- a/source/source_io/test/read_input_ptest.cpp +++ b/source/source_io/test/read_input_ptest.cpp @@ -204,7 +204,8 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(param.inp.out_proj_band, 0); EXPECT_EQ(param.inp.out_mat_hs[0], 0); EXPECT_EQ(param.inp.out_mat_hs[1], 8); - EXPECT_EQ(param.inp.out_mat_hs2, 0); + EXPECT_EQ(param.inp.out_mat_hs2[0], 0); + EXPECT_EQ(param.inp.out_mat_hs2[1], 8); EXPECT_FALSE(param.inp.out_mat_xc); EXPECT_FALSE(param.inp.out_mat_xc2); EXPECT_FALSE(param.inp.out_eband_terms); diff --git a/source/source_lcao/hamilt_lcao.cpp b/source/source_lcao/hamilt_lcao.cpp index 3850f636bd..1f5947db97 100644 --- a/source/source_lcao/hamilt_lcao.cpp +++ b/source/source_lcao/hamilt_lcao.cpp @@ -478,6 +478,22 @@ HamiltLCAO::HamiltLCAO(const UnitCell& ucell, return; } +template +std::vector*> HamiltLCAO::getHR_vector() +{ + if (PARAM.inp.nspin == 2) + { + const int nnr = this->hRS2.size() / 2; + HContainer* hr_up = new HContainer(*this->hR, this->hRS2.data()); + HContainer* hr_dn = new HContainer(*this->hR, this->hRS2.data() + nnr); + return {hr_up, hr_dn}; + } + else + { + return {this->hR}; + } +} + // case for multi-k-points template void HamiltLCAO::matrix(MatrixBlock& hk_in, MatrixBlock& sk_in) diff --git a/source/source_lcao/hamilt_lcao.h b/source/source_lcao/hamilt_lcao.h index 49b309b8c3..7341a3665d 100644 --- a/source/source_lcao/hamilt_lcao.h +++ b/source/source_lcao/hamilt_lcao.h @@ -126,6 +126,11 @@ class HamiltLCAO : public Hamilt /// get hRS2 buffer for NSPIN=2 case (spin-up in first half, spin-down in second half) std::vector& getHRS2() { return this->hRS2; } + /// Get HR as a vector of HContainer pointers (one per spin). + /// For nspin=2, creates temporary HContainers wrapping each spin half of hRS2. + /// Caller must delete returned pointers when nspin=2. + std::vector*> getHR_vector(); + /// refresh the status of HR void refresh(bool yes) override; diff --git a/source/source_lcao/spar_hsr.cpp b/source/source_lcao/spar_hsr.cpp index c7e26791d4..64ef1ca823 100644 --- a/source/source_lcao/spar_hsr.cpp +++ b/source/source_lcao/spar_hsr.cpp @@ -68,123 +68,6 @@ void sparse_format::sync_all_R_coor(std::set>& all_R_co } #endif // __MPI -template -void sparse_format::cal_HSR(const UnitCell& ucell, - Plus_U &dftu, // mohan add 20251107 - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const Grid_Driver& grid, - const int& current_spin, - const double& sparse_thr, - const int (&nmp)[3], - hamilt::Hamilt* p_ham -#ifdef __EXX - , - const std::vector>>>* Hexxd, - const std::vector>>>>* Hexxc -#endif - ) -{ - ModuleBase::TITLE("sparse_format", "cal_HSR"); - - // sparse_format::set_R_range(HS_Arrays.all_R_coor, grid); - - const int nspin = PARAM.inp.nspin; - - // cal_STN_R_sparse(current_spin, sparse_thr); - if (nspin == 1 || nspin == 2) - { - hamilt::HamiltLCAO* p_ham_lcao - = dynamic_cast*>(p_ham); - - HS_Arrays.all_R_coor = get_R_range(*(p_ham_lcao->getHR())); - - if (PARAM.inp.esolver_type == "tddft" && PARAM.inp.td_stype == 1) - { - sparse_format::cal_HContainer>( - pv, - sparse_thr, - *(p_ham_lcao->getHR()), - TD_info::td_vel_op->HR_sparse_td_vel[current_spin]); - } - else - { - - sparse_format::cal_HContainer(pv, - sparse_thr, - *(p_ham_lcao->getHR()), - HS_Arrays.HR_sparse[current_spin]); - } - - sparse_format::cal_HContainer(pv, sparse_thr, *(p_ham_lcao->getSR()), HS_Arrays.SR_sparse); - } - else if (nspin == 4) - { - hamilt::HamiltLCAO, std::complex>* p_ham_lcao - = dynamic_cast, std::complex>*>(p_ham); - - HS_Arrays.all_R_coor = get_R_range(*(p_ham_lcao->getHR())); - - sparse_format::cal_HContainer>(pv, - sparse_thr, - *(p_ham_lcao->getHR()), - HS_Arrays.HR_soc_sparse); - - sparse_format::cal_HContainer>(pv, - sparse_thr, - *(p_ham_lcao->getSR()), - HS_Arrays.SR_soc_sparse); - } - else - { - ModuleBase::WARNING_QUIT("cal_HSR", "check the value of nspin."); - } - - // only old DFT+U method need to cal extra contribution to HR - if (PARAM.inp.dft_plus_u == 2) - { - if (nspin == 1 || nspin == 2) - { - cal_HR_dftu(dftu, pv, HS_Arrays.all_R_coor, - HS_Arrays.SR_sparse, HS_Arrays.HR_sparse, current_spin, sparse_thr); - } - else if (nspin == 4) - { - cal_HR_dftu_soc(dftu, pv, HS_Arrays.all_R_coor, - HS_Arrays.SR_soc_sparse, HS_Arrays.HR_soc_sparse, - current_spin, sparse_thr); - } - else - { - ModuleBase::WARNING_QUIT("cal_HSR", "check the value of nspin."); - } - } - -#ifdef __EXX -#ifdef __MPI - // if EXX is considered - if (GlobalC::exx_info.info_global.cal_exx) - { - - if (Hexxd && GlobalC::exx_info.info_ri.real_number) - { - - sparse_format::cal_HR_exx(ucell, pv, HS_Arrays, current_spin, sparse_thr, nmp, *Hexxd); - } - else if (Hexxc && !GlobalC::exx_info.info_ri.real_number) - { - - sparse_format::cal_HR_exx(ucell, pv, HS_Arrays, current_spin, sparse_thr, nmp, *Hexxc); - } - } -#endif // __MPI -#endif // __EXX - - sparse_format::clear_zero_elements(HS_Arrays, current_spin, sparse_thr); - - return; -} - template void sparse_format::cal_HContainer(const Parallel_Orbitals& pv, const double& sparse_thr, @@ -373,40 +256,6 @@ void sparse_format::destroy_HS_R_sparse(LCAO_HS_Arrays& HS_Arrays) return; } -template void sparse_format::cal_HSR( - const UnitCell& ucell, - Plus_U &dftu, // mohan add 20251107 - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const Grid_Driver& grid, - const int& current_spin, - const double& sparse_thr, - const int (&nmp)[3], - hamilt::Hamilt* p_ham -#ifdef __EXX - , - const std::vector>>>* Hexxd, - const std::vector>>>>* Hexxc -#endif - ); - -template void sparse_format::cal_HSR>( - const UnitCell& ucell, - Plus_U &dftu, // mohan add 20251107 - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const Grid_Driver& grid, - const int& current_spin, - const double& sparse_thr, - const int (&nmp)[3], - hamilt::Hamilt>* p_ham -#ifdef __EXX - , - const std::vector>>>* Hexxd, - const std::vector>>>>* Hexxc -#endif - ); - template void sparse_format::cal_HContainer( const Parallel_Orbitals& pv, const double& sparse_thr, diff --git a/source/source_lcao/spar_hsr.h b/source/source_lcao/spar_hsr.h index b196d3be3b..09e41a614a 100644 --- a/source/source_lcao/spar_hsr.h +++ b/source/source_lcao/spar_hsr.h @@ -42,24 +42,6 @@ std::set> get_R_range(const hamilt::HContainer& hR) return all_R_coor; }; -using TAC = std::pair>; -template -void cal_HSR(const UnitCell& ucell, - Plus_U &dftu, // mohan add 2025-11-07 - const Parallel_Orbitals& pv, - LCAO_HS_Arrays& HS_Arrays, - const Grid_Driver& grid, - const int& current_spin, - const double& sparse_thr, - const int (&nmp)[3], - hamilt::Hamilt* p_ham -#ifdef __EXX - , - const std::vector>>>* Hexxd = nullptr, - const std::vector>>>>* Hexxc = nullptr -#endif - ); - template void cal_HContainer(const Parallel_Orbitals& pv, const double& sparse_thr, From 36152651159580b209ef99f6434ac2a523c07628 Mon Sep 17 00:00:00 2001 From: dyzheng Date: Mon, 2 Mar 2026 22:48:42 +0800 Subject: [PATCH 2/3] feature: modify out_mat_ds, out_mat_t, out_mat_r, out_mat_xc2 for new CSR format --- source/source_esolver/esolver_gets.cpp | 4 +- .../module_ctrl/ctrl_runner_lcao.cpp | 2 +- .../source_io/module_ctrl/ctrl_scf_lcao.cpp | 8 +- source/source_io/module_hs/write_HS_R.cpp | 115 +++++++++++++++++ source/source_io/module_hs/write_HS_R.h | 19 +++ .../module_parameter/input_parameter.h | 10 +- .../source_io/module_parameter/read_input.cpp | 2 +- .../read_input_item_output.cpp | 121 ++++++++++++++---- source/source_io/test/read_input_ptest.cpp | 6 +- .../test_serial/read_input_item_test.cpp | 104 ++++++++++++++- 10 files changed, 351 insertions(+), 40 deletions(-) diff --git a/source/source_esolver/esolver_gets.cpp b/source/source_esolver/esolver_gets.cpp index 7eff0f537a..a17e395f39 100644 --- a/source/source_esolver/esolver_gets.cpp +++ b/source/source_esolver/esolver_gets.cpp @@ -127,14 +127,14 @@ void ESolver_GetS::runner(UnitCell& ucell, const int istep) ModuleIO::output_SR(pv, gd, this->p_hamilt, fn); - if (PARAM.inp.out_mat_r) + if (PARAM.inp.out_mat_r[0]) { cal_r_overlap_R r_matrix; r_matrix.init(ucell, pv, orb_); r_matrix.out_rR(ucell, gd, istep); } - if (PARAM.inp.out_mat_ds) + if (PARAM.inp.out_mat_ds[0]) { LCAO_HS_Arrays HS_Arrays; // store sparse arrays //! Print out sparse matrix diff --git a/source/source_io/module_ctrl/ctrl_runner_lcao.cpp b/source/source_io/module_ctrl/ctrl_runner_lcao.cpp index 902337f35e..fb683f193a 100644 --- a/source/source_io/module_ctrl/ctrl_runner_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_runner_lcao.cpp @@ -76,7 +76,7 @@ void ctrl_runner_lcao(UnitCell& ucell, // unitcell ); } - if (inp.out_mat_xc2) + if (inp.out_mat_xc2[0]) { ModuleIO::write_Vxc_R(inp.nspin, &pv, diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index 6af849824d..526ae8390e 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -237,10 +237,10 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, //------------------------------------------------------------------ hamilt::Hamilt* p_ham_tk = static_cast*>(p_hamilt); - ModuleIO::output_mat_sparse(inp.out_mat_dh, - inp.out_mat_ds, - inp.out_mat_t, - inp.out_mat_r, + ModuleIO::output_mat_sparse(inp.out_mat_dh[0], + inp.out_mat_ds[0], + inp.out_mat_t[0], + inp.out_mat_r[0], istep, pelec->pot->get_eff_v(), pv, diff --git a/source/source_io/module_hs/write_HS_R.cpp b/source/source_io/module_hs/write_HS_R.cpp index d065c07cae..41b3163bb1 100644 --- a/source/source_io/module_hs/write_HS_R.cpp +++ b/source/source_io/module_hs/write_HS_R.cpp @@ -8,6 +8,32 @@ #include "source_lcao/spar_st.h" #include "write_HS_sparse.h" +namespace { +// Helper: Convert sparse map to HContainer +template +hamilt::HContainer* sparse_map_to_hcontainer( + const std::map, std::map>>& sparse_map, + const Parallel_Orbitals& pv, + const int nbasis) +{ + hamilt::HContainer* hc = new hamilt::HContainer(&pv); + hc->set_zero(); + + for (const auto& [R, row_map] : sparse_map) + { + for (const auto& [row, col_map] : row_map) + { + for (const auto& [col, value] : col_map) + { + hc->set_value(R.x, R.y, R.z, row, col, value); + } + } + } + + return hc; +} +} // anonymous namespace + // if 'binary=true', output binary file. // The 'sparse_thr' is the accuracy of the sparse matrix. // If the absolute value of the matrix element is less than or equal to the @@ -226,6 +252,20 @@ std::string ModuleIO::hsr_gen_fname(const std::string& prefix, } } +std::string ModuleIO::dhr_gen_fname(const std::string& prefix, + const int ispin, + const bool append, + const int istep) +{ + std::string fname = prefix + "rs" + std::to_string(ispin + 1); + if (!append && istep >= 0) + { + fname += "g" + std::to_string(istep + 1); + } + fname += "_nao.csr"; + return fname; +} + template void ModuleIO::write_hcontainer_csr(const std::string& fname, const UnitCell* ucell, @@ -344,3 +384,78 @@ template void ModuleIO::write_hsr>( const UnitCell*, const int, const Parallel_2D&, const bool, const int*, const int, const int); + +template +void ModuleIO::write_matrix_r(const std::string& matrix_label, + const std::string& description, + const std::vector*>& matrices, + const UnitCell* ucell, + const int precision, + const Parallel_2D& paraV, + const bool append, + const int* iat2iwt, + const int nat, + const int istep) +{ + const int nspin = matrices.size(); + assert(nspin > 0); + + for (int ispin = 0; ispin < nspin; ispin++) + { + const int nbasis = matrices[ispin]->get_nbasis(); + + // Generate filename + std::string fname = dhr_gen_fname(matrix_label, ispin, append, istep); + if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) + { + fname = PARAM.globalv.global_matrix_dir + fname; + } + else + { + fname = PARAM.globalv.global_out_dir + fname; + } + + // Gather parallel matrix to serial +#ifdef __MPI + Parallel_Orbitals serialV; + serialV.init(nbasis, nbasis, nbasis, paraV.comm()); + serialV.set_serial(nbasis, nbasis); + serialV.set_atomic_trace(iat2iwt, nat, nbasis); + + hamilt::HContainer matrix_serial(&serialV); + hamilt::gatherParallels(*matrices[ispin], &matrix_serial, 0); + + if (GlobalV::MY_RANK == 0) + { + write_hcontainer_csr(fname, ucell, precision, &matrix_serial, istep, ispin, nspin, description); + } +#else + write_hcontainer_csr(fname, ucell, precision, matrices[ispin], istep, ispin, nspin, description); +#endif + } +} + +// Template instantiations +template void ModuleIO::write_matrix_r( + const std::string&, + const std::string&, + const std::vector*>&, + const UnitCell*, + const int, + const Parallel_2D&, + const bool, + const int*, + const int, + const int); + +template void ModuleIO::write_matrix_r>( + const std::string&, + const std::string&, + const std::vector>*>&, + const UnitCell*, + const int, + const Parallel_2D&, + const bool, + const int*, + const int, + const int); diff --git a/source/source_io/module_hs/write_HS_R.h b/source/source_io/module_hs/write_HS_R.h index 5bcdea4718..c6489a85b1 100644 --- a/source/source_io/module_hs/write_HS_R.h +++ b/source/source_io/module_hs/write_HS_R.h @@ -63,6 +63,12 @@ std::string hsr_gen_fname(const std::string& prefix, const bool append, const int istep); +/// Generate filename for derivative matrices (dH/dR, dS/dR). +std::string dhr_gen_fname(const std::string& prefix, + const int ispin, + const bool append, + const int istep); + /// Write a single HContainer to CSR file with header. template void write_hcontainer_csr(const std::string& fname, @@ -86,6 +92,19 @@ void write_hsr(const std::vector*>& hr_vec, const int nat, const int istep); +/// Write real-space matrix in CSR format (generic interface). +template +void write_matrix_r(const std::string& matrix_label, + const std::string& description, + const std::vector*>& matrices, + const UnitCell* ucell, + const int precision, + const Parallel_2D& paraV, + const bool append, + const int* iat2iwt, + const int nat, + const int istep); + } // namespace ModuleIO #endif diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index 155d40c4d0..fd63509cd2 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -387,18 +387,18 @@ struct Input_para std::vector out_mat_tk = {0, 8}; ///< output T(k) matrix in local basis. std::vector out_mat_l = {0, 8}; ///< output L matrix in local basis. std::vector out_mat_hs2 = {0, 8}; ///< output H(R) and S(R) matrix with precision - bool out_mat_dh = false; - bool out_mat_ds = false; + std::vector out_mat_dh = {0, 8}; ///< output dH/dR matrices with precision + std::vector out_mat_ds = {0, 8}; ///< output dS/dR matrices with precision bool out_mat_xc = false; ///< output exchange-correlation matrix in ///< KS-orbital representation. - bool out_mat_xc2 = false; ///< output exchange-correlation matrix Vxc(R) in NAO representation. + std::vector out_mat_xc2 = {0, 8}; ///< output Vxc(R) matrix with precision bool out_eband_terms = false; ///< output the band energy terms separately bool out_app_flag = true; ///< whether output r(R), H(R), S(R), T(R), and dH(R) matrices ///< in an append manner during MD liuyu 2023-03-20 int out_ndigits = 8; ///< Assuming 8 digits precision is needed for matrices output - bool out_mat_t = false; + std::vector out_mat_t = {0, 8}; ///< output T(R) matrix with precision bool out_element_info = false; ///< output information of all elements - bool out_mat_r = false; ///< jingan add 2019-8-14, output r(R) matrix. + std::vector out_mat_r = {0, 8}; ///< output r(R) matrix with precision int out_wfc_lcao = 0; ///< output the wave functions in local basis. bool out_dipole = false; ///< output the dipole or not bool out_efield = false; ///< output the efield or not diff --git a/source/source_io/module_parameter/read_input.cpp b/source/source_io/module_parameter/read_input.cpp index 95029ebe90..2954bc55f8 100644 --- a/source/source_io/module_parameter/read_input.cpp +++ b/source/source_io/module_parameter/read_input.cpp @@ -253,7 +253,7 @@ void ReadInput::create_directory(const Parameter& param) //---------------------------------------------------------- bool out_dir = false; if (!param.input.out_app_flag - && (param.input.out_mat_hs2[0] || param.input.out_mat_r || param.input.out_mat_t || param.input.out_mat_dh || param.input.out_mat_ds)) + && (param.input.out_mat_hs2[0] || param.input.out_mat_r[0] || param.input.out_mat_t[0] || param.input.out_mat_dh[0] || param.input.out_mat_ds[0])) { out_dir = true; } diff --git a/source/source_io/module_parameter/read_input_item_output.cpp b/source/source_io/module_parameter/read_input_item_output.cpp index 11b69f3acf..1bda111671 100644 --- a/source/source_io/module_parameter/read_input_item_output.cpp +++ b/source/source_io/module_parameter/read_input_item_output.cpp @@ -503,7 +503,7 @@ Also controled by out_freq_ion and out_app_flag. catch (const std::out_of_range&) {/* do nothing */} }; item.check_value = [](const Input_Item& item, const Parameter& para) { - if (para.input.out_mat_r && para.sys.gamma_only_local) + if (para.input.out_mat_r[0] && para.sys.gamma_only_local) { ModuleBase::WARNING_QUIT("ReadInput", "out_mat_r is not available for gamma only calculations"); } @@ -537,15 +537,29 @@ Also controled by out_freq_ion and out_app_flag. Input_Item item("out_mat_r"); item.annotation = "output r(R) matrix"; item.category = "Output information"; - item.type = "Boolean"; - item.description = "Whether to print the matrix representation of the position matrix into a file named rr.csr in the directory OUT.${suffix}. If calculation is set to get_s, the position matrix can be obtained without scf iterations. For more information, please refer to position_matrix.md." + item.type = R"(Boolean \[Integer\](optional))"; + item.description = "Whether to print the matrix representation of the position matrix into files named rxrs1_nao.csr, ryrs1_nao.csr, rzrs1_nao.csr in the directory OUT.${suffix}. If calculation is set to get_s, the position matrix can be obtained without scf iterations. For more information, please refer to position_matrix.md." "\n\n[NOTE] In the 3.10-LTS version, the file name is data-rR-sparse.csr."; - item.default_value = "False"; + item.default_value = "False 8"; item.unit = "Bohr"; item.availability = "Numerical atomic orbital basis (not gamma-only algorithm)"; - read_sync_bool(input.out_mat_r); + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + if (count < 1) ModuleBase::WARNING_QUIT("ReadInput", "out_mat_r needs at least 1 value"); + try { + para.input.out_mat_r[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_r[1] = 8; + if (count >= 2) try { para.input.out_mat_r[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_r precision must be an integer, using default 8"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_r enable flag must be 0/1, using default 0"); + } + }; item.check_value = [](const Input_Item& item, const Parameter& para) { - if ((para.inp.out_mat_r || para.inp.out_mat_hs2[0] || para.inp.out_mat_t || para.inp.out_mat_dh + if ((para.inp.out_mat_r[0] || para.inp.out_mat_hs2[0] || para.inp.out_mat_t[0] || para.inp.out_mat_dh[0] || para.inp.dm_to_rho) && para.sys.gamma_only_local) { @@ -554,57 +568,103 @@ Also controled by out_freq_ion and out_app_flag. "available for gamma only calculations"); } }; + sync_intvec(input.out_mat_r, 2, 0); this->add_item(item); } { Input_Item item("out_mat_t"); item.annotation = "output T(R) matrix"; item.category = "Output information"; - item.type = "Boolean"; + item.type = R"(Boolean \[Integer\](optional))"; item.description = "Generate files containing the kinetic energy matrix. The format will be the same as the Hamiltonian matrix and overlap matrix as mentioned in out_mat_hs2. The name of the files will be trs1_nao.csr and so on. Also controled by out_freq_ion and out_app_flag." "\n\n[NOTE] In the 3.10-LTS version, the file name is data-TR-sparse_SPIN0.csr."; - item.default_value = "False"; + item.default_value = "False 8"; item.unit = "Ry"; item.availability = "Numerical atomic orbital basis (not gamma-only algorithm)"; - read_sync_bool(input.out_mat_t); + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + if (count < 1) ModuleBase::WARNING_QUIT("ReadInput", "out_mat_t needs at least 1 value"); + try { + para.input.out_mat_t[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_t[1] = 8; + if (count >= 2) try { para.input.out_mat_t[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_t precision must be an integer, using default 8"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_t enable flag must be 0/1, using default 0"); + } + }; + sync_intvec(input.out_mat_t, 2, 0); this->add_item(item); } { Input_Item item("out_mat_dh"); - item.annotation = "output of derivative of H(R) matrix"; + item.annotation = "output Hamiltonian derivatives dH/dR matrices"; item.category = "Output information"; - item.type = "Boolean"; + item.type = "Integer"; item.description = "Whether to print files containing the derivatives of the Hamiltonian matrix. The format will be the same as the Hamiltonian matrix and overlap matrix as mentioned in out_mat_hs2. The name of the files will be dhrxs1_nao.csr, dhrys1_nao.csr, dhrzs1_nao.csr and so on. Also controled by out_freq_ion and out_app_flag." "\n\n[NOTE] In the 3.10-LTS version, the file name is data-dHRx-sparse_SPIN0.csr and so on."; - item.default_value = "False"; + item.default_value = "0 8"; item.unit = "Ry/Bohr"; item.availability = "Numerical atomic orbital basis (not gamma-only algorithm)"; - read_sync_bool(input.out_mat_dh); + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + if (count < 1) ModuleBase::WARNING_QUIT("ReadInput", "out_mat_dh needs at least 1 value"); + try { + para.input.out_mat_dh[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_dh[1] = 8; + if (count >= 2) try { para.input.out_mat_dh[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_dh precision must be an integer, using default 8"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_dh enable flag must be 0/1, using default 0"); + } + }; item.check_value = [](const Input_Item& item, const Parameter& para) { - if (para.input.out_mat_dh && para.input.nspin == 4) + if (para.input.out_mat_dh[0] && para.input.nspin == 4) { ModuleBase::WARNING_QUIT("ReadInput", "out_mat_dh is not available for nspin = 4"); } }; + sync_intvec(input.out_mat_dh, 2, 0); this->add_item(item); } { Input_Item item("out_mat_ds"); item.annotation = "output of derivative of S(R) matrix"; item.category = "Output information"; - item.type = "Boolean"; - item.description = "Whether to print files containing the derivatives of the overlap matrix. The format will be the same as the overlap matrix as mentioned in out_mat_dh. The name of the files will be dsrxs1.csr and so on. Also controled by out_freq_ion and out_app_flag. This feature can be used with calculation get_s." + item.type = R"(Boolean \[Integer\](optional))"; + item.description = "Whether to print files containing the derivatives of the overlap matrix. The format will be the same as the overlap matrix as mentioned in out_mat_dh. The name of the files will be dsxrs1_nao.csr and so on. Also controled by out_freq_ion and out_app_flag. This feature can be used with calculation get_s." "\n\n[NOTE] In the 3.10-LTS version, the file name is data-dSRx-sparse_SPIN0.csr and so on."; - item.default_value = "False"; + item.default_value = "False 8"; item.unit = "Ry/Bohr"; item.availability = "Numerical atomic orbital basis (not gamma-only algorithm)"; - read_sync_bool(input.out_mat_ds); + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + if (count < 1) ModuleBase::WARNING_QUIT("ReadInput", "out_mat_ds needs at least 1 value"); + try { + para.input.out_mat_ds[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_ds[1] = 8; + if (count >= 2) try { para.input.out_mat_ds[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_ds precision must be an integer, using default 8"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_ds enable flag must be 0/1, using default 0"); + } + }; item.check_value = [](const Input_Item& item, const Parameter& para) { - if (para.input.out_mat_ds && para.input.nspin == 4) + if (para.input.out_mat_ds[0] && para.input.nspin == 4) { ModuleBase::WARNING_QUIT("ReadInput", "out_mat_ds is not available for nspin = 4"); } }; + sync_intvec(input.out_mat_ds, 2, 0); this->add_item(item); } { @@ -624,13 +684,28 @@ Also controled by out_freq_ion and out_app_flag. Input_Item item("out_mat_xc2"); item.annotation = "output exchange-correlation matrix in NAO representation"; item.category = "Output information"; - item.type = "Boolean"; - item.description = "Whether to print the exchange-correlation matrices in numerical orbital representation: in CSR format in the directory OUT.s." + item.type = R"(Boolean \[Integer\](optional))"; + item.description = "Whether to print the exchange-correlation matrices in numerical orbital representation: in CSR format in the directory OUT.${suffix}. The name of the files will be vxcrs1_nao.csr and so on." "\n\n[NOTE] In the 3.10-LTS version, the file name is Vxc_R_spin$s and so on."; - item.default_value = "False"; + item.default_value = "False 8"; item.unit = "Ry"; item.availability = "Numerical atomic orbital (NAO) basis"; - read_sync_bool(input.out_mat_xc2); + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + if (count < 1) ModuleBase::WARNING_QUIT("ReadInput", "out_mat_xc2 needs at least 1 value"); + try { + para.input.out_mat_xc2[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_xc2[1] = 8; + if (count >= 2) try { para.input.out_mat_xc2[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_xc2 precision must be an integer, using default 8"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_xc2 enable flag must be 0/1, using default 0"); + } + }; + sync_intvec(input.out_mat_xc2, 2, 0); this->add_item(item); } { diff --git a/source/source_io/test/read_input_ptest.cpp b/source/source_io/test/read_input_ptest.cpp index dda864580a..433c9d8094 100644 --- a/source/source_io/test/read_input_ptest.cpp +++ b/source/source_io/test/read_input_ptest.cpp @@ -207,10 +207,12 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(param.inp.out_mat_hs2[0], 0); EXPECT_EQ(param.inp.out_mat_hs2[1], 8); EXPECT_FALSE(param.inp.out_mat_xc); - EXPECT_FALSE(param.inp.out_mat_xc2); + EXPECT_EQ(param.inp.out_mat_xc2[0], 0); + EXPECT_EQ(param.inp.out_mat_xc2[1], 8); EXPECT_FALSE(param.inp.out_eband_terms); EXPECT_EQ(param.inp.out_app_flag, 0); - EXPECT_EQ(param.inp.out_mat_r, 0); + EXPECT_EQ(param.inp.out_mat_r[0], 0); + EXPECT_EQ(param.inp.out_mat_r[1], 8); EXPECT_FALSE(param.inp.out_wfc_lcao); EXPECT_FALSE(param.inp.out_alllog); EXPECT_DOUBLE_EQ(param.inp.dos_emin_ev, -15); diff --git a/source/source_io/test_serial/read_input_item_test.cpp b/source/source_io/test_serial/read_input_item_test.cpp index 48dbeb7914..0a6e3024b4 100644 --- a/source/source_io/test_serial/read_input_item_test.cpp +++ b/source/source_io/test_serial/read_input_item_test.cpp @@ -925,7 +925,7 @@ TEST_F(InputTest, Item_test) { // out_mat_r auto it = find_label("out_mat_r", readinput.input_lists); param.input.esolver_type = "lcao"; - param.input.out_mat_r = true; + param.input.out_mat_r[0] = 1; param.sys.gamma_only_local = true; testing::internal::CaptureStdout(); EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), ""); @@ -967,7 +967,7 @@ TEST_F(InputTest, Item_test2) std::string output = ""; { // out_mat_dh auto it = find_label("out_mat_dh", readinput.input_lists); - param.input.out_mat_dh = true; + param.input.out_mat_dh[0] = 1; param.input.nspin = 4; testing::internal::CaptureStdout(); EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), ""); @@ -1848,3 +1848,103 @@ TEST_F(InputTest, Item_test2) EXPECT_EQ(param.input.nocc, 4); } } + +TEST_F(InputParaTest, OutMatDH) +{ + std::string input_file = "./support/INPUT"; + std::ofstream ofs(input_file); + ofs << "out_mat_dh 1" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_dh[0], 1); + EXPECT_EQ(PARAM.input.out_mat_dh[1], 8); + remove(input_file.c_str()); + + ofs.open(input_file); + ofs << "out_mat_dh 1 12" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_dh[0], 1); + EXPECT_EQ(PARAM.input.out_mat_dh[1], 12); + remove(input_file.c_str()); +} + +TEST_F(InputParaTest, OutMatDS) +{ + std::string input_file = "./support/INPUT"; + std::ofstream ofs(input_file); + ofs << "out_mat_ds 1" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_ds[0], 1); + EXPECT_EQ(PARAM.input.out_mat_ds[1], 8); + remove(input_file.c_str()); + + ofs.open(input_file); + ofs << "out_mat_ds 1 10" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_ds[0], 1); + EXPECT_EQ(PARAM.input.out_mat_ds[1], 10); + remove(input_file.c_str()); +} + +TEST_F(InputParaTest, OutMatT) +{ + std::string input_file = "./support/INPUT"; + std::ofstream ofs(input_file); + ofs << "out_mat_t 1" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_t[0], 1); + EXPECT_EQ(PARAM.input.out_mat_t[1], 8); + remove(input_file.c_str()); + + ofs.open(input_file); + ofs << "out_mat_t 1 15" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_t[0], 1); + EXPECT_EQ(PARAM.input.out_mat_t[1], 15); + remove(input_file.c_str()); +} + +TEST_F(InputParaTest, OutMatR) +{ + std::string input_file = "./support/INPUT"; + std::ofstream ofs(input_file); + ofs << "out_mat_r 1" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_r[0], 1); + EXPECT_EQ(PARAM.input.out_mat_r[1], 8); + remove(input_file.c_str()); + + ofs.open(input_file); + ofs << "out_mat_r 1 6" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_r[0], 1); + EXPECT_EQ(PARAM.input.out_mat_r[1], 6); + remove(input_file.c_str()); +} + +TEST_F(InputParaTest, OutMatXC2) +{ + std::string input_file = "./support/INPUT"; + std::ofstream ofs(input_file); + ofs << "out_mat_xc2 1" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_xc2[0], 1); + EXPECT_EQ(PARAM.input.out_mat_xc2[1], 8); + remove(input_file.c_str()); + + ofs.open(input_file); + ofs << "out_mat_xc2 1 9" << std::endl; + ofs.close(); + PARAM.input.Read(input_file); + EXPECT_EQ(PARAM.input.out_mat_xc2[0], 1); + EXPECT_EQ(PARAM.input.out_mat_xc2[1], 9); + remove(input_file.c_str()); +} From f7cce86a1c3229fda7565ab6f621099a826a3335 Mon Sep 17 00:00:00 2001 From: dyzheng Date: Tue, 3 Mar 2026 15:40:29 +0800 Subject: [PATCH 3/3] fix: UT of input --- .../test_serial/read_input_item_test.cpp | 154 +++++++----------- 1 file changed, 61 insertions(+), 93 deletions(-) diff --git a/source/source_io/test_serial/read_input_item_test.cpp b/source/source_io/test_serial/read_input_item_test.cpp index 0a6e3024b4..dc510c5a4a 100644 --- a/source/source_io/test_serial/read_input_item_test.cpp +++ b/source/source_io/test_serial/read_input_item_test.cpp @@ -1849,102 +1849,70 @@ TEST_F(InputTest, Item_test2) } } -TEST_F(InputParaTest, OutMatDH) +TEST_F(InputTest, Item_test_out_mat_vec) { - std::string input_file = "./support/INPUT"; - std::ofstream ofs(input_file); - ofs << "out_mat_dh 1" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_dh[0], 1); - EXPECT_EQ(PARAM.input.out_mat_dh[1], 8); - remove(input_file.c_str()); - - ofs.open(input_file); - ofs << "out_mat_dh 1 12" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_dh[0], 1); - EXPECT_EQ(PARAM.input.out_mat_dh[1], 12); - remove(input_file.c_str()); -} + ModuleIO::ReadInput readinput(0); + readinput.check_ntype_flag = false; + Parameter param; -TEST_F(InputParaTest, OutMatDS) -{ - std::string input_file = "./support/INPUT"; - std::ofstream ofs(input_file); - ofs << "out_mat_ds 1" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_ds[0], 1); - EXPECT_EQ(PARAM.input.out_mat_ds[1], 8); - remove(input_file.c_str()); - - ofs.open(input_file); - ofs << "out_mat_ds 1 10" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_ds[0], 1); - EXPECT_EQ(PARAM.input.out_mat_ds[1], 10); - remove(input_file.c_str()); -} + { // out_mat_dh + auto it = find_label("out_mat_dh", readinput.input_lists); + it->second.str_values = {"1"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_dh[0], 1); + EXPECT_EQ(param.input.out_mat_dh[1], 8); -TEST_F(InputParaTest, OutMatT) -{ - std::string input_file = "./support/INPUT"; - std::ofstream ofs(input_file); - ofs << "out_mat_t 1" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_t[0], 1); - EXPECT_EQ(PARAM.input.out_mat_t[1], 8); - remove(input_file.c_str()); - - ofs.open(input_file); - ofs << "out_mat_t 1 15" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_t[0], 1); - EXPECT_EQ(PARAM.input.out_mat_t[1], 15); - remove(input_file.c_str()); -} + it->second.str_values = {"1", "12"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_dh[0], 1); + EXPECT_EQ(param.input.out_mat_dh[1], 12); + } + { // out_mat_ds + auto it = find_label("out_mat_ds", readinput.input_lists); + it->second.str_values = {"1"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_ds[0], 1); + EXPECT_EQ(param.input.out_mat_ds[1], 8); -TEST_F(InputParaTest, OutMatR) -{ - std::string input_file = "./support/INPUT"; - std::ofstream ofs(input_file); - ofs << "out_mat_r 1" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_r[0], 1); - EXPECT_EQ(PARAM.input.out_mat_r[1], 8); - remove(input_file.c_str()); - - ofs.open(input_file); - ofs << "out_mat_r 1 6" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_r[0], 1); - EXPECT_EQ(PARAM.input.out_mat_r[1], 6); - remove(input_file.c_str()); -} + it->second.str_values = {"1", "10"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_ds[0], 1); + EXPECT_EQ(param.input.out_mat_ds[1], 10); + } + { // out_mat_t + auto it = find_label("out_mat_t", readinput.input_lists); + it->second.str_values = {"1"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_t[0], 1); + EXPECT_EQ(param.input.out_mat_t[1], 8); -TEST_F(InputParaTest, OutMatXC2) -{ - std::string input_file = "./support/INPUT"; - std::ofstream ofs(input_file); - ofs << "out_mat_xc2 1" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_xc2[0], 1); - EXPECT_EQ(PARAM.input.out_mat_xc2[1], 8); - remove(input_file.c_str()); - - ofs.open(input_file); - ofs << "out_mat_xc2 1 9" << std::endl; - ofs.close(); - PARAM.input.Read(input_file); - EXPECT_EQ(PARAM.input.out_mat_xc2[0], 1); - EXPECT_EQ(PARAM.input.out_mat_xc2[1], 9); - remove(input_file.c_str()); + it->second.str_values = {"1", "15"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_t[0], 1); + EXPECT_EQ(param.input.out_mat_t[1], 15); + } + { // out_mat_r + auto it = find_label("out_mat_r", readinput.input_lists); + it->second.str_values = {"1"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_r[0], 1); + EXPECT_EQ(param.input.out_mat_r[1], 8); + + it->second.str_values = {"1", "6"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_r[0], 1); + EXPECT_EQ(param.input.out_mat_r[1], 6); + } + { // out_mat_xc2 + auto it = find_label("out_mat_xc2", readinput.input_lists); + it->second.str_values = {"1"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_xc2[0], 1); + EXPECT_EQ(param.input.out_mat_xc2[1], 8); + + it->second.str_values = {"1", "9"}; + it->second.read_value(it->second, param); + EXPECT_EQ(param.input.out_mat_xc2[0], 1); + EXPECT_EQ(param.input.out_mat_xc2[1], 9); + } }