Skip to content

Implementation of EEQ-BC and unit tests #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Thomas3R
Copy link
Contributor

This pull request introduces significant improvements and refactoring to the charge model and coordination number logic in the codebase. The main changes include a redesign of the coordination number calculation, the addition of a new charge model (EEQBCModel), and enhanced flexibility for coordination number handling via new base and derived classes. The changes also streamline the interface for charge calculation and improve memory management.

Charge Model and Coordination Number Refactoring

  • The ChargeModel class now owns a NCoordErf member and delegates the calculation of coordination numbers to a new virtual method get_cn, allowing derived models to customize how coordination numbers are computed. This enables more flexible and extensible charge model implementations.

Addition of New Charge Model

  • A new EEQBCModel class is introduced, supporting bond capacitance-based charge calculation. This class includes extensive element-specific parameters and methods for local charge, capacitance matrix. It offers analytic partial charges and numerical gradients.

Coordination Number Class Hierarchy Enhancement

  • The coordination number logic is refactored into a base class NCoordBase and several derived classes (NCoordErf, NCoordErfEN, NCoordErfD4). This supports different counting functions, covalent radii handling, and electronegativity scaling, making the coordination number calculation more modular and adaptable to different charge models.

API and Interface Improvements

  • Method signatures in the charge and coordination number classes are updated for clarity, consistency, and to better separate concerns. For example, the counting function now takes explicit atomic distances and covalent radii, improving correctness and readability.

Memory Management Fix

  • A memory leak is fixed in the matrix inversion routine by ensuring that the pivot array is deleted in all error cases, improving code safety and reliability.

@marvinfriede marvinfriede requested a review from Copilot August 15, 2025 11:20
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request implements the EEQ-BC (Electronegativity Equilibration with Bond Capacitance) charge model and significantly refactors the coordination number calculation system. The changes introduce a more flexible class hierarchy for coordination number computations and add comprehensive unit tests for the new functionality.

Key changes include:

  • Implementation of EEQBCModel class with bond capacitance-based charge calculation
  • Refactoring of coordination number classes into a base-derived hierarchy (NCoordBase, NCoordErf, NCoordErfEN, NCoordErfD4)
  • Enhanced coordination number calculation with configurable parameters and electronegativity scaling
  • Addition of comprehensive unit tests for the new EEQ-BC model and parameter validation

Reviewed Changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
test/test_multi.h Header file defining reference values and test function declaration for EEQ-BC model validation
test/test_multi.cpp Unit test implementation for EEQ-BC parameters and charge calculation functionality
test/molecules.h Addition of hydroxide ion test molecules with different atom orderings
test/meson.build Integration of new multi test into the build system
test/main.cpp Registration of multi test in the main test runner
src/dftd_ncoord.cpp Major refactoring of coordination number calculation with new class hierarchy and enhanced functionality
src/dftd_eeq.cpp Implementation of EEQ-BC model and refactoring of charge model interface
include/dftd_ncoord.h Header definitions for the new coordination number class hierarchy

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

} else {
info = ncoord_base(mol, realIdx, dist);
}
if (info != EXIT_SUCCESS) return info;

info = cut_coordination_number(cn_max, cn, dcndr, lgrad);
if (info != EXIT_SUCCESS) return info;
if (cn_max != -1.0) { // cn_max = -1.0 for EEQ-BC for cn and qloc; using NCoordErf and NCoordErfEN
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (cn_max != -1.0) { // cn_max = -1.0 for EEQ-BC for cn and qloc; using NCoordErf and NCoordErfEN
if (cn_max < 0.0) { // cn_max = -1.0 for EEQ-BC for cn and qloc; using NCoordErf and NCoordErfEN

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should also work instead of float comparison.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the advantage here? Why not use the exact value that cn_max is set to?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Equality comparison of floats is discouraged due to rounding errors.

} else {
info = ncoord_base(mol, realIdx, dist);
}
if (info != EXIT_SUCCESS) return info;

info = cut_coordination_number(cn_max, cn, dcndr, lgrad);
if (info != EXIT_SUCCESS) return info;
if (cn_max != -1.0) { // cn_max = -1.0 for EEQ-BC for cn and qloc; using NCoordErf and NCoordErfEN
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should also work instead of float comparison.

namespace eeqbc {

// Maximum value of the atom number implemented in the EEQ_BC model
constexpr int MAXELEMENT = 104;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be too new for ORCA's C++ standard. Not sure though.


f_en = get_en_factor(mol.ATNO(i), mol.ATNO(j));
countf = f_en * count_fct(rr);
countf = f_en * count_fct(r, rcovij);
cn(ii) += countf;
cn(jj) += countf;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No f_directed here?

Copy link
Contributor Author

@Thomas3R Thomas3R Aug 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, the JJ index should always get the directed factor. Apparently, this is not covered by the eeq-bc unit test. Maybe we can find a system where this makes a difference.

src/dftd_eeq.cpp Outdated
Comment on lines 443 to 448
int EEQBCModel::get_amat_0d(
const TMolecule &mol,
const TIVector &realIdx,
const TMatrix<double> &dist,
TMatrix<double> &Amat
) const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No ghost atom handling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not work because the matrices use the compressed format, i.e., only contain real atoms, but mol.NAtoms contains all atoms.

bool lgrad);
/**
/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Format

Comment on lines +36 to +37
//TVector<double> cn; // coordination number
//TMatrix<double> dcndr; // derivative of the coordination number
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove if not needed anymore.


int EEQModel::get_vrhs(
const TMolecule &mol,
const TIVector &realIdx,
const int &charge,
const TMatrix<double> &dist,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed in the function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dist matrix is needed in the EEQBCModel::get_vrhs

const TVector<double> &cn,
TVector<double> &Xvec,
TVector<double> &dXvec,
const TMatrix<double> &dcndr,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Derivative not used in method

Comment on lines +283 to +284
const TVector<double> &cn,
const TMatrix<double> &dcndr,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are also not needed. Please double-check the signatures (compare with the Fortran implementation at https://github.com/grimme-lab/multicharge/blob/main/src/multicharge/model.F90)

TVector<double> qloc; // local charges
TMatrix<double> cmat; // capacitance matrix

//
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty comment

const TVector<double> &cn,
const TMatrix<double> &dcndr,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also below, derivative should not be required.

EEQModel();

int get_vrhs(
const TMolecule &mol,
const TIVector &realIdx,
const int &charge,
const TMatrix<double> &dist,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required?

Comment on lines +181 to +182
const TVector<double> &cn,
const TMatrix<double> &dcndr,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required? Especially, the derivative should not be required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants