Skip to content

Conversation

@awvwgk
Copy link
Collaborator

@awvwgk awvwgk commented Jan 19, 2026

  • GauXC::Molecule in gauxc/molecule.hpp
  • GauXC::Atom in gauxc/atom.hpp
  • GauXC::BasisSet in gauxc/basisset.hpp (double only)
  • GauXC::Shell in gauxc/shell.hpp
    • set_shell_tolerance method
  • GauXC::RuntimeEnvironment and GauXC::DeviceRuntimeEnvironment
    • set_buffer, comm_rank, comm_size
  • GauXC::AtomicGridSizeDefault, GauXC::PruningScheme, GauXC::RadialQuad in gauxc/enum.hpp
  • GauXC::MolGridFactory
    • create_default_molgrid
  • GauXC::MolGrid
  • GauXC::ExecutionSpace in gauxc/enum.hpp
  • GauXC::LoadBalancerFactory
    • get_shared_instance method
  • GauXC::MolecularWeightsFactory
    • get_instance method
  • GauXC::MolecularWeightsSettings
  • GauXC::functional_type (from ExchCXX)
  • GauXC::XCIntegratorFactory
    • get_instance method
    • provide default matrix type implementation for C
  • GauXC::XCIntegrator
    • eval_exc, eval_exc_vxc, etc. methods

Closes #171

@awvwgk awvwgk self-assigned this Jan 19, 2026
@awvwgk awvwgk force-pushed the c-api branch 3 times, most recently from dd396c2 to 5881a76 Compare January 26, 2026 09:54
@awvwgk awvwgk force-pushed the c-api branch 3 times, most recently from 1d61b38 to 83841ad Compare January 27, 2026 10:05
@awvwgk awvwgk changed the title [WIP] Basic C API for GauXC Basic C API for GauXC Jan 27, 2026
@awvwgk awvwgk added the enhancement New feature or request label Jan 27, 2026
Copy link

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 adds a comprehensive C API for the GauXC library, enabling integration with C codebases and other languages that interface with C. The implementation wraps core GauXC C++ functionality including molecular structures, basis sets, integration grids, load balancing, and XC integrators.

Changes:

  • Added C API bindings for core classes (Molecule, Atom, BasisSet, Shell, etc.)
  • Implemented factory patterns for runtime environments, load balancers, molecular weights, and XC integrators
  • Created C/C++ compatible enum definitions with mappings between C and C++ versions
  • Added HDF5 I/O support for C API
  • Refactored configuration headers to separate C and C++ concerns

Reviewed changes

Copilot reviewed 47 out of 47 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
include/gauxc/*.h New C API header files defining opaque handles and functions for core types
include/gauxc/util/c_*.hpp Helper headers for casting between C handles and C++ objects
src/c_*.cxx C API implementation files wrapping C++ functionality
include/gauxc/enum.h C-compatible enum definitions
include/gauxc/enums.hpp C++ enum class definitions mapped to C enums
include/gauxc/gauxc_config.h.in C-compatible configuration header
include/gauxc/gauxc_config.hpp C++ configuration header including C header
tests/moltypes_test.cxx Basic C API interoperability test
src/CMakeLists.txt CMake integration for conditional C API compilation
src/external/c_hdf5_*.cxx HDF5 I/O functions for C API

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- provide C enums
- add atom and molecule types
- add basis set and shell definitions
- add molecule grid and runtime environment
- add load balancer to C API
- add molecular weights for C API
- add functional class wrapping ExchCXX
- add xc integrator and matrix type
- add references for functionals
- add support for reading and writing from HDF5 in C
Copy link

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

Copilot reviewed 48 out of 48 changed files in this pull request and generated 17 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* @brief Create a new XCIntegratorFactory instance.
* @param status Status object to capture any errors.
* @param execution_space Execution space to use.
* @param integrator_input_type Type of integrator input.
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The parameter name integrator_input_type is inconsistent with the actual usage. The parameter is documented as "Type of integrator input" but the actual C++ constructor template parameter is for the matrix type (CMatrix). Consider renaming to matrix_type or updating the documentation to reflect that this is the matrix type specification.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +30
try {
mol.ptr = new Molecule();
status->code = 0;
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The status->message field is not initialized to nullptr in successful code paths. When status->code is set to 0, status->message should also be explicitly set to nullptr (or NULL in C) to ensure consistent state. This affects all functions that use the status pattern throughout the C API.

Copilot uses AI. Check for mistakes.
#ifdef __cplusplus
} // extern "C"
} // namespace GauXC::C
#endif
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The HDF5 include guard checks for GAUXC_HAS_HDF5 but this file is only included when HDF5 is enabled (based on the CMakeLists.txt). The guard on line 13 provides defense in depth, which is good practice, but consider whether the entire file should error out or provide stub implementations when HDF5 is not available, rather than silently compiling to nothing.

Suggested change
#endif
#endif
#else
#error "GauXC was built without HDF5 support, but <gauxc/external/hdf5.h> was included. Enable GAUXC_HAS_HDF5 to use this header."

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +49
GauXCMolGrid gauxc_molgrid_new_default(
GauXCStatus* status,
const GauXCMolecule mol,
const enum GauXC_PruningScheme pruning_scheme,
const int64_t batchsize,
const enum GauXC_RadialQuad radial_quad,
const enum GauXC_AtomicGridSizeDefault grid_size
) {
GauXCMolGrid mg{};
mg.ptr = nullptr;

try {
auto grid_map = MolGridFactory::create_default_gridmap(
*detail::get_molecule_ptr(mol),
static_cast<PruningScheme>(pruning_scheme),
static_cast<BatchSize>(batchsize),
static_cast<RadialQuad>(radial_quad),
static_cast<AtomicGridSizeDefault>(grid_size)
);
mg.ptr = new MolGrid(grid_map);
status->code = 0;
} catch (std::exception& e) {
status->code = 1;
status->message = detail::strdup(e.what());
}
return mg;
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The GauXCMolGrid struct is missing the hdr field initialization before returning it. In lines 32-33, mg.ptr is set to nullptr but mg.hdr is never initialized. This should be initialized similar to other factory functions, e.g., mg.hdr = GauXCHeader{GauXC_Type_MolGrid}; before line 36 (in the try block after successful creation).

Copilot uses AI. Check for mistakes.
Comment on lines +143 to +149
void resize(size_t rows, size_t cols) {
if (rows == rows_ && cols == cols_) return;
delete[] data_;
rows_ = rows;
cols_ = cols;
data_ = new value_type[rows * cols]();
}
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

In the resize method, if rows == 0 or cols == 0, the allocation new value_type[rows * cols]() will allocate a zero-sized array (or array of size 0), which could lead to implementation-defined behavior. Consider explicitly handling the zero-size case by setting data_ to nullptr and not allocating.

Copilot uses AI. Check for mistakes.
SphericalType{shell.pure},
alpha, coeff, O, normalize };

if (shell.shell_tolerance >= 0.0) {
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

Missing boundary check for shell tolerance. The condition if (shell.shell_tolerance >= 0.0) should use > instead of >= since a tolerance of exactly 0.0 might not be a valid/meaningful threshold. Alternatively, if 0.0 is a valid value, this should be documented.

Suggested change
if (shell.shell_tolerance >= 0.0) {
if (shell.shell_tolerance > 0.0) {

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +62
void gauxc_matrix_resize(
GauXCStatus* status,
const GauXCMatrix matrix,
const size_t rows,
const size_t cols
) {
status->code = 0;
try { // can throw std::bad_alloc
detail::get_matrix_ptr(matrix)->resize( rows, cols );
} catch (std::exception& e) {
status->code = 1;
status->message = detail::strdup(e.what());
}
}
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The parameter matrix should be marked as const since the function only reads from the matrix and doesn't modify it. This applies to the function declarations in the header as well (lines 66-70 in matrix.h).

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +80
try {
auto polar = polarized ? ExchCXX::Spin::Polarized : ExchCXX::Spin::Unpolarized;
functional_type func;
if(ExchCXX::functional_map.key_exists(functional_spec)) {
func = functional_type( ExchCXX::Backend::builtin, ExchCXX::functional_map.value(functional_spec),
polar );
}
#ifdef EXCHCXX_ENABLE_LIBXC
else {
std::vector<std::pair<double, ExchCXX::XCKernel>> funcs;
std::vector<std::string> libxc_names;
detail::split(libxc_names, functional_spec, ",");
for( auto n : libxc_names ) {
funcs.push_back( {1.0, ExchCXX::XCKernel(ExchCXX::libxc_name_string(n), polar)} );
}
func = functional_type(funcs);
}
#endif

Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

Missing error handling for the case where the functional name is not found in ExchCXX::functional_map and EXCHCXX_ENABLE_LIBXC is not defined. In this case, the func variable would be uninitialized, leading to undefined behavior when passed to new functional_type. Add an else clause to throw an exception with a clear error message.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +80
inline static void gauxc_objects_delete(
GauXCStatus* status,
void** ptrs,
size_t nptrs
) {
status->code = 0;
for(void** ptr = ptrs; ptr < ptrs + nptrs; ++ptr) {
#ifdef __cplusplus
if(*ptr != nullptr) {
#else
if(*ptr != NULL) {
#endif
gauxc_object_delete( status, ptr );
if(status->code != 0) return;
}
}
}
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The function gauxc_objects_delete is defined as inline static in a header file. This can lead to linker errors when compiling in C mode if multiple translation units include this header, as each will have its own definition of the function. For C compatibility, consider either: (1) removing the inline keyword and defining the function in a source file, or (2) keeping it inline but ensuring it's only called from one translation unit, or (3) using appropriate guards to handle C vs C++ compilation differences.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C API Related to the C API enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Basic C API

1 participant