//////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2008 The Regents of the University of California // // This file is part of Qbox // // Qbox is distributed under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 2 of // the License, or (at your option) any later version. // See the file COPYING in the root directory of this distribution // or . // //////////////////////////////////////////////////////////////////////////////// // // AtomSet.C // //////////////////////////////////////////////////////////////////////////////// #include "AtomSet.h" #include "Species.h" #include "NameOf.h" #include "sampling.h" #include #include #include using namespace std; //////////////////////////////////////////////////////////////////////////////// AtomSet::~AtomSet(void) { for ( int is = 0; is < species_list.size(); is++ ) { for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { delete atom_list[is][ia]; } delete species_list[is]; } } //////////////////////////////////////////////////////////////////////////////// bool AtomSet::addSpecies(Species* sp, string name) { const double rcps = 1.5; sp->initialize(rcps); Species *s = findSpecies(name); if ( s != 0 ) { // species is already defined: substitute with new definition if ( ctxt_.onpe0() ) { cout << " AtomSet::addSpecies: species " << name << " is already defined" << endl; cout << " AtomSet::addSpecies: redefining species" << endl; } // Check if s and sp are compatible: zval must be equal if ( s->zval() != sp->zval() ) { cout << " AtomSet::addSpecies: species do not have the same" << " number of valence electrons. Cannot redefine species" << endl; return false; } int is = isp_[s->name()]; species_list[is] = sp; delete s; } else { // create new entry in species list species_list.push_back(sp); spname.push_back(name); isp_[name] = species_list.size()-1; na_[name] = 0; atom_list.resize(atom_list.size()+1); } if ( ctxt_.onpe0() ) { cout << endl << " species " << sp->name() << ":" << endl; sp->info(cout); } return true; } //////////////////////////////////////////////////////////////////////////////// bool AtomSet::addAtom(Atom *a) { // check atom_list for name if ( findAtom(a->name()) ) { // this name is already in the atom list, reject atom definition if ( ctxt_.onpe0() ) cout << " AtomSet:addAtom: atom " << a->name() << " is already defined" << endl; return false; } // check if species is defined string spname = a->species(); Species *s = findSpecies(spname); if ( !s ) { // species not found, cannot define atom if ( ctxt_.onpe0() ) cout << " AtomSet:addAtom: species " << spname << " is undefined" << endl; return false; } // add an atom to the atom_list int is = isp(spname); assert ( is >= 0 ); atom_list[is].push_back(a); ia_[a->name()] = atom_list[is].size()-1; is_[a->name()] = is; // update count of atoms of species spname // increment count na_[spname]++; // update total number of electrons nel_ = 0; for ( int is = 0; is < species_list.size(); is++ ) { nel_ += species_list[is]->zval() * atom_list[is].size(); } return true; } //////////////////////////////////////////////////////////////////////////////// bool AtomSet::delAtom(string name) { vector >::iterator psa = atom_list.begin(); vector::iterator ps = species_list.begin(); for ( int is = 0; is < species_list.size(); is++ ) { vector::iterator pa = atom_list[is].begin(); for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { if ( atom_list[is][ia]->name() == name ) { string spname = atom_list[is][ia]->species(); na_[spname]--; delete atom_list[is][ia]; // remove map entries ia_[name] and is_[name] map::iterator i = ia_.find(name); ia_.erase(i); i = is_.find(name); is_.erase(i); atom_list[is].erase(pa); nel_ -= species_list[is]->zval(); return true; } pa++; } psa++; ps++; } // this name was not found in the atom list if ( ctxt_.onpe0() ) cout << " AtomSet:delAtom: no such atom: " << name << endl; return false; } //////////////////////////////////////////////////////////////////////////////// Atom *AtomSet::findAtom(string name) const { for ( int is = 0; is < species_list.size(); is++ ) { for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { if ( atom_list[is][ia]->name() == name ) return atom_list[is][ia]; } } return 0; } //////////////////////////////////////////////////////////////////////////////// Species *AtomSet::findSpecies(string name) const { int is = isp(name); if ( is >= 0 ) return species_list[is]; else return 0; } //////////////////////////////////////////////////////////////////////////////// int AtomSet::isp(const string& name) const { map::const_iterator i = isp_.find(name); if ( i != isp_.end() ) return (*i).second; else return -1; } //////////////////////////////////////////////////////////////////////////////// int AtomSet::is(const string& atom_name) const { map::const_iterator i = is_.find(atom_name); if ( i != is_.end() ) return (*i).second; else return -1; } //////////////////////////////////////////////////////////////////////////////// int AtomSet::ia(const string& atom_name) const { map::const_iterator i = ia_.find(atom_name); if ( i != ia_.end() ) return (*i).second; else return -1; } //////////////////////////////////////////////////////////////////////////////// void AtomSet::listAtoms(void) const { for ( int is = 0; is < species_list.size(); is++ ) { for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { if ( ctxt_.onpe0() ) cout << *atom_list[is][ia]; } } } //////////////////////////////////////////////////////////////////////////////// void AtomSet::listSpecies(void) const { for ( int is = 0; is < species_list.size(); is++ ) { if ( ctxt_.onpe0() ) { cout << endl << " species " << spname[is] << ":" << endl; species_list[is]->info(cout); cout << endl; } } } //////////////////////////////////////////////////////////////////////////////// int AtomSet::na(const string& spname) const { map::const_iterator i = na_.find(spname); if ( i != na_.end() ) return (*i).second; else return 0; } //////////////////////////////////////////////////////////////////////////////// int AtomSet::na(int is) const { assert( is >= 0 && is < atom_list.size() ); return atom_list[is].size(); } //////////////////////////////////////////////////////////////////////////////// int AtomSet::size(void) const { int n = 0; for ( int is = 0; is < atom_list.size(); is++ ) n += atom_list[is].size(); return n; } //////////////////////////////////////////////////////////////////////////////// bool AtomSet::reset(void) { // delete all atoms and species for ( int is = 0; is < species_list.size(); is++ ) { for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { delete atom_list[is][ia]; } atom_list[is].resize(0); delete species_list[is]; } atom_list.resize(0); species_list.resize(0); spname.resize(0); for ( map::iterator i = na_.begin(); i != na_.end(); i++ ) na_.erase(i); for ( map::iterator i = isp_.begin(); i != isp_.end(); i++ ) isp_.erase(i); for ( map::iterator i = is_.begin(); i != is_.end(); i++ ) is_.erase(i); for ( map::iterator i = ia_.begin(); i != ia_.end(); i++ ) ia_.erase(i); nel_ = 0; return true; } //////////////////////////////////////////////////////////////////////////////// void AtomSet::get_positions(vector >& tau) const { if (tau.size() != atom_list.size()) tau.resize(atom_list.size()); for ( int is = 0; is < atom_list.size(); is++ ) { if (tau[is].size() != 3*atom_list[is].size()) tau[is].resize(3*atom_list[is].size()); int i = 0; for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { D3vector t = atom_list[is][ia]->position(); tau[is][i++] = t.x; tau[is][i++] = t.y; tau[is][i++] = t.z; } } } //////////////////////////////////////////////////////////////////////////////// void AtomSet::sync_positions(vector >& tau) { for ( int is = 0; is < tau.size(); is++ ) { int m = tau[is].size(); double* p = &tau[is][0]; if ( ctxt_.onpe0() ) { ctxt_.dbcast_send(m,1,p,m); } else { ctxt_.dbcast_recv(m,1,p,m,0,0); } } } //////////////////////////////////////////////////////////////////////////////// void AtomSet::set_positions(vector >& tau) { sync_positions(tau); assert(tau.size() == atom_list.size()); for ( int is = 0; is < atom_list.size(); is++ ) { assert(tau[is].size() == 3*atom_list[is].size()); for ( int ia = 0, i = 0; ia < atom_list[is].size(); ia++ ) { atom_list[is][ia]->set_position( D3vector(tau[is][i],tau[is][i+1],tau[is][i+2])); i += 3; } } } //////////////////////////////////////////////////////////////////////////////// void AtomSet::get_velocities(vector >& vel) const { if (vel.size() != atom_list.size()) vel.resize(atom_list.size()); for ( int is = 0; is < atom_list.size(); is++ ) { if (vel[is].size() != 3*atom_list[is].size()) vel[is].resize(3*atom_list[is].size()); int i = 0; for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { D3vector t = atom_list[is][ia]->velocity(); vel[is][i++] = t.x; vel[is][i++] = t.y; vel[is][i++] = t.z; } } } //////////////////////////////////////////////////////////////////////////////// void AtomSet::sync_velocities(vector >& vel) { for ( int is = 0; is < vel.size(); is++ ) { int m = vel[is].size(); double* p = &vel[is][0]; if ( ctxt_.onpe0() ) { ctxt_.dbcast_send(m,1,p,m); } else { ctxt_.dbcast_recv(m,1,p,m,0,0); } } } //////////////////////////////////////////////////////////////////////////////// void AtomSet::set_velocities(vector >& vel) { sync_velocities(vel); assert(vel.size() == atom_list.size()); for ( int is = 0; is < atom_list.size(); is++ ) { assert(vel[is].size() == 3*atom_list[is].size()); for ( int ia = 0, i = 0; ia < atom_list[is].size(); ia++ ) { atom_list[is][ia]->set_velocity( D3vector(vel[is][i],vel[is][i+1],vel[is][i+2])); i += 3; } } } //////////////////////////////////////////////////////////////////////////////// void AtomSet::reset_velocities(void) { for ( int is = 0; is < atom_list.size(); is++ ) { for ( int ia = 0; ia < atom_list[is].size(); ia++ ) atom_list[is][ia]->set_velocity(D3vector(0.0, 0.0, 0.0)); } } //////////////////////////////////////////////////////////////////////////////// void AtomSet::rescale_velocities(double fac) { vector > v; get_velocities(v); for ( int is = 0; is < v.size(); is++ ) { for ( int i = 0; i < v[is].size(); i++ ) v[is][i] *= fac; } set_velocities(v); } //////////////////////////////////////////////////////////////////////////////// void AtomSet::randomize_positions(double amplitude) { // add random displacements to positions using // random numbers from a normal distribution scaled // by the amplitude parameter vector > r; get_positions(r); for ( int is = 0; is < r.size(); is++ ) { for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { // draw pairs of unit variance gaussian random variables double xi0, xi1, xi2, xi3; // xi3 not used normal_dev(&xi0,&xi1); normal_dev(&xi2,&xi3); r[is][3*ia+0] += amplitude * xi0; r[is][3*ia+1] += amplitude * xi1; r[is][3*ia+2] += amplitude * xi2; } } set_positions(r); } //////////////////////////////////////////////////////////////////////////////// void AtomSet::randomize_velocities(double temp) { // initialize velocities with random numbers from a Maxwell-Boltzmann // distribution at temperature temp const double boltz = 1.0 / ( 11605.0 * 2.0 * 13.6058 ); vector > v; get_velocities(v); for ( int is = 0; is < v.size(); is++ ) { const double m = species_list[is]->mass() * 1822.89; const double width = sqrt( boltz * temp / m ); for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { // draw pairs of unit variance gaussian random variables double xi0, xi1, xi2, xi3; // xi3 not used normal_dev(&xi0,&xi1); normal_dev(&xi2,&xi3); v[is][3*ia+0] = width * xi0; v[is][3*ia+1] = width * xi1; v[is][3*ia+2] = width * xi2; } } set_velocities(v); reset_vcm(); } //////////////////////////////////////////////////////////////////////////////// D3vector AtomSet::vcm(void) const { D3vector mvsum; double msum = 0.0; for ( int is = 0; is < atom_list.size(); is++ ) { double mass = species_list[is]->mass(); for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { D3vector v = atom_list[is][ia]->velocity(); mvsum += mass * v; msum += mass; } } if ( msum == 0.0 ) return D3vector(0,0,0); return mvsum / msum; } //////////////////////////////////////////////////////////////////////////////// void AtomSet::reset_vcm(void) { D3vector vc = vcm(); vector > v; get_velocities(v); // subtract center of mass velocity for ( int is = 0; is < v.size(); is++ ) { int i = 0; for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { v[is][i++] -= vc.x; v[is][i++] -= vc.y; v[is][i++] -= vc.z; } } set_velocities(v); } //////////////////////////////////////////////////////////////////////////////// void AtomSet::fold_in_ws(void) { vector > p; get_positions(p); for ( int is = 0; is < p.size(); is++ ) { for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { D3vector pos(&p[is][3*ia]); cell_.fold_in_ws(pos); p[is][3*ia+0] = pos.x; p[is][3*ia+1] = pos.y; p[is][3*ia+2] = pos.z; } } set_positions(p); } //////////////////////////////////////////////////////////////////////////////// D3vector AtomSet::dipole(void) const { D3vector sum; for ( int is = 0; is < atom_list.size(); is++ ) { double charge = species_list[is]->zval(); for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { D3vector p = atom_list[is][ia]->position(); sum += charge * p; } } return sum; } //////////////////////////////////////////////////////////////////////////////// D3tensor AtomSet::quadrupole(void) const { D3tensor sum; for ( int is = 0; is < atom_list.size(); is++ ) { double charge = species_list[is]->zval(); for ( int ia = 0; ia < atom_list[is].size(); ia++ ) { D3vector p = atom_list[is][ia]->position(); for ( int idir = 0; idir < 3; idir++ ) for ( int jdir = 0; jdir < 3; jdir++ ) sum[idir*3+jdir] += charge * p[idir] * p[jdir]; } } return sum; } //////////////////////////////////////////////////////////////////////////////// void AtomSet::set_cell(const D3vector& a, const D3vector& b, const D3vector& c) { cell_.set(a,b,c); sync_cell(); } //////////////////////////////////////////////////////////////////////////////// void AtomSet::sync_cell(void) { sync_cell(cell_); } //////////////////////////////////////////////////////////////////////////////// void AtomSet::sync_cell(UnitCell& cell) { if ( ctxt_.onpe0() ) { double sbuf[9]; for ( int i = 0; i < 9; i++ ) sbuf[i] = cell.amat(i); ctxt_.dbcast_send(9,1,sbuf,9); } else { double rbuf[9]; ctxt_.dbcast_recv(9,1,rbuf,9,0,0); D3vector a0(rbuf[0],rbuf[1],rbuf[2]); D3vector a1(rbuf[3],rbuf[4],rbuf[5]); D3vector a2(rbuf[6],rbuf[7],rbuf[8]); cell.set(a0,a1,a2); } } //////////////////////////////////////////////////////////////////////////////// ostream& operator << ( ostream &os, const AtomSet &as ) { if ( as.context().onpe0() ) { os << "\n"; os << as.cell(); for ( int is = 0; is < as.species_list.size(); is++ ) { os << *as.species_list[is]; } for ( int is = 0; is < as.species_list.size(); is++ ) { for ( int ia = 0; ia < as.atom_list[is].size(); ia++ ) { os << *as.atom_list[is][ia]; } } } os << "\n"; return os; }