Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
26af4d0
preparation on gdm.cpp
v-boqinzhang Feb 25, 2026
a27effe
compute_restricted_open_shell_gradient
v-boqinzhang Feb 26, 2026
ea5becb
add compute_restricted_open_shell_gradient function
v-boqinzhang Feb 26, 2026
e6d06a0
modify GDMLinearFunctor::eval, remove Uoo Uvv from class GDM
v-boqinzhang Feb 27, 2026
2401bdd
Merge branch 'gh-branch/main' into gh-feature/gdm_rohf
v-boqinzhang Feb 27, 2026
bfb6e73
Merge branch 'gh-branch/main' into gh-feature/gdm_rohf
v-boqinzhang Apr 14, 2026
0237d01
generate_restricted_open_shell_pseudo_canonical_orbital_
v-boqinzhang Apr 15, 2026
eea787b
ROHF initial Hessian, move function build_rohf_f_p_matrix
v-boqinzhang Apr 21, 2026
77634c1
Merge branch 'gh-branch/main' into gh-feature/gdm_rohf
v-boqinzhang Apr 21, 2026
5ddf2d7
delete ROHF_invalid_GDM test
v-boqinzhang Apr 21, 2026
f2b15c1
add tests
v-boqinzhang Apr 22, 2026
afb3617
clean the code 1
v-boqinzhang Apr 22, 2026
09e9a9f
clean the code 2
v-boqinzhang Apr 22, 2026
e7e5e89
add python tests
v-boqinzhang Apr 22, 2026
dfc534c
pre-commit
v-boqinzhang Apr 22, 2026
bac2355
resolve comments 1
v-boqinzhang Apr 23, 2026
5c9b7a9
add function compute_atba_gemm
v-boqinzhang Apr 27, 2026
9737c3c
mod rotate_gradient_to_pseudo_canonical_basis
v-boqinzhang Apr 27, 2026
c61e91b
Merge branch 'gh-branch/main' into gh-feature/gdm_rohf
v-boqinzhang Apr 27, 2026
709344c
move compute_atba_gemm
v-boqinzhang Apr 29, 2026
70ef7ec
Merge branch 'gh-branch/main' into gh-feature/gdm_rohf
v-boqinzhang Apr 29, 2026
e15cb95
mod update_density_matrix
v-boqinzhang Apr 29, 2026
caf2634
resolve comments 2
v-boqinzhang Apr 30, 2026
584c4af
resolve comments 3
v-boqinzhang Apr 30, 2026
51494e8
small debug
v-boqinzhang Apr 30, 2026
2cd4678
add cached_J_ and cached_K_ for ROHF
v-boqinzhang Apr 30, 2026
71e3124
resolve comments 4
v-boqinzhang May 1, 2026
c88fc5c
resolve comments 5
v-boqinzhang May 1, 2026
0c2d22c
Merge branch 'gh-branch/main' into gh-feature/gdm_rohf
v-boqinzhang May 1, 2026
ebd54dc
resolve comments 6
v-boqinzhang May 1, 2026
d0dab18
Merge branch 'gh-branch/main' into gh-feature/gdm_rohf
v-boqinzhang May 18, 2026
7ffd6be
resolve comments 7
v-boqinzhang May 18, 2026
960e8d9
Merge branch 'gh-branch/main' into gh-feature/gdm_rohf
v-boqinzhang May 18, 2026
602ec72
forbid trial_density_energy_fock with MPI
v-boqinzhang May 19, 2026
d004d96
forbid GDM with MPI
v-boqinzhang May 19, 2026
32b6eee
resolve comments 8
v-boqinzhang May 21, 2026
b85588e
CLI review
v-boqinzhang May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,12 @@ class SCFAlgorithm {
int num_molecular_orbitals, int idx_spin);

/**
* @brief Update the density matrix for restricted or unrestricted
* calculations. For ASAHF and ROHF calculations, this method will be
* overridden to implement the specific density matrix construction for those
* methods.
* @brief Update the density matrix for RHF, UHF, or ROHF calculations.
*
* The base implementation handles standard RHF/UHF construction and also
* reconstructs spin-blocked alpha/beta densities for ROHF from a shared
* molecular-orbital coefficient matrix. Algorithms with custom density
* construction (for example ASAHF) can still override this method.
*
* @param[in,out] P Reference to the density matrix to be updated
* @param[in] C Reference to the molecular orbital coefficients
Expand All @@ -113,6 +115,20 @@ class SCFAlgorithm {
bool unrestricted, int nelec_alpha,
int nelec_beta);

/**
* @brief Provide ROHF convergence matrices for OG evaluation
*
* For ROHF, some algorithms evaluate convergence using an effective Fock
* matrix and total density matrix rather than the spin-blocked SCFImpl
* matrices. This helper returns references to those matrices.
*
* @param[in] scf_impl SCF implementation object
* @return Pair of references to convergence Fock and density matrices
* @throws std::logic_error If ROHF convergence matrices are unavailable
*/
std::pair<const RowMajorMatrix&, const RowMajorMatrix&>
try_get_rohf_convergence_matrices(const SCFImpl& scf_impl);

/**
* @brief Calculate orbital gradient (OG) error for convergence checking
*
Expand All @@ -137,6 +153,45 @@ class SCFAlgorithm {
RowMajorMatrix& error_matrix,
int num_orbital_sets);

/**
* @brief Build ROHF convergence matrices from spin-blocked SCF matrices
*
* Converts spin-blocked Fock/density matrices into the effective ROHF Fock
* and total-density representation used for OG evaluation.
*
* @param[in] F Spin-blocked Fock matrix in AO basis with alpha and beta
* blocks stacked by row
* @param[in] C Molecular-orbital coefficient matrix used for AO<->MO
* transformations
* @param[in] P Spin-blocked density matrix in AO basis with alpha and beta
* blocks stacked by row
* @param[in] nelec_alpha Number of alpha electrons
* @param[in] nelec_beta Number of beta electrons
* @param[out] effective_fock Effective ROHF Fock matrix in AO basis
* @param[out] total_density Total AO density matrix (P_alpha + P_beta)
*/
static void build_rohf_f_p_matrix(const RowMajorMatrix& F,
const RowMajorMatrix& C,
const RowMajorMatrix& P, int nelec_alpha,
int nelec_beta,
RowMajorMatrix& effective_fock,
RowMajorMatrix& total_density);

/**
* @brief Access cached ROHF effective Fock matrix
*/
const RowMajorMatrix& get_rohf_convergence_fock_matrix() const;

/**
* @brief Access cached ROHF total density matrix
*/
const RowMajorMatrix& get_rohf_convergence_density_matrix() const;

/**
* @brief Mutable access to cached ROHF total density matrix
*/
RowMajorMatrix& rohf_convergence_density_matrix();

protected:
const SCFContext& ctx_; ///< Reference to SCF context
double og_error_ = 0.0; ///< Current orbital gradient error
Expand All @@ -149,5 +204,7 @@ class SCFAlgorithm {
double delta_energy_ =
std::numeric_limits<double>::infinity(); ///< Energy change
double density_rms_ = 0.0; ///< Last calculated density RMS
RowMajorMatrix rohf_effective_fock_; ///< Cached ROHF effective Fock (AO)
RowMajorMatrix rohf_total_density_; ///< Cached ROHF total density (P_a+P_b)
};
} // namespace qdk::chemistry::scf
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ KSImpl::KSImpl(std::shared_ptr<Molecule> mol, const SCFConfig& cfg,
std::shared_ptr<BasisSet> raw_basis_set)
: SCFImpl(mol, cfg, basis_set, raw_basis_set, true) {
QDK_LOG_TRACE_ENTERING();
if (cfg.scf_orbital_type == SCFOrbitalType::RestrictedOpenShell) {
throw std::invalid_argument(
"ROKS (Restricted Open-Shell Kohn-Sham) is not supported. "
"Use ROHF (scf_type=\"restricted\") without DFT functionals.");
}
#ifdef ENABLE_NVTX3
NVTX3_FUNC_RANGE();
#endif
Expand Down Expand Up @@ -128,12 +133,14 @@ double KSImpl::total_energy_() {

std::pair<double, RowMajorMatrix>
KSImpl::evaluate_trial_density_energy_and_fock(
const RowMajorMatrix& P_matrix, const std::source_location& loc) const {
const RowMajorMatrix& P_matrix, double* J_out, double* K_out,
const std::source_location& loc) const {
QDK_LOG_TRACE_ENTERING();
// Fock matrix from base class does not include XC contributions; XC terms are
// added below
auto [total_energy, F_matrix] =
SCFImpl::evaluate_trial_density_energy_and_fock(P_matrix, loc);
SCFImpl::evaluate_trial_density_energy_and_fock(P_matrix, J_out, K_out,
loc);
Comment thread
v-boqinzhang marked this conversation as resolved.
// Do not update XC_ here: XC_ is a member variable and must not be modified
// in this const trial evaluation.
double scf_xc_energy = 0.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,16 @@ class KSImpl : public SCFImpl {
* must be fully initialized before calling it.
*
* @param P_matrix Trial density matrix
* @param J_out Optional output buffer for Coulomb matrix J
* @param K_out Optional output buffer for exchange matrix K
* @param loc Source location of the caller (automatically captured)
* @return std::pair containing:
* - first: total energy including XC in Hartree
* - second: Fock matrix in AO basis
*/
std::pair<double, RowMajorMatrix> evaluate_trial_density_energy_and_fock(
const RowMajorMatrix& P_matrix,
const RowMajorMatrix& P_matrix, double* J_out = nullptr,
double* K_out = nullptr,
const std::source_location& loc =
std::source_location::current()) const override;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#endif
#include <qdk/chemistry/scf/util/env_helper.h>

#include <cstring>
#include <filesystem>
#include <fstream>
#include <iostream>
Expand Down Expand Up @@ -618,10 +619,20 @@ void SCFImpl::iterate_() {
auto [alpha, beta, omega] = get_hyb_coeff_();
eri_->build_JK(P_.data(), J_.data(), K_.data(), alpha, beta, omega);
update_fock_();
for (int i = 0; i < num_orbital_spin_blocks_; ++i) {
scf_algorithm_->solve_fock_eigenproblem(F_, S_, X_, C_, eigenvalues_, P_,
nelec_, num_atomic_orbitals_,
num_molecular_orbitals_, i);

if (ctx_.cfg->scf_orbital_type == SCFOrbitalType::RestrictedOpenShell) {
const auto rohf_convergence_matrices =
scf_algorithm_->try_get_rohf_convergence_matrices(*this);
const auto& effective_fock = std::get<0>(rohf_convergence_matrices);
scf_algorithm_->solve_fock_eigenproblem(
effective_fock, S_, X_, C_, eigenvalues_, P_, nelec_,
num_atomic_orbitals_, num_molecular_orbitals_, 0);
} else {
for (int i = 0; i < num_orbital_spin_blocks_; ++i) {
scf_algorithm_->solve_fock_eigenproblem(
F_, S_, X_, C_, eigenvalues_, P_, nelec_, num_atomic_orbitals_,
num_molecular_orbitals_, i);
}
}
scf_algorithm_->update_density_matrix(
P_, C_, ctx_.cfg->scf_orbital_type == SCFOrbitalType::Unrestricted,
Expand Down Expand Up @@ -1035,9 +1046,18 @@ void SCFImpl::write_gradients_(const std::vector<double>& gradients,

std::pair<double, RowMajorMatrix>
SCFImpl::evaluate_trial_density_energy_and_fock(
const RowMajorMatrix& P_matrix, const std::source_location& loc) const {
const RowMajorMatrix& P_matrix, double* J_out, double* K_out,
const std::source_location& loc) const {
QDK_LOG_TRACE_ENTERING();

// TODO: This function is called within iterate_ which runs only on rank 0,
// but build_jk_matrices requires participation from all MPI ranks.
if (ctx_.cfg->mpi.world_size > 1) {
throw std::runtime_error(
"Temporary limitation: evaluate_trial_density_energy_and_fock is not "
"supported with MPI world_size > 1.");
}

QDK_LOGGER().debug(
"Computing energy and Fock matrix by trial density matrix (called from "
"function '{}' at line {})",
Expand All @@ -1056,12 +1076,22 @@ SCFImpl::evaluate_trial_density_energy_and_fock(
num_density_matrices_ * num_atomic_orbitals_, num_atomic_orbitals_);
eri_->build_JK(P_matrix.data(), J_matrix.data(), K_matrix.data(), alpha, beta,
omega);

if (J_out != nullptr) {
std::memcpy(J_out, J_matrix.data(),
sizeof(double) * static_cast<size_t>(J_matrix.size()));
}
if (K_out != nullptr) {
std::memcpy(K_out, K_matrix.data(),
sizeof(double) * static_cast<size_t>(K_matrix.size()));
}
#ifdef QDK_CHEMISTRY_ENABLE_PCM
throw std::runtime_error("PCM is not supported in trial density evaluation.");
#endif

if (ctx_.cfg->mpi.world_rank == 0) {
if (ctx_.cfg->scf_orbital_type == SCFOrbitalType::Unrestricted) {
if (ctx_.cfg->scf_orbital_type == SCFOrbitalType::Unrestricted ||
ctx_.cfg->scf_orbital_type == SCFOrbitalType::RestrictedOpenShell) {
F_matrix +=
(J_matrix.block(0, 0, num_atomic_orbitals_, num_atomic_orbitals_) +
J_matrix.block(num_atomic_orbitals_, 0, num_atomic_orbitals_,
Expand Down Expand Up @@ -1097,4 +1127,23 @@ SCFImpl::evaluate_trial_density_energy_and_fock(
return {total_energy, F_matrix};
}

void SCFImpl::build_jk_matrices(const RowMajorMatrix& density_matrix,
RowMajorMatrix& J, RowMajorMatrix& K) const {
QDK_LOG_TRACE_ENTERING();
Comment thread
v-boqinzhang marked this conversation as resolved.

const int expected_rows = num_density_matrices_ * num_atomic_orbitals_;
const int expected_cols = num_atomic_orbitals_;
VERIFY_INPUT(density_matrix.rows() == expected_rows &&
density_matrix.cols() == expected_cols,
"density_matrix shape should be (num_density_matrices_ * "
"num_atomic_orbitals_, num_atomic_orbitals_)");
VERIFY_INPUT(J.rows() == expected_rows && J.cols() == expected_cols,
"J shape should match density_matrix shape");
VERIFY_INPUT(K.rows() == expected_rows && K.cols() == expected_cols,
"K shape should match density_matrix shape");

auto [alpha, beta, omega] = get_hyb_coeff_();
eri_->build_JK(density_matrix.data(), J.data(), K.data(), alpha, beta, omega);
}

} // namespace qdk::chemistry::scf
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,29 @@ class SCFImpl {
*/
const RowMajorMatrix& get_fock_matrix() const { return F_; }

/**
* @brief Get the core Hamiltonian matrix
* @return Reference to core Hamiltonian H
Comment thread
v-boqinzhang marked this conversation as resolved.
*/
const RowMajorMatrix& get_core_hamiltonian() const { return H_; }

/**
* @brief Build Coulomb (J) and exchange (K) matrices for a given density
*
* Utility JK build for a caller-supplied density matrix.
* Currently used by the GDM trial-rotation gradient path
* (GDMLineFunctor / ROHF generalized-gradient evaluation).
* It is not part of the main SCFImpl::iterate_ update loop.
* Keeps this trial-path two-electron build logic in one place.
*
* @param[in] density_matrix Density matrix
* (num_density_matrices x NAO x NAO)
* @param[out] J Output Coulomb matrix (same size as density_matrix)
* @param[out] K Output exchange matrix (same size as density_matrix)
*/
void build_jk_matrices(const RowMajorMatrix& density_matrix,
RowMajorMatrix& J, RowMajorMatrix& K) const;

/**
* @brief Get the molecular orbital coefficient matrix
* @see SCF::get_orbitals_matrix() for API details
Expand Down Expand Up @@ -198,14 +221,19 @@ class SCFImpl {
* must be fully initialized before calling it.
*
* @param P_matrix Trial density matrix
* @param J_out Optional output buffer for Coulomb matrix J (same shape as
* P_matrix)
* @param K_out Optional output buffer for exchange matrix K (same shape as
* P_matrix)
* @param loc Source location of the caller (automatically captured)
* @return std::pair containing:
* - first: total energy in Hartree
* - second: Fock matrix in AO basis
*/
virtual std::pair<double, RowMajorMatrix>
evaluate_trial_density_energy_and_fock(
const RowMajorMatrix& P_matrix,
const RowMajorMatrix& P_matrix, double* J_out = nullptr,
double* K_out = nullptr,
const std::source_location& loc = std::source_location::current()) const;

protected:
Expand Down
Loading
Loading