diff --git a/.gitignore b/.gitignore index ed5c116b2ba209e5a6d3b75d856c21e99addd32d..08b2c79005fd7443817b6cd54013981bbbae9e36 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ test/back *.coeff *.cube *.arch +*.back diff --git a/src/spectrum.cpp b/src/spectrum.cpp index 15ffd5055ec64ae8546b2bd687c6f82c42d38905..e11b41483285191f85e2be7e1a27549281633e10 100644 --- a/src/spectrum.cpp +++ b/src/spectrum.cpp @@ -41,22 +41,118 @@ Spectrum::~Spectrum() { } void Spectrum::compute() { - GLOG() << "Compute spectrum ..." << std::endl; + this->compute(_structure->particles(), _structure->particles()); +} + +void Spectrum::compute(Segment *center, Segment *target) { + this->compute(center->particles(), target->particles()); +} + +void Spectrum::compute(Structure::particle_array_t ¢ers, Structure::particle_array_t &targets) { + GLOG() << "Compute spectrum " + << "(centers " << centers.size() << ", targets " << targets.size() << ") ..." << std::endl; GLOG() << _options->summarizeOptions() << std::endl; GLOG() << "Using radial basis of type '" << _basis->getRadBasis()->identify() << "'" << std::endl; GLOG() << "Using angular basis of type '" << _basis->getAngBasis()->identify() << "'" << std::endl; GLOG() << "Using cutoff function of type '" << _basis->getCutoff()->identify() << "'" << std::endl; Structure::particle_it_t pit; - for (pit = _structure->beginParticles(); pit != _structure->endParticles(); ++pit) { + for (pit = centers.begin(); pit != centers.end(); ++pit) { // Continue if exclusion defined ... if (_options->doExcludeCenter((*pit)->getType())) continue; // Compute ... - AtomicSpectrum *atomic_spectrum = this->computeAtomic(*pit); - //atomic_spectrum->getReduced()->writeDensityOnGrid("density.expanded.cube", _options, _structure, *pit, true); - //atomic_spectrum->getReduced()->writeDensityOnGrid("density.explicit.cube", _options, _structure, *pit, false); - this->addAtomic(atomic_spectrum); + AtomicSpectrum *atomic_spectrum = this->computeAtomic(*pit, targets); + //atomic_spectrum->getReduced()->writeDensityOnGrid("density.expanded.cube", _options, _structure, *pit, true); + //atomic_spectrum->getReduced()->writeDensityOnGrid("density.explicit.cube", _options, _structure, *pit, false); + this->addAtomic(atomic_spectrum); + } +} + +void Spectrum::computePower() { + atomspec_array_t::iterator it; + for (it = _atomspec_array.begin(); it != _atomspec_array.end(); ++it) { + (*it)->computePower(); + } + return; +} + +AtomicSpectrum *Spectrum::computeAtomic(Particle *center) { + return this->computeAtomic(center, _structure->particles()); +} + +AtomicSpectrum *Spectrum::computeAtomic(Particle *center, Structure::particle_array_t &targets) { + GLOG() << "Compute atomic spectrum for particle " << center->getId() + << " (type " << center->getType() << ", targets " << targets.size() << ") ..." << std::endl; + +// RadialCoefficients c_n_zero = _radbasis->computeCoefficientsAllZero(); +// AngularCoefficients c_lm_zero = _angbasis->computeCoefficientsAllZero(); +// BasisCoefficients c_nlm(c_n_zero, c_lm_zero); +// c_nlm.linkBasis(_radbasis, _angbasis); + +// BasisExpansion *nbhood_expansion = new BasisExpansion(this->_basis); + AtomicSpectrum *atomic_spectrum = new AtomicSpectrum(center, this->_basis); + + Structure::particle_it_t pit; + for (pit = targets.begin(); pit != targets.end(); ++pit) { + + // CHECK FOR EXCLUSIONS + if (_options->doExcludeTarget((*pit)->getType())) continue; + + // FIND DISTANCE & DIRECTION, APPLY CUTOFF (= WEIGHT REDUCTION) + vec dr = _structure->connect(center->getPos(), (*pit)->getPos()); + double r = soap::linalg::abs(dr); + double weight_scale = this->_basis->getCutoff()->calculateWeight(r); + if (weight_scale < 0.) continue; // <- Negative cutoff weight means: skip + vec d = dr/r; + + // APPLY WEIGHT IF CENTER + if (*pit == center) { + weight_scale *= this->_basis->getCutoff()->getCenterWeight(); + } + + // COMPUTE EXPANSION & ADD TO SPECTRUM + BasisExpansion nb_expansion(this->_basis); + nb_expansion.computeCoefficients(r, d, weight_scale*(*pit)->getWeight(), (*pit)->getSigma()); + std::string type_other = (*pit)->getType(); + atomic_spectrum->addQnlm(type_other, nb_expansion); + +// nbhood_expansion->add(nb_expansion); + + +// // COMPUTE RADIAL COEFFICIENTS +// RadialCoefficients c_n_pair = _radbasis->computeCoefficients(r); +// /* +// GLOG() << "Radial coefficients r = " << r << std::endl; +// for (int i = 0; i < c_n.size(); ++i) { +// GLOG() << c_n[i] << " | "; +// } +// GLOG() << std::endl; +// */ +// +// // COMPUTE ANGULAR COEFFICIENTS +// AngularCoefficients c_lm_pair = _angbasis->computeCoefficients(d, r); +// /* +// GLOG() << "Angular coefficients d = " << d << std::endl; +// for (int lm = 0; lm < c_lm.size(); ++lm) { +// GLOG() << c_lm[lm] << " | "; +// } +// GLOG() << std::endl; +// */ +// +// BasisCoefficients c_nlm_pair(c_n_pair, c_lm_pair); +// c_nlm.add(c_nlm_pair); + + } + + +// c_nlm.writeDensityOnGrid("density.expanded.cube", _options, _structure, center, true); +// c_nlm.writeDensityOnGrid("density.explicit.cube", _options, _structure, center, false); + +// nbhood_expansion->writeDensityOnGrid("density.expanded.cube", _options, _structure, center, true); +// nbhood_expansion->writeDensityOnGrid("density.explicit.cube", _options, _structure, center, false); + + return atomic_spectrum; } AtomicSpectrum *Spectrum::getAtomic(int slot_idx, std::string center_type) { @@ -135,93 +231,6 @@ void Spectrum::writePowerDensity(int slot_idx, std::string center_type, std::str return; } -void Spectrum::computePower() { - atomspec_array_t::iterator it; - for (it = _atomspec_array.begin(); it != _atomspec_array.end(); ++it) { - (*it)->computePower(); - } - return; -} - -// TODO change to ::computeAtomic(Particle *center, vector<Particle*> &nbhood) -AtomicSpectrum *Spectrum::computeAtomic(Particle *center) { - GLOG() << "Compute atomic spectrum for particle " << center->getId() - << " (type " << center->getType() << ")" << std::endl; - -// RadialCoefficients c_n_zero = _radbasis->computeCoefficientsAllZero(); -// AngularCoefficients c_lm_zero = _angbasis->computeCoefficientsAllZero(); -// BasisCoefficients c_nlm(c_n_zero, c_lm_zero); -// c_nlm.linkBasis(_radbasis, _angbasis); - -// BasisExpansion *nbhood_expansion = new BasisExpansion(this->_basis); - AtomicSpectrum *atomic_spectrum = new AtomicSpectrum(center, this->_basis); - - Structure::particle_it_t pit; - for (pit = _structure->beginParticles(); pit != _structure->endParticles(); ++pit) { - - // CHECK FOR EXCLUSIONS - if (_options->doExcludeTarget((*pit)->getType())) continue; - - // FIND DISTANCE & DIRECTION, APPLY CUTOFF (= WEIGHT REDUCTION) - vec dr = _structure->connect(center->getPos(), (*pit)->getPos()); - double r = soap::linalg::abs(dr); - double weight_scale = this->_basis->getCutoff()->calculateWeight(r); - if (weight_scale < 0.) continue; // <- Negative cutoff weight means: skip - vec d = dr/r; - - // APPLY WEIGHT IF CENTER - if (*pit == center) { - weight_scale *= this->_basis->getCutoff()->getCenterWeight(); - } - - // COMPUTE EXPANSION & ADD TO SPECTRUM - BasisExpansion nb_expansion(this->_basis); - nb_expansion.computeCoefficients(r, d, weight_scale*(*pit)->getWeight(), (*pit)->getSigma()); - std::string type_other = (*pit)->getType(); - atomic_spectrum->addQnlm(type_other, nb_expansion); - -// nbhood_expansion->add(nb_expansion); - - -// // COMPUTE RADIAL COEFFICIENTS -// RadialCoefficients c_n_pair = _radbasis->computeCoefficients(r); -// /* -// GLOG() << "Radial coefficients r = " << r << std::endl; -// for (int i = 0; i < c_n.size(); ++i) { -// GLOG() << c_n[i] << " | "; -// } -// GLOG() << std::endl; -// */ -// -// // COMPUTE ANGULAR COEFFICIENTS -// AngularCoefficients c_lm_pair = _angbasis->computeCoefficients(d, r); -// /* -// GLOG() << "Angular coefficients d = " << d << std::endl; -// for (int lm = 0; lm < c_lm.size(); ++lm) { -// GLOG() << c_lm[lm] << " | "; -// } -// GLOG() << std::endl; -// */ -// -// BasisCoefficients c_nlm_pair(c_n_pair, c_lm_pair); -// c_nlm.add(c_nlm_pair); - - - } - - -// c_nlm.writeDensityOnGrid("density.expanded.cube", _options, _structure, center, true); -// c_nlm.writeDensityOnGrid("density.explicit.cube", _options, _structure, center, false); - -// nbhood_expansion->writeDensityOnGrid("density.expanded.cube", _options, _structure, center, true); -// nbhood_expansion->writeDensityOnGrid("density.explicit.cube", _options, _structure, center, false); - - - - return atomic_spectrum; -} - - void Spectrum::addAtomic(AtomicSpectrum *atomspec) { assert(atomspec->getBasis() == _basis && "Should not append atomic spectrum linked against different basis."); @@ -252,11 +261,17 @@ void Spectrum::load(std::string archfile) { void Spectrum::registerPython() { using namespace boost::python; + void (Spectrum::*computeAll)() = &Spectrum::compute; + void (Spectrum::*computeSegPair)(Segment*, Segment*) = &Spectrum::compute; + void (Spectrum::*computeCentersTargets)(Structure::particle_array_t&, Structure::particle_array_t&) = &Spectrum::compute; + class_<Spectrum>("Spectrum", init<Structure &, Options &>()) .def(init<Structure &, Options &, Basis &>()) .def(init<std::string>()) .def("__iter__", range<return_value_policy<reference_existing_object> >(&Spectrum::beginAtomic, &Spectrum::endAtomic)) - .def("compute", &Spectrum::compute) + .def("compute", computeAll) + .def("compute", computeSegPair) + .def("compute", computeCentersTargets) .def("computePower", &Spectrum::computePower) .def("addAtomic", &Spectrum::addAtomic) .def("getAtomic", &Spectrum::getAtomic, return_value_policy<reference_existing_object>()) diff --git a/src/spectrum.hpp b/src/spectrum.hpp index 0e2623cacf08944f2a183200b6d73702e0a03563..ab15986323326f573e1dff40980e1794ffd2e1ea 100644 --- a/src/spectrum.hpp +++ b/src/spectrum.hpp @@ -46,7 +46,10 @@ public: void clean(); void compute(); + void compute(Segment *centers, Segment *targets); + void compute(Structure::particle_array_t &sources, Structure::particle_array_t &targets); AtomicSpectrum *computeAtomic(Particle *center); + AtomicSpectrum *computeAtomic(Particle *center, Structure::particle_array_t &targets); void addAtomic(AtomicSpectrum *atomspec); AtomicSpectrum *getAtomic(int slot_idx, std::string center_type); void writeDensityOnGrid(int slot_idx, std::string center_type, std::string density_type); diff --git a/src/structure.cpp b/src/structure.cpp index d9f25c983adae643ebb04e301145f33a1cf52422..b0c9e6a74ff7ff53e2017f5eadce651927ddf23b 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -47,7 +47,11 @@ Particle &Segment::addParticle(Particle *new_part) { void Segment::registerPython() { using namespace boost::python; - class_<Segment>("Segment", init<int>()) + class_<Segment, Segment*>("Segment", init<int>()) + .add_property("id", &Segment::getId, &Segment::setId) + .add_property("name", make_function(&Segment::getName, copy_non_const()), &Segment::setName) + .add_property("type", make_function(&Segment::getType, copy_non_const()), &Segment::setType) + .add_property("particles", range<return_value_policy<reference_existing_object> >(&Segment::beginParticles, &Segment::endParticles)) .def("addParticle", &Segment::addParticle, return_value_policy<reference_existing_object>()); } @@ -154,14 +158,18 @@ void Structure::registerPython() { using namespace boost::python; class_<Structure>("Structure", init<std::string>()) .def("addSegment", &Structure::addSegment, return_value_policy<reference_existing_object>()) + .def("getSegment", &Structure::getSegment, return_value_policy<reference_existing_object>()) .def("addParticle", &Structure::addParticle, return_value_policy<reference_existing_object>()) .def("__iter__", range<return_value_policy<reference_existing_object> >(&Structure::beginParticles, &Structure::endParticles)) .add_property("particles", range<return_value_policy<reference_existing_object> >(&Structure::beginParticles, &Structure::endParticles)) + .add_property("segments", range<return_value_policy<reference_existing_object> >(&Structure::beginSegments, &Structure::endSegments)) .def("connect", &Structure::connectNumeric) .add_property("box", &Structure::getBoundaryNumeric, &Structure::setBoundaryNumeric) .add_property("label", make_function(&Structure::getLabel, copy_non_const()), &Structure::setLabel); class_<particle_array_t>("ParticleContainer") .def(vector_indexing_suite<particle_array_t>()); + class_<segment_array_t>("SegmentContainer") + .def(vector_indexing_suite<segment_array_t>()); } } /* CLOSE NAMESPACE */ diff --git a/src/structure.hpp b/src/structure.hpp index 2834d2caa6bce587af66fafa26d0f7497f41770c..a95b5be8245602a04ffac2f044c6651ab697a647 100644 --- a/src/structure.hpp +++ b/src/structure.hpp @@ -6,6 +6,8 @@ #include <boost/python/iterator.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> #include <iostream> + +#include "base/exceptions.hpp" #include "types.hpp" #include "boundary.hpp" @@ -49,6 +51,8 @@ public: // Sigma void setSigma(double sigma) { _sigma = sigma; } double &getSigma() { return _sigma; } + // Segment + Segment *getSegment() { return _segment; } static void registerPython(); @@ -85,24 +89,43 @@ class Segment { public: typedef std::vector<Particle*> particle_array_t; + typedef particle_array_t::iterator particle_it_t; - Segment(int id) : _id(id) { ; } - Segment() : _id(-1) { ; } + Segment(int id) : _id(id), _name("?"), _type("?") { ; } + Segment() : _id(-1), _name("?"), _type("?") { ; } ~Segment() { _particles.clear(); } + // PARTICLE CONTAINER Particle &addParticle(Particle *new_part); + particle_array_t &particles() { return _particles; } + particle_it_t beginParticles() { return _particles.begin(); } + particle_it_t endParticles() { return _particles.end(); } + + // Name + void setName(std::string name) { _name = name; } + std::string &getName() { return _name; } + // Id + void setId(int id) { _id = id; } + int getId() { return _id; } + // Type + void setType(std::string type) { _type = type; } + std::string &getType() { return _type; } static void registerPython(); template<class Archive> void serialize(Archive &arch, const unsigned int version) { arch & _id; + arch & _name; + arch & _type; arch & _particles; return; } private: int _id; + std::string _name; + std::string _type; particle_array_t _particles; }; @@ -120,10 +143,18 @@ public: ~Structure(); void null(); + // PARTICLE CONTAINER particle_array_t &particles() { return _particles; } particle_it_t beginParticles() { return _particles.begin(); } particle_it_t endParticles() { return _particles.end(); } + // SEGMENT CONTAINER + segment_array_t &segments() { return _segments; } + segment_it_t beginSegments() { return _segments.begin(); } + segment_it_t endSegments() { return _segments.end(); } + + Segment *getSegment(int id) { if (id > _segments.size()) throw soap::base::OutOfRange("getSegment"); return _segments[id-1]; } + std::string &getLabel() { return _label; } void setLabel(std::string label) { _label = label; } diff --git a/src/tools/loadwrite.py b/src/tools/loadwrite.py index 1ea6a5722377b68988f552c53f24192746442fa8..438b0fe02fc79e3b7efaaae097baa379ff1d6fd9 100644 --- a/src/tools/loadwrite.py +++ b/src/tools/loadwrite.py @@ -33,7 +33,7 @@ def ase_load_single(config_file, log=None): ase_config_list = AseConfigList([config_file], log=log) return ase_config_list[0] -def setup_structure_ase(label, ase_config): +def setup_structure_ase(label, ase_config, top=None): # DEFINE SYSTEM structure = soap.Structure(label) # DEFINE BOUNDARY @@ -45,26 +45,42 @@ def setup_structure_ase(label, ase_config): else: raise NotImplementedError("<setup_structure_ase> Partial periodicity not implemented.") structure.box = box - # CREATE SINGLE SEGMENT - segment = structure.addSegment() - # CREATE PARTICLES + # PARTICLE PROPERTIES props = ['id', 'type', 'mass', 'pos'] ids = [ i+1 for i in range(ase_config.get_number_of_atoms()) ] types = ase_config.get_atomic_numbers() positions = ase_config.get_positions() masses = ase_config.get_masses() names = ase_config.get_chemical_symbols() - for id, name, typ, pos, mass in zip(ids, names, types, positions, masses): - particle = structure.addParticle(segment) - particle.pos = pos - particle.mass = mass - particle.weight = 1. - particle.sigma = 0.5 - particle.name = name - particle.type = name - particle.type_id = typ - return structure - + # DEFAULT TOPOLOGY + if top == None: + top = [('segment', 1, len(positions))] + # VERIFY PARTICLE COUNT + atom_count = 0 + for section in top: + atom_count += section[1]*section[2] + assert atom_count == len(positions) # Does topology match structure? + # PARTITION: CREATE SEGMENTS, PARTICLES + atom_idx = 0 + for section in top: + seg_type = section[0] + n_segs = section[1] + n_atoms = section[2] + for i in range(n_segs): + segment = structure.addSegment() + segment.name = seg_type + segment.type = seg_type + for j in range(n_atoms): + particle = structure.addParticle(segment) + particle.pos = positions[atom_idx] + particle.mass = masses[atom_idx] + particle.weight = 1. + particle.sigma = 0.5 + particle.name = names[atom_idx] + particle.type = names[atom_idx] + particle.type_id = types[atom_idx] + atom_idx += 1 + return structure class AseConfigList(object): def __init__(self, diff --git a/test/test_particle_collection/pair_1_185.xyz b/test/test_particle_collection/pair_1_185.xyz new file mode 100644 index 0000000000000000000000000000000000000000..8b91ca28857ee7b2a8d1e779a355bd157c6ba8a4 --- /dev/null +++ b/test/test_particle_collection/pair_1_185.xyz @@ -0,0 +1,58 @@ + 56 + + N 31.7089747 41.3358810 86.1879144 + C 31.0963060 42.3161507 86.2185478 + N 31.3970531 45.5996138 85.1468239 + C 30.9257581 44.6682396 85.6434692 + C 30.3374277 43.5219791 86.2588437 + C 29.1051424 43.6238866 86.8452780 + H 28.6444550 44.6060930 86.7995154 + S 26.5114656 43.0332444 87.7821424 + C 28.0557940 42.5877650 87.0792750 + C 25.9764906 41.3711514 87.7813444 + C 28.1114444 41.2134848 86.8713598 + C 26.9523627 40.5322804 87.2623076 + H 28.9805352 40.7295230 86.4444793 + H 26.8266698 39.4615986 87.1706784 + S 23.9568568 39.5509530 87.2655544 + C 24.6420806 40.8717467 88.1791861 + C 22.4560907 39.6397130 88.1695727 + C 23.7445178 41.3425147 89.1269129 + C 22.5256926 40.6534842 89.1195166 + H 23.9674447 42.1589141 89.8009676 + H 21.7023754 40.8769762 89.7858237 + N 22.8727617 36.4567146 86.2629242 + C 22.0151208 37.0052059 86.8114155 + N 18.5761651 36.7452785 87.1665305 + C 19.6445382 37.1630458 87.3089482 + C 20.9614142 37.6845811 87.4894200 + C 21.1535122 38.7831753 88.2825193 + H 20.2573205 39.1962221 88.7356038 + N 19.1184299 44.4606155 84.8200553 + C 19.8203483 43.7586971 85.4132258 + N 21.9330886 43.9144593 88.1577179 + C 21.3729007 43.4590333 87.2549388 + C 20.6843079 42.8896901 86.1411975 + C 20.8756715 41.5716588 85.8265692 + H 21.5634575 41.0315692 86.4702384 + S 19.2379633 41.4329068 83.4498397 + C 20.4513290 40.9071150 84.6025371 + C 19.2139267 39.8633124 82.6852826 + C 20.7913095 39.5782930 84.3709831 + C 20.1021994 38.9935283 83.3016247 + H 21.5250027 39.0574350 84.9727855 + H 20.2449165 37.9687937 82.9852308 + S 18.6109755 38.3455761 80.4189344 + C 18.4701380 39.7438911 81.4550959 + C 17.5286776 39.0538128 79.2338359 + C 17.6279332 40.6957514 80.8982471 + C 17.1039831 40.3083420 79.6589961 + H 17.4016988 41.6397519 81.3759868 + H 16.4286554 40.9179682 79.0724356 + N 15.2367960 40.9679090 76.8556936 + C 15.6011496 39.8748479 76.9541676 + N 14.4666724 36.6838087 76.2123351 + C 15.1748066 37.5118217 76.5985657 + C 16.0545982 38.5292386 77.0776911 + C 17.2620658 38.1820877 77.6202088 + H 17.4738301 37.1174875 77.6491110 diff --git a/test/test_particle_collection/test.py b/test/test_particle_collection/test.py new file mode 100755 index 0000000000000000000000000000000000000000..5cf3488be2bc3f7c1a467210378696c38d002434 --- /dev/null +++ b/test/test_particle_collection/test.py @@ -0,0 +1,56 @@ +#! /usr/bin/env python +import soap +import soap.tools + +import os +import numpy as np +from momo import osio, endl, flush + +options = soap.Options() +options.excludeCenters(['H']) +options.excludeTargets([]) +options.set('radialbasis.type', 'gaussian') +options.set('radialbasis.mode', 'adaptive') +options.set('radialbasis.N', 9) +options.set('radialbasis.sigma', 0.9) +options.set('radialbasis.integration_steps', 15) +options.set('radialcutoff.Rc', 6.8) +options.set('radialcutoff.Rc_width', 0.5) +options.set('radialcutoff.type', 'shifted-cosine') +options.set('radialcutoff.center_weight', 1.) +options.set('angularbasis.type', 'spherical-harmonic') +options.set('angularbasis.L', 6) +options.set('densitygrid.N', 20) +options.set('densitygrid.dx', 0.15) + +# STRUCTURE +xyzfile = 'pair_1_185.xyz' +top = [('dcv2t', 2, 28)] +config = soap.tools.ase_load_single(xyzfile) +structure = soap.tools.setup_structure_ase(config.config_file, config.atoms, top) + +seg1 = structure.getSegment(1) +seg2 = structure.getSegment(2) + +print seg1.id, seg1.name +print seg2.id, seg2.name + +for particle in seg1.particles: + particle.weight = -1. + +for particle in seg2.particles: + particle.weight = +1. + +for part in structure.particles: + print part.id, part.weight + +# SPECTRUM +spectrum = soap.Spectrum(structure, options) +spectrum.compute(seg1, seg2) +spectrum.compute(seg2, seg1) +spectrum.computePower() + +spectrum.save('test.arch') +atomic = spectrum.getAtomic(1, "S") +atomic.getLinear("").writeDensityOnGrid('test.cube', options, structure, atomic.getCenter(), True) +