diff --git a/src/soap/bindings.cpp b/src/soap/bindings.cpp index 26d2002c01fc58bc34b1880e63cccd974f75866d..2829d6c02475629e1560b9cd050cb4507cb13adf 100644 --- a/src/soap/bindings.cpp +++ b/src/soap/bindings.cpp @@ -1,4 +1,5 @@ #include "bindings.hpp" +#include "coulomb.hpp" namespace soap { @@ -11,14 +12,17 @@ BOOST_PYTHON_MODULE(_soapxx) soap::Structure::registerPython(); soap::Segment::registerPython(); soap::Particle::registerPython(); - soap::Options::registerPython(); + soap::Spectrum::registerPython(); soap::Basis::registerPython(); soap::AtomicSpectrum::registerPython(); soap::BasisExpansion::registerPython(); soap::PowerExpansion::registerPython(); + soap::EnergySpectrum::registerPython(); + soap::HierarchicalCoulomb::registerPython(); + soap::AtomicSpectrumHC::registerPython(); soap::RadialBasisFactory::registerAll(); soap::AngularBasisFactory::registerAll(); diff --git a/src/soap/coulomb.cpp b/src/soap/coulomb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e0e2b1b0952957f667d3387de2fad122eae8a0c --- /dev/null +++ b/src/soap/coulomb.cpp @@ -0,0 +1,251 @@ +#include "soap/coulomb.hpp" +#include "soap/linalg/numpy.hpp" + +namespace soap { + +namespace ub = boost::numeric::ublas; + +// ===================================== +// Spectrum::HierarchicalCoulomb::Atomic +// ===================================== + +const std::string AtomicSpectrumHC::_numpy_t = "float64"; + +AtomicSpectrumHC::AtomicSpectrumHC(Particle *center, int S) + : _center(center), _S(S) { + this->_Q0 = coeff_zero_t(S,1); + this->_Q1 = coeff_zero_t(S,S); + this->_Q2 = coeff_zero_t(S,S*S); + this->_Q3 = coeff_zero_t(S,S*S*S); + + this->_s = center->getTypeId()-1; + assert(_s >= 0 && "Type-IDs should start from 1"); +} + +AtomicSpectrumHC::~AtomicSpectrumHC() { + _Q0.clear(); + _Q1.clear(); + _Q2.clear(); + _Q3.clear(); +} + +void AtomicSpectrumHC::setCoefficientsNumpy_k1(boost::python::object &np_array) { + throw soap::base::APIError("<AtomicSpectrumHC::setCoefficientsNumpy> Not implemented."); +} + +void AtomicSpectrumHC::setCoefficientsNumpy_k2(boost::python::object &np_array) { + throw soap::base::APIError("<AtomicSpectrumHC::setCoefficientsNumpy> Not implemented."); +} + +void AtomicSpectrumHC::setCoefficientsNumpy_k3(boost::python::object &np_array) { + throw soap::base::APIError("<AtomicSpectrumHC::setCoefficientsNumpy> Not implemented."); +} + +void AtomicSpectrumHC::setCoefficientsNumpy_k4(boost::python::object &np_array) { + throw soap::base::APIError("<AtomicSpectrumHC::setCoefficientsNumpy> Not implemented."); +} + +boost::python::object AtomicSpectrumHC::getCoefficientsNumpy_k1() { + soap::linalg::numpy_converter npc(_numpy_t.c_str()); + return npc.ublas_to_numpy< dtype_t >(_Q0); +} + +boost::python::object AtomicSpectrumHC::getCoefficientsNumpy_k2() { + soap::linalg::numpy_converter npc(_numpy_t.c_str()); + return npc.ublas_to_numpy< dtype_t >(_Q1); +} + +boost::python::object AtomicSpectrumHC::getCoefficientsNumpy_k3() { + soap::linalg::numpy_converter npc(_numpy_t.c_str()); + return npc.ublas_to_numpy< dtype_t >(_Q2); +} + +boost::python::object AtomicSpectrumHC::getCoefficientsNumpy_k4() { + soap::linalg::numpy_converter npc(_numpy_t.c_str()); + return npc.ublas_to_numpy< dtype_t >(_Q3); +} + +void AtomicSpectrumHC::registerPython() { + using namespace boost::python; + class_<AtomicSpectrumHC, AtomicSpectrumHC*>("AtomicSpectrumHC", init<Particle*, int>()) + .add_property("array_k1", &AtomicSpectrumHC::getCoefficientsNumpy_k1, &AtomicSpectrumHC::setCoefficientsNumpy_k1) + .add_property("array_k2", &AtomicSpectrumHC::getCoefficientsNumpy_k2, &AtomicSpectrumHC::setCoefficientsNumpy_k2) + .add_property("array_k3", &AtomicSpectrumHC::getCoefficientsNumpy_k3, &AtomicSpectrumHC::setCoefficientsNumpy_k3) + .add_property("array_k4", &AtomicSpectrumHC::getCoefficientsNumpy_k4, &AtomicSpectrumHC::setCoefficientsNumpy_k4) + .def("getArray_k1", &AtomicSpectrumHC::getCoefficientsNumpy_k1) + .def("getArray_k2", &AtomicSpectrumHC::getCoefficientsNumpy_k2) + .def("getArray_k3", &AtomicSpectrumHC::getCoefficientsNumpy_k3) + .def("getArray_k4", &AtomicSpectrumHC::getCoefficientsNumpy_k4); +} + +// ============================= +// Spectrum::HierarchicalCoulomb +// ============================= + +HierarchicalCoulomb::HierarchicalCoulomb(Structure &structure, Options &options) { + GLOG() << "Creating HierarchicalCoulomb ..." << std::endl; + _structure = &structure; + _options = &options; + _cutoff = CutoffFunctionOutlet().create(_options->get<std::string>("radialcutoff.type")); + _cutoff->configure(*_options); + _S = 5; // TODO + return; +} + +HierarchicalCoulomb::~HierarchicalCoulomb() { + for (auto it = _atomic_array.begin(); it != _atomic_array.end(); ++it) { + delete *it; + } + _atomic_array.clear(); + return; +} + +void HierarchicalCoulomb::compute() { + GLOG() << "Computing HierarchicalCoulomb ..." << std::endl; + + // CLEAN EXISTING + for (auto it = _atomic_array.begin(); it != _atomic_array.end(); ++it) { + delete *it; + } + _atomic_array.clear(); + // CREATE ATOMIC SPECTRA + for (auto pit = _structure->beginParticles(); pit != _structure->endParticles(); ++pit) { + atomic_t *new_atomic = new atomic_t(*pit, _S); + _atomic_array.push_back(new_atomic); + } + + double R0 = _options->get<double>("hierarchicalcoulomb.r0"); + double gamma = _options->get<double>("hierarchicalcoulomb.gamma"); + bool norm = _options->get<bool>("hierarchicalcoulomb.norm"); + + // ZEROETH-ORDER + GLOG() << "k = 1-body ..." << std::endl; + for (auto it = beginAtomic(); it != endAtomic(); ++it) { + atomic_t *a = *it; + int sa = a->getTypeIdx(); + double wa = a->getCenter()->getWeight(); + GLOG() << " " << a->getCenter()->getId() << std::endl; + a->_Q0(sa, 0) = wa/pow(R0, gamma); + } + if (norm) { + for (auto it = beginAtomic(); it != endAtomic(); ++it) { + atomic_t *a = *it; + a->_Q0 = a->_Q0/ub::norm_frobenius(a->_Q0); + } + } + + // FIRST-ORDER + GLOG() << "k = 2-body ..." << std::endl; + for (auto it1 = beginAtomic(); it1 != endAtomic(); ++it1) { + atomic_t *a = *it1; + int sa = a->getTypeIdx(); + vec ra = a->getCenter()->getPos(); + for (auto it2 = beginAtomic(); it2 != endAtomic(); ++it2) { + atomic_t *b = *it2; + int sb = b->getTypeIdx(); + vec rb = b->getCenter()->getPos(); + // Apply weight function + vec dr_ab = _structure->connect(ra, rb); + double R_ab = soap::linalg::abs(dr_ab); + if (! _cutoff->isWithinCutoff(R_ab)) continue; + double w_ab = _cutoff->calculateWeight(R_ab); + GLOG() << " " << a->getCenter()->getId() << ":" << b->getCenter()->getId() << " R=" << R_ab << " w=" << w_ab << std::endl; + // Interact + double inter_ab = w_ab/pow(R_ab+R0, gamma); + a->_Q1(sa, sb) += ( + a->_Q0(sa,0)*b->_Q0(sb,0) + )*inter_ab; + } + } + if (norm) { + for (auto it = beginAtomic(); it != endAtomic(); ++it) { + atomic_t *a = *it; + a->_Q1 = a->_Q1/ub::norm_frobenius(a->_Q1); + } + } + // SECOND-ORDER + GLOG() << "k = 3-body ..." << std::endl; + for (auto it1 = beginAtomic(); it1 != endAtomic(); ++it1) { + atomic_t *a = *it1; + int sa = a->getTypeIdx(); + vec ra = a->getCenter()->getPos(); + for (auto it2 = beginAtomic(); it2 != endAtomic(); ++it2) { + atomic_t *b = *it2; + int sb = b->getTypeIdx(); + vec rb = b->getCenter()->getPos(); + // Apply weight function + vec dr_ab = _structure->connect(ra, rb); + double R_ab = soap::linalg::abs(dr_ab); + if (! _cutoff->isWithinCutoff(R_ab)) continue; + double w_ab = _cutoff->calculateWeight(R_ab); + GLOG() << " " << a->getCenter()->getId() << ":" << b->getCenter()->getId() << " R=" << R_ab << " w=" << w_ab << std::endl; + // Interact + double inter_ab = w_ab/pow(R_ab+R0, gamma); + for (int sb = 0; sb < _S; ++sb) { + for (int sc = 0; sc < _S; ++sc) { + a->_Q2(sa, sb*_S+sc) += ( + a->_Q1(sa,sb) *b->_Q0(sc,0) + // runs over sb + a->_Q0(sa,0) *b->_Q1(sb,sc) // runs over sc + )*inter_ab; + } + } + } + } + if (norm) { + for (auto it = beginAtomic(); it != endAtomic(); ++it) { + atomic_t *a = *it; + a->_Q2 = a->_Q2/ub::norm_frobenius(a->_Q2); + } + } + + // THIRD-ORDER + GLOG() << "k = 4-body ..." << std::endl; + for (auto it1 = beginAtomic(); it1 != endAtomic(); ++it1) { + atomic_t *a = *it1; + int sa = a->getTypeIdx(); + vec ra = a->getCenter()->getPos(); + for (auto it2 = beginAtomic(); it2 != endAtomic(); ++it2) { + atomic_t *b = *it2; + int sb = b->getTypeIdx(); + vec rb = b->getCenter()->getPos(); + // Apply weight function + vec dr_ab = _structure->connect(ra, rb); + double R_ab = soap::linalg::abs(dr_ab); + if (! _cutoff->isWithinCutoff(R_ab)) continue; + double w_ab = _cutoff->calculateWeight(R_ab); + GLOG() << " " << a->getCenter()->getId() << ":" << b->getCenter()->getId() << " R=" << R_ab << " w=" << w_ab << std::endl; + // Interact + double inter_ab = w_ab/pow(R_ab+R0, gamma); + for (int sb = 0; sb < _S; ++sb) { + for (int sc = 0; sc < _S; ++sc) { + for (int sd = 0; sd < _S; ++sd) { + a->_Q3(sa, sb*_S*_S+sc*_S+sd) += ( + a->_Q0(sa,0) *b->_Q2(sb, sc*_S+sd) + // runs over sc, sd + a->_Q1(sa,sb) *b->_Q1(sc, sd) + // runs over sb, sd + a->_Q2(sa,sb*_S+sc) *b->_Q0(sd,0) // runs over sb, sc + )*inter_ab; + } + } + } + } + } + + if (norm) { + for (auto it = beginAtomic(); it != endAtomic(); ++it) { + atomic_t *a = *it; + a->_Q3 = a->_Q3/ub::norm_frobenius(a->_Q3); + } + } + + return; +} + +void HierarchicalCoulomb::registerPython() { + using namespace boost::python; + class_<HierarchicalCoulomb>("HierarchicalCoulomb", init<Structure &, Options &>()) + .def("__iter__", range<return_value_policy<reference_existing_object> >(&HierarchicalCoulomb::beginAtomic, &HierarchicalCoulomb::endAtomic)) + .def("compute", &HierarchicalCoulomb::compute); + return; +} + +} diff --git a/src/soap/coulomb.hpp b/src/soap/coulomb.hpp new file mode 100644 index 0000000000000000000000000000000000000000..49e4cdf23aafe0069c87379d6e3b99bf50308963 --- /dev/null +++ b/src/soap/coulomb.hpp @@ -0,0 +1,75 @@ +#ifndef _SOAP_COULOMB_HPP +#define _SOAP_COULOMB_HPP + +#include "soap/structure.hpp" +#include "soap/options.hpp" +#include "soap/cutoff.hpp" + +namespace soap { + +class AtomicSpectrumHC +{ +public: + typedef double dtype_t; + typedef ub::matrix<dtype_t> coeff_t; + typedef ub::zero_matrix<dtype_t> coeff_zero_t; + static const std::string _numpy_t; + + AtomicSpectrumHC(Particle *center, int S); + ~AtomicSpectrumHC(); + Particle *getCenter() { return _center; } + int getTypeIdx() { return _s; } + + static void registerPython(); + void setCoefficientsNumpy_k1(boost::python::object &np_array); + void setCoefficientsNumpy_k2(boost::python::object &np_array); + void setCoefficientsNumpy_k3(boost::python::object &np_array); + void setCoefficientsNumpy_k4(boost::python::object &np_array); + boost::python::object getCoefficientsNumpy_k1(); + boost::python::object getCoefficientsNumpy_k2(); + boost::python::object getCoefficientsNumpy_k3(); + boost::python::object getCoefficientsNumpy_k4(); + + coeff_t _Q0; + coeff_t _Q1; + coeff_t _Q2; + coeff_t _Q3; + +private: + Particle *_center; + int _S; // <- Number of distinct types + int _s; // <- Type index +}; + +class HierarchicalCoulomb +{ +public: + typedef AtomicSpectrumHC atomic_t; + typedef std::vector<AtomicSpectrumHC*> atomic_array_t; + typedef std::vector<AtomicSpectrumHC*>::iterator atomic_it_t; + + HierarchicalCoulomb(Structure &structure, Options &options); + ~HierarchicalCoulomb(); + void compute(); + atomic_it_t beginAtomic() { return _atomic_array.begin(); } + atomic_it_t endAtomic() { return _atomic_array.end(); } + + static void registerPython(); + +private: + Structure *_structure; + Options *_options; + CutoffFunction *_cutoff; + int _S; + + atomic_array_t _atomic_array; +}; + +} + + + + + + +#endif /* _SOAP_COULOMB_HPP */