/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * molecule_graph.cpp * * Created on: Oct 5, 2009 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include #include "atom.hpp" #include "Bond/bond.hpp" #include "Box.hpp" #include "CodePatterns/Assert.hpp" #include "CodePatterns/Info.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/Verbose.hpp" #include "config.hpp" #include "Graph/DepthFirstSearchAnalysis.hpp" #include "Element/element.hpp" #include "Graph/BondGraph.hpp" #include "Helpers/defs.hpp" #include "Helpers/helpers.hpp" #include "LinearAlgebra/RealSpaceMatrix.hpp" #include "linkedcell.hpp" #include "molecule.hpp" #include "PointCloudAdaptor.hpp" #include "World.hpp" #include "WorldTime.hpp" /** Fills the bond structure of this chain list subgraphs that are derived from a complete \a *reference molecule. * Calls this routine in each MoleculeLeafClass::next subgraph if it's not NULL. * \param *reference reference molecule with the bond structure to be copied * \param **&ListOfLocalAtoms Lookup table for this subgraph and index of each atom in \a *reference, may be NULL on start, then it is filled * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not * \return true - success, false - failure */ bool molecule::FillBondStructureFromReference(const molecule * const reference, atom **&ListOfLocalAtoms, bool FreeList) { atom *OtherWalker = NULL; atom *Father = NULL; bool status = true; int AtomNo; DoLog(1) && (Log() << Verbose(1) << "Begin of FillBondStructureFromReference." << endl); // fill ListOfLocalAtoms if NULL was given if (!FillListOfLocalAtoms(ListOfLocalAtoms, reference->getAtomCount())) { DoLog(1) && (Log() << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl); return false; } if (status) { DoLog(1) && (Log() << Verbose(1) << "Creating adjacency list for molecule " << getName() << "." << endl); // remove every bond from the list for_each(begin(), end(), boost::bind(&BondedParticle::ClearBondsAtStep,_1,WorldTime::getTime())); for(molecule::const_iterator iter = begin(); iter != end(); ++iter) { Father = (*iter)->GetTrueFather(); AtomNo = Father->getNr(); // global id of the current walker const BondList& ListOfBonds = Father->getListOfBonds(); for (BondList::const_iterator Runner = ListOfBonds.begin(); Runner != ListOfBonds.end(); ++Runner) { OtherWalker = ListOfLocalAtoms[(*Runner)->GetOtherAtom((*iter)->GetTrueFather())->getNr()]; // local copy of current bond partner of walker if (OtherWalker != NULL) { if (OtherWalker->getNr() > (*iter)->getNr()) AddBond((*iter), OtherWalker, (*Runner)->BondDegree); } else { DoLog(1) && (Log() << Verbose(1) << "OtherWalker = ListOfLocalAtoms[" << (*Runner)->GetOtherAtom((*iter)->GetTrueFather())->getNr() << "] is NULL!" << endl); status = false; } } } } if ((FreeList) && (ListOfLocalAtoms != NULL)) { // free the index lookup list delete[](ListOfLocalAtoms); } DoLog(1) && (Log() << Verbose(1) << "End of FillBondStructureFromReference." << endl); return status; }; /** Checks for presence of bonds within atom list. * TODO: more sophisticated check for bond structure (e.g. connected subgraph, ...) * \return true - bonds present, false - no bonds */ bool molecule::hasBondStructure() const { for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) { //LOG(0, "molecule::hasBondStructure() - checking bond list of atom " << (*AtomRunner)->getId() << "."); const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds(); if (!ListOfBonds.empty()) return true; } return false; } /** Prints a list of all bonds to \a *out. */ void molecule::OutputBondsList() const { DoLog(1) && (Log() << Verbose(1) << endl << "From contents of bond chain list:"); for(molecule::const_iterator AtomRunner = molecule::begin(); AtomRunner != molecule::end(); ++AtomRunner) { const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds(); for(BondList::const_iterator BondRunner = ListOfBonds.begin(); BondRunner != ListOfBonds.end(); ++BondRunner) if ((*BondRunner)->leftatom == *AtomRunner) { DoLog(0) && (Log() << Verbose(0) << *(*BondRunner) << "\t" << endl); } } DoLog(0) && (Log() << Verbose(0) << endl); } ; /** Storing the bond structure of a molecule to file. * Simply stores Atom::Nr and then the Atom::Nr of all bond partners per line. * \param &filename name of file * \param path path to file, defaults to empty * \return true - file written successfully, false - writing failed */ bool molecule::StoreAdjacencyToFile(std::string filename, std::string path) { ofstream AdjacencyFile; string line; bool status = true; if (path != "") line = path + "/" + filename; else line = filename; AdjacencyFile.open(line.c_str(), ios::out); DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl); if (AdjacencyFile.good()) { AdjacencyFile << "m\tn" << endl; for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputAdjacency),&AdjacencyFile)); AdjacencyFile.close(); DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl); } else { DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl); status = false; } return status; } ; /** Storing the bond structure of a molecule to file. * Simply stores Atom::Nr and then the Atom::Nr of all bond partners, one per line. * \param &filename name of file * \param path path to file, defaults to empty * \return true - file written successfully, false - writing failed */ bool molecule::StoreBondsToFile(std::string filename, std::string path) { ofstream BondFile; string line; bool status = true; if (path != "") line = path + "/" + filename; else line = filename; BondFile.open(line.c_str(), ios::out); DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl); if (BondFile.good()) { BondFile << "m\tn" << endl; for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputBonds),&BondFile)); BondFile.close(); DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl); } else { DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl); status = false; } return status; } ; /** Adds a bond as a copy to a given one * \param *left leftatom of new bond * \param *right rightatom of new bond * \param *CopyBond rest of fields in bond are copied from this * \return pointer to new bond */ bond * molecule::CopyBond(atom *left, atom *right, bond *CopyBond) { bond *Binder = AddBond(left, right, CopyBond->BondDegree); Binder->Cyclic = CopyBond->Cyclic; Binder->Type = CopyBond->Type; return Binder; } ; /** Fills a lookup list of father's Atom::nr -> atom for each subgraph. * \param **&ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled * \param GlobalAtomCount number of atoms in the complete molecule * \return true - success, false - failure (ListOfLocalAtoms != NULL) */ bool molecule::FillListOfLocalAtoms(atom **&ListOfLocalAtoms, const int GlobalAtomCount) { bool status = true; if (ListOfLocalAtoms == NULL) { // allocate and fill list of this fragment/subgraph status = status && CreateFatherLookupTable(ListOfLocalAtoms, GlobalAtomCount); } else return false; return status; } /** Creates a lookup table for true father's Atom::Nr -> atom ptr. * \param *start begin of list (STL iterator, i.e. first item) * \paran *end end of list (STL iterator, i.e. one past last item) * \param **Lookuptable pointer to return allocated lookup table (should be NULL on start) * \param count optional predetermined size for table (otherwise we set the count to highest true father id) * \return true - success, false - failure */ bool molecule::CreateFatherLookupTable(atom **&LookupTable, int count) { bool status = true; int AtomNo; if (LookupTable != NULL) { Log() << Verbose(0) << "Pointer for Lookup table is not NULL! Aborting ..." < atom) used as a marker table lateron count = (count < (*iter)->GetTrueFather()->getNr()) ? (*iter)->GetTrueFather()->getNr() : count; } } if (count <= 0) { Log() << Verbose(0) << "Count of lookup list is 0 or less." << endl; return false; } // allocate and fill LookupTable = new atom *[count]; if (LookupTable == NULL) { eLog() << Verbose(0) << "LookupTable memory allocation failed!" << endl; performCriticalExit(); status = false; } else { for (int i=0;iGetTrueFather()->getNr(); if ((AtomNo >= 0) && (AtomNo < count)) { //*out << "Setting LookupTable[" << AtomNo << "] to " << *(*iter) << endl; LookupTable[AtomNo] = (*iter); } else { Log() << Verbose(0) << "Walker " << *(*iter) << " exceeded range of nuclear ids [0, " << count << ")." << endl; status = false; break; } } } return status; }; /** Corrects the nuclei position if the fragment was created over the cell borders. * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction. * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically * and re-add the bond. Looping on the distance check. * \param *out ofstream for debugging messages */ bool molecule::ScanForPeriodicCorrection() { bond *Binder = NULL; //bond *OtherBinder = NULL; atom *Walker = NULL; atom *OtherWalker = NULL; RealSpaceMatrix matrix = World::getInstance().getDomain().getM(); enum GraphEdge::Shading *ColorList = NULL; double tmp; //bool LastBond = true; // only needed to due list construct Vector Translationvector; //std::deque *CompStack = NULL; std::deque *AtomStack = new std::deque; // (getAtomCount()); bool flag = true; BondGraph *BG = World::getInstance().getBondGraph(); DoLog(2) && (Log() << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl); ColorList = new enum GraphEdge::Shading[getAtomCount()]; for (int i=0;igetListOfBonds(); for(BondList::const_iterator BondRunner = ListOfBonds.begin(); (!flag) && (BondRunner != ListOfBonds.end()); ++BondRunner) { Binder = (*BondRunner); for (int i=NDIM;i--;) { tmp = fabs(Binder->leftatom->at(i) - Binder->rightatom->at(i)); //Log() << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl; const range MinMaxDistance( BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom)); if (!MinMaxDistance.isInRange(tmp)) { DoLog(2) && (Log() << Verbose(2) << "Correcting at bond " << *Binder << "." << endl); flag = true; break; } } } } //if (flag) { if (0) { // create translation vector from their periodically modified distance for (int i=NDIM;i--;) { tmp = Binder->leftatom->at(i) - Binder->rightatom->at(i); const range MinMaxDistance( BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom)); if (fabs(tmp) > MinMaxDistance.last) // check against Min is not useful for components Translationvector[i] = (tmp < 0) ? +1. : -1.; } Translationvector *= matrix; //Log() << Verbose(3) << "Translation vector is "; Log() << Verbose(0) << Translationvector << endl; // apply to all atoms of first component via BFS for (int i=getAtomCount();i--;) ColorList[i] = GraphEdge::white; AtomStack->push_front(Binder->leftatom); while (!AtomStack->empty()) { Walker = AtomStack->front(); AtomStack->pop_front(); //Log() << Verbose (3) << "Current Walker is: " << *Walker << "." << endl; ColorList[Walker->getNr()] = GraphEdge::black; // mark as explored *Walker += Translationvector; // translate const BondList& ListOfBonds = Walker->getListOfBonds(); for (BondList::const_iterator Runner = ListOfBonds.begin(); Runner != ListOfBonds.end(); ++Runner) { if ((*Runner) != Binder) { OtherWalker = (*Runner)->GetOtherAtom(Walker); if (ColorList[OtherWalker->getNr()] == GraphEdge::white) { AtomStack->push_front(OtherWalker); // push if yet unexplored } } } } // // re-add bond // if (OtherBinder == NULL) { // is the only bond? // //Do nothing // } else { // if (!LastBond) { // link(Binder, OtherBinder); // no more implemented bond::previous ... // } else { // link(OtherBinder, Binder); // no more implemented bond::previous ... // } // } } else { DoLog(3) && (Log() << Verbose(3) << "No corrections for this fragment." << endl); } //delete(CompStack); } // free allocated space from ReturnFullMatrixforSymmetric() delete(AtomStack); delete[](ColorList); DoLog(2) && (Log() << Verbose(2) << "End of ScanForPeriodicCorrection." << endl); return flag; };