mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
* c++20 builds working * get MolStandardize building with clang19 * get FMCS building with clang-19 * set cxx version to c++20 * remove a few more compiler warnings * bump min boost version, CI cleanup * boost 1.81 is not available from conda-forge * remove unused constants * bump linux version for CI * remove another unused variable * fix (hopefully) cartridge CI builds * simplify cartridge environment * try postgresql14 in CI * start the postgresql service * change the columns used in the pandastools nbtest * remove missed merge conflict artifact * get github4823 test to pass with numpy 2.2 * remove a compiler warning/error with g++13
210 lines
6.6 KiB
C++
210 lines
6.6 KiB
C++
//
|
|
// Copyright (C) 2018-2020 Greg Landrum
|
|
//
|
|
#include "EHTTools.h"
|
|
#include <GraphMol/RDKitBase.h>
|
|
#include <GraphMol/MolOps.h>
|
|
#include <RDGeneral/BadFileException.h>
|
|
#ifdef RDK_BUILD_THREADSAFE_SSS
|
|
#include <mutex>
|
|
#endif
|
|
#include <fstream>
|
|
#include <cstdio>
|
|
#include <filesystem>
|
|
|
|
extern "C" {
|
|
#include <yaehmop/tightbind/bind.h>
|
|
}
|
|
|
|
namespace RDKit {
|
|
namespace EHTTools {
|
|
// we should only call into the C code, which uses tons of globals, from one
|
|
// thread at a time. This mutex enforces that.
|
|
#ifdef RDK_BUILD_THREADSAFE_SSS
|
|
std::mutex yaehmop_mutex;
|
|
#endif
|
|
|
|
namespace {
|
|
std::string randomstring(unsigned int len = 8) {
|
|
const std::string alphanum{
|
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"};
|
|
const auto strSize = alphanum.size();
|
|
std::string res;
|
|
res.reserve(len);
|
|
|
|
while (res.size() != len) {
|
|
const auto pos = rand() % strSize;
|
|
res.push_back(alphanum[pos]);
|
|
}
|
|
return res;
|
|
}
|
|
// RAII tempfile class
|
|
struct Tempfile {
|
|
std::filesystem::path fname;
|
|
FILE *fptr = nullptr;
|
|
|
|
Tempfile() {
|
|
fname = std::filesystem::temp_directory_path() / randomstring();
|
|
fptr = std::fopen(fname.string().c_str(), "w+");
|
|
if (!fptr) {
|
|
throw BadFileException("could not open temporary file");
|
|
}
|
|
}
|
|
~Tempfile() {
|
|
if (!fptr) {
|
|
return;
|
|
}
|
|
#ifdef WIN32
|
|
std::fclose(fptr);
|
|
#else
|
|
if (fcntl(fileno(fptr), F_GETFD) != -1) {
|
|
std::fclose(fptr);
|
|
}
|
|
#endif
|
|
std::filesystem::remove(fname);
|
|
}
|
|
Tempfile(const Tempfile &o) = delete;
|
|
Tempfile &operator=(const Tempfile &o) = delete;
|
|
Tempfile(Tempfile &&o) = default;
|
|
Tempfile &operator=(Tempfile &&o) = default;
|
|
};
|
|
} // namespace
|
|
|
|
bool runMol(const ROMol &mol, EHTResults &results, int confId,
|
|
bool preserveHamiltonianAndOverlapMatrices) {
|
|
#ifdef RDK_BUILD_THREADSAFE_SSS
|
|
std::lock_guard<std::mutex> lock(yaehmop_mutex);
|
|
#endif
|
|
|
|
// -----------------------------
|
|
// ----- BOILERPLATE -----------
|
|
// -----------------------------
|
|
Tempfile nullHolder;
|
|
FILE *nullfile = nullHolder.fptr;
|
|
status_file = nullfile;
|
|
output_file = nullfile;
|
|
Tempfile destHolder;
|
|
FILE *dest = destHolder.fptr;
|
|
|
|
unit_cell = (cell_type *)calloc(1, sizeof(cell_type));
|
|
details = (detail_type *)calloc(1, sizeof(detail_type));
|
|
|
|
set_details_defaults(details);
|
|
set_cell_defaults(unit_cell);
|
|
|
|
safe_strcpy(details->title, (char *)"RDKit job");
|
|
|
|
// molecular calculation
|
|
details->Execution_Mode = MOLECULAR;
|
|
details->num_KPOINTS = 1;
|
|
details->K_POINTS = (k_point_type *)calloc(1, sizeof(k_point_type));
|
|
details->K_POINTS[0].weight = 1.0;
|
|
details->avg_props = 1;
|
|
details->use_symmetry = 1;
|
|
details->find_princ_axes = 0;
|
|
details->net_chg_PRT = 1;
|
|
details->ROP_mat_PRT = 1;
|
|
details->Rchg_mat_PRT = 1;
|
|
|
|
unit_cell->using_Zmat = 0;
|
|
unit_cell->using_xtal_coords = 0;
|
|
// ---------------------------------
|
|
// ----- END BOILERPLATE -----------
|
|
// ---------------------------------
|
|
|
|
unit_cell->num_atoms = mol.getNumAtoms();
|
|
unit_cell->num_raw_atoms = unit_cell->num_atoms;
|
|
|
|
unit_cell->atoms =
|
|
(atom_type *)calloc(unit_cell->num_atoms, sizeof(atom_type));
|
|
|
|
const Conformer &conf = mol.getConformer(confId);
|
|
for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) {
|
|
safe_strcpy(unit_cell->atoms[i].symb,
|
|
(char *)mol.getAtomWithIdx(i)->getSymbol().c_str());
|
|
auto p = conf.getAtomPos(i);
|
|
unit_cell->atoms[i].loc.x = p.x;
|
|
unit_cell->atoms[i].loc.y = p.y;
|
|
unit_cell->atoms[i].loc.z = p.z;
|
|
}
|
|
|
|
unit_cell->charge = MolOps::getFormalCharge(mol);
|
|
|
|
// -----------------------------
|
|
// ----- BOILERPLATE -----------
|
|
// -----------------------------
|
|
const char *parmFilePtr = nullptr;
|
|
std::string pfName = "";
|
|
if (std::getenv("BIND_PARM_FILE") == nullptr) {
|
|
auto rdbase = std::getenv("RDBASE");
|
|
if (rdbase != nullptr) {
|
|
pfName += rdbase;
|
|
pfName += "/Data/eht_parms.dat";
|
|
std::ifstream f(pfName.c_str());
|
|
if (f.good()) {
|
|
parmFilePtr = pfName.c_str();
|
|
} else {
|
|
std::cerr << "file " << pfName << " doesn't seem to exist" << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
fill_atomic_parms(unit_cell->atoms, unit_cell->num_atoms, nullptr,
|
|
const_cast<char *>(parmFilePtr));
|
|
unit_cell->num_raw_atoms = unit_cell->num_atoms;
|
|
charge_to_num_electrons(unit_cell);
|
|
build_orbital_lookup_table(unit_cell, &num_orbs, &orbital_lookup_table);
|
|
|
|
run_eht(dest);
|
|
// ---------------------------------
|
|
// ----- END BOILERPLATE -----------
|
|
// ---------------------------------
|
|
|
|
// pull properties
|
|
results.numAtoms = mol.getNumAtoms();
|
|
results.numOrbitals = num_orbs;
|
|
results.numElectrons = std::lround(unit_cell->num_electrons);
|
|
results.fermiEnergy = properties.Fermi_E;
|
|
results.totalEnergy = properties.total_E;
|
|
results.atomicCharges = std::make_unique<double[]>(mol.getNumAtoms());
|
|
std::memcpy(static_cast<void *>(results.atomicCharges.get()),
|
|
static_cast<void *>(properties.net_chgs),
|
|
mol.getNumAtoms() * sizeof(double));
|
|
size_t sz = mol.getNumAtoms() * num_orbs;
|
|
results.reducedChargeMatrix = std::make_unique<double[]>(sz);
|
|
memcpy(static_cast<void *>(results.reducedChargeMatrix.get()),
|
|
static_cast<void *>(properties.Rchg_mat), sz * sizeof(double));
|
|
|
|
sz = mol.getNumAtoms() * (mol.getNumAtoms() + 1) / 2;
|
|
results.reducedOverlapPopulationMatrix = std::make_unique<double[]>(sz);
|
|
memcpy(static_cast<void *>(results.reducedOverlapPopulationMatrix.get()),
|
|
static_cast<void *>(properties.ROP_mat), sz * sizeof(double));
|
|
|
|
results.orbitalEnergies = std::make_unique<double[]>(num_orbs);
|
|
std::memcpy(static_cast<void *>(results.orbitalEnergies.get()),
|
|
static_cast<void *>(eigenset.val), num_orbs * sizeof(double));
|
|
|
|
if (preserveHamiltonianAndOverlapMatrices) {
|
|
// these need to be recalculated, because they were overwritten during the
|
|
// calculation
|
|
R_space_overlap_matrix(unit_cell, details, Overlap_R, num_orbs,
|
|
tot_overlaps, orbital_lookup_table, 0);
|
|
full_R_space_Hamiltonian(unit_cell, details, Overlap_R, Hamil_R, num_orbs,
|
|
orbital_lookup_table, 1);
|
|
sz = num_orbs * num_orbs * sizeof(double);
|
|
results.hamiltonianMatrix = std::make_unique<double[]>(sz);
|
|
std::memcpy(static_cast<void *>(results.hamiltonianMatrix.get()),
|
|
static_cast<void *>(Hamil_R.mat), sz);
|
|
results.overlapMatrix = std::make_unique<double[]>(sz);
|
|
std::memcpy(static_cast<void *>(results.overlapMatrix.get()),
|
|
static_cast<void *>(Overlap_R.mat), sz);
|
|
}
|
|
cleanup_memory();
|
|
|
|
fclose(nullfile);
|
|
fclose(dest);
|
|
return true;
|
|
}
|
|
|
|
} // end of namespace EHTTools
|
|
} // end of namespace RDKit
|