/* * World.cpp * * Created on: Feb 3, 2010 * Author: crueger */ #include "Helpers/MemDebug.hpp" #include "World.hpp" #include #include "atom.hpp" #include "config.hpp" #include "molecule.hpp" #include "periodentafel.hpp" #include "ThermoStatContainer.hpp" #include "Descriptors/AtomDescriptor.hpp" #include "Descriptors/AtomDescriptor_impl.hpp" #include "Descriptors/MoleculeDescriptor.hpp" #include "Descriptors/MoleculeDescriptor_impl.hpp" #include "Descriptors/SelectiveIterator_impl.hpp" #include "Actions/ManipulateAtomsProcess.hpp" #include "Helpers/Assert.hpp" #include "Box.hpp" #include "Matrix.hpp" #include "defs.hpp" #include "Patterns/Singleton_impl.hpp" #include "Patterns/ObservedContainer_impl.hpp" using namespace std; /******************************* getter and setter ************************/ periodentafel *&World::getPeriode(){ return periode; } config *&World::getConfig(){ return configuration; } // Atoms atom* World::getAtom(AtomDescriptor descriptor){ return descriptor.find(); } vector World::getAllAtoms(AtomDescriptor descriptor){ return descriptor.findAll(); } vector World::getAllAtoms(){ return getAllAtoms(AllAtoms()); } int World::numAtoms(){ return atoms.size(); } // Molecules molecule *World::getMolecule(MoleculeDescriptor descriptor){ return descriptor.find(); } std::vector World::getAllMolecules(MoleculeDescriptor descriptor){ return descriptor.findAll(); } std::vector World::getAllMolecules(){ return getAllMolecules(AllMolecules()); } int World::numMolecules(){ return molecules_deprecated->ListOfMolecules.size(); } // system Box& World::getDomain() { return *cell_size; } void World::setDomain(const Matrix &mat){ *cell_size = mat; } void World::setDomain(double * matrix) { Matrix M = ReturnFullMatrixforSymmetric(matrix); cell_size->setM(M); } std::string World::getDefaultName() { return defaultName; } void World::setDefaultName(std::string name) { defaultName = name; }; class ThermoStatContainer * World::getThermostats() { return Thermostats; } int World::getExitFlag() { return ExitFlag; } void World::setExitFlag(int flag) { if (ExitFlag < flag) ExitFlag = flag; } /******************** Methods to change World state *********************/ molecule* World::createMolecule(){ OBSERVE; molecule *mol = NULL; mol = NewMolecule(); moleculeId_t id = getNextMoleculeId(); ASSERT(!molecules.count(id),"proposed id did not specify an unused ID"); mol->setId(id); // store the molecule by ID molecules[mol->getId()] = mol; mol->signOn(this); return mol; } void World::destroyMolecule(molecule* mol){ OBSERVE; destroyMolecule(mol->getId()); } void World::destroyMolecule(moleculeId_t id){ OBSERVE; molecule *mol = molecules[id]; ASSERT(mol,"Molecule id that was meant to be destroyed did not exist"); DeleteMolecule(mol); molecules.erase(id); releaseMoleculeId(id); } atom *World::createAtom(){ OBSERVE; atomId_t id = getNextAtomId(); ASSERT(!atoms.count(id),"proposed id did not specify an unused ID"); atom *res = NewAtom(id); res->setWorld(this); // store the atom by ID atoms[res->getId()] = res; return res; } int World::registerAtom(atom *atom){ OBSERVE; atomId_t id = getNextAtomId(); atom->setId(id); atom->setWorld(this); atoms[atom->getId()] = atom; return atom->getId(); } void World::destroyAtom(atom* atom){ OBSERVE; int id = atom->getId(); destroyAtom(id); } void World::destroyAtom(atomId_t id) { OBSERVE; atom *atom = atoms[id]; ASSERT(atom,"Atom ID that was meant to be destroyed did not exist"); DeleteAtom(atom); atoms.erase(id); releaseAtomId(id); } bool World::changeAtomId(atomId_t oldId, atomId_t newId, atom* target){ OBSERVE; // in case this call did not originate from inside the atom, we redirect it, // to also let it know that it has changed if(!target){ target = atoms[oldId]; ASSERT(target,"Atom with that ID not found"); return target->changeId(newId); } else{ if(reserveAtomId(newId)){ atoms.erase(oldId); atoms.insert(pair(newId,target)); return true; } else{ return false; } } } ManipulateAtomsProcess* World::manipulateAtoms(boost::function op,std::string name,AtomDescriptor descr){ return new ManipulateAtomsProcess(op, descr,name,true); } ManipulateAtomsProcess* World::manipulateAtoms(boost::function op,std::string name){ return manipulateAtoms(op,name,AllAtoms()); } /********************* Internal Change methods for double Callback and Observer mechanism ********/ void World::doManipulate(ManipulateAtomsProcess *proc){ proc->signOn(this); { OBSERVE; proc->doManipulate(this); } proc->signOff(this); } /******************************* IDManagement *****************************/ // Atoms atomId_t World::getNextAtomId(){ // try to find an Id in the pool; if(!atomIdPool.empty()){ atomIdPool_t::iterator iter=atomIdPool.begin(); atomId_t id = iter->first; pair newRange = make_pair(id+1,iter->second); // we wont use this iterator anymore, so we don't care about invalidating atomIdPool.erase(iter); if(newRange.first=currAtomId ){ pair newRange = make_pair(currAtomId,id); if(newRange.firstfirst>id){ // we have coverd all available ranges... nothing to be found here break; } // no need to check first, since it has to be <=id, since otherwise we would have broken out if(iter->second > id){ // we found a matching range... get the id from this range // split up this range at the point of id pair bottomRange = make_pair(iter->first,id); pair topRange = make_pair(id+1,iter->second); // remove this range atomIdPool.erase(iter); if(bottomRange.firstfirst==iter->second)){ // merge the two ranges pair newRange = make_pair(iter->first,next->second); atomIdPool.erase(iter); atomIdPool.erase(next); pair res = atomIdPool.insert(newRange); ASSERT(res.second,"Id-Pool was confused"); iter=res.first; continue; } ++iter; } if(!atomIdPool.empty()){ // check if the last range is at the border atomIdPool_t::iterator iter = atomIdPool.end(); iter--; if(iter->second==currAtomId){ currAtomId=iter->first; atomIdPool.erase(iter); } } lastAtomPoolSize=atomIdPool.size(); numAtomDefragSkips=0; } // Molecules moleculeId_t World::getNextMoleculeId(){ // try to find an Id in the pool; if(!moleculeIdPool.empty()){ moleculeIdPool_t::iterator iter=moleculeIdPool.begin(); moleculeId_t id = iter->first; pair newRange = make_pair(id+1,iter->second); // we wont use this iterator anymore, so we don't care about invalidating moleculeIdPool.erase(iter); if(newRange.first=currMoleculeId ){ pair newRange = make_pair(currMoleculeId,id); if(newRange.firstfirst>id){ // we have coverd all available ranges... nothing to be found here break; } // no need to check first, since it has to be <=id, since otherwise we would have broken out if(iter->second > id){ // we found a matching range... get the id from this range // split up this range at the point of id pair bottomRange = make_pair(iter->first,id); pair topRange = make_pair(id+1,iter->second); // remove this range moleculeIdPool.erase(iter); if(bottomRange.firstfirst==iter->second)){ // merge the two ranges pair newRange = make_pair(iter->first,next->second); moleculeIdPool.erase(iter); moleculeIdPool.erase(next); pair res = moleculeIdPool.insert(newRange); ASSERT(res.second,"Id-Pool was confused"); iter=res.first; continue; } ++iter; } if(!moleculeIdPool.empty()){ // check if the last range is at the border moleculeIdPool_t::iterator iter = moleculeIdPool.end(); iter--; if(iter->second==currMoleculeId){ currMoleculeId=iter->first; moleculeIdPool.erase(iter); } } lastMoleculePoolSize=moleculeIdPool.size(); numMoleculeDefragSkips=0; } /******************************* Iterators ********************************/ // external parts with observers CONSTRUCT_SELECTIVE_ITERATOR(atom*,World::AtomSet,AtomDescriptor); World::AtomIterator World::getAtomIter(AtomDescriptor descr){ return AtomIterator(descr,atoms); } World::AtomIterator World::getAtomIter(){ return AtomIterator(AllAtoms(),atoms); } World::AtomIterator World::atomEnd(){ return AtomIterator(AllAtoms(),atoms,atoms.end()); } CONSTRUCT_SELECTIVE_ITERATOR(molecule*,World::MoleculeSet,MoleculeDescriptor); World::MoleculeIterator World::getMoleculeIter(MoleculeDescriptor descr){ return MoleculeIterator(descr,molecules); } World::MoleculeIterator World::getMoleculeIter(){ return MoleculeIterator(AllMolecules(),molecules); } World::MoleculeIterator World::moleculeEnd(){ return MoleculeIterator(AllMolecules(),molecules,molecules.end()); } // Internal parts, without observers // Build the AtomIterator from template CONSTRUCT_SELECTIVE_ITERATOR(atom*,World::AtomSet::set_t,AtomDescriptor); World::internal_AtomIterator World::getAtomIter_internal(AtomDescriptor descr){ return internal_AtomIterator(descr,atoms.getContent()); } World::internal_AtomIterator World::atomEnd_internal(){ return internal_AtomIterator(AllAtoms(),atoms.getContent(),atoms.end_internal()); } // build the MoleculeIterator from template CONSTRUCT_SELECTIVE_ITERATOR(molecule*,World::MoleculeSet::set_t,MoleculeDescriptor); World::internal_MoleculeIterator World::getMoleculeIter_internal(MoleculeDescriptor descr){ return internal_MoleculeIterator(descr,molecules.getContent()); } World::internal_MoleculeIterator World::moleculeEnd_internal(){ return internal_MoleculeIterator(AllMolecules(),molecules.getContent(),molecules.end_internal()); } /************************** Selection of Atoms and molecules ******************/ // Atoms void World::clearAtomSelection(){ selectedAtoms.clear(); } void World::selectAtom(atom *atom){ ASSERT(atom,"Invalid pointer in selection of atom"); selectedAtoms[atom->getId()]=atom; } void World::selectAtom(atomId_t id){ ASSERT(atoms.count(id),"Atom Id selected that was not in the world"); selectedAtoms[id]=atoms[id]; } void World::selectAllAtoms(AtomDescriptor descr){ internal_AtomIterator begin = getAtomIter_internal(descr); internal_AtomIterator end = atomEnd_internal(); void (World::*func)(atom*) = &World::selectAtom; // needed for type resolution of overloaded function for_each(begin,end,bind1st(mem_fun(func),this)); // func is select... see above } void World::selectAtomsOfMolecule(molecule *_mol){ ASSERT(_mol,"Invalid pointer to molecule in selection of Atoms of Molecule"); // need to make it const to get the fast iterators const molecule *mol = _mol; void (World::*func)(atom*) = &World::selectAtom; // needed for type resolution of overloaded function for_each(mol->begin(),mol->end(),bind1st(mem_fun(func),this)); // func is select... see above } void World::selectAtomsOfMolecule(moleculeId_t id){ ASSERT(molecules.count(id),"No molecule with the given id upon Selection of atoms from molecule"); selectAtomsOfMolecule(molecules[id]); } void World::unselectAtom(atom *atom){ ASSERT(atom,"Invalid pointer in unselection of atom"); unselectAtom(atom->getId()); } void World::unselectAtom(atomId_t id){ ASSERT(atoms.count(id),"Atom Id unselected that was not in the world"); selectedAtoms.erase(id); } void World::unselectAllAtoms(AtomDescriptor descr){ internal_AtomIterator begin = getAtomIter_internal(descr); internal_AtomIterator end = atomEnd_internal(); void (World::*func)(atom*) = &World::unselectAtom; // needed for type resolution of overloaded function for_each(begin,end,bind1st(mem_fun(func),this)); // func is unselect... see above } void World::unselectAtomsOfMolecule(molecule *_mol){ ASSERT(_mol,"Invalid pointer to molecule in selection of Atoms of Molecule"); // need to make it const to get the fast iterators const molecule *mol = _mol; void (World::*func)(atom*) = &World::unselectAtom; // needed for type resolution of overloaded function for_each(mol->begin(),mol->end(),bind1st(mem_fun(func),this)); // func is unsselect... see above } void World::unselectAtomsOfMolecule(moleculeId_t id){ ASSERT(molecules.count(id),"No molecule with the given id upon Selection of atoms from molecule"); unselectAtomsOfMolecule(molecules[id]); } // Molecules void World::clearMoleculeSelection(){ selectedMolecules.clear(); } void World::selectMolecule(molecule *mol){ ASSERT(mol,"Invalid pointer to molecule in selection"); selectedMolecules[mol->getId()]=mol; } void World::selectMolecule(moleculeId_t id){ ASSERT(molecules.count(id),"Molecule Id selected that was not in the world"); selectedMolecules[id]=molecules[id]; } void World::selectAllMoleculess(MoleculeDescriptor descr){ internal_MoleculeIterator begin = getMoleculeIter_internal(descr); internal_MoleculeIterator end = moleculeEnd_internal(); void (World::*func)(molecule*) = &World::selectMolecule; // needed for type resolution of overloaded function for_each(begin,end,bind1st(mem_fun(func),this)); // func is select... see above } void World::selectMoleculeOfAtom(atom *atom){ ASSERT(atom,"Invalid atom pointer in selection of MoleculeOfAtom"); molecule *mol=atom->getMolecule(); // the atom might not be part of a molecule if(mol){ selectMolecule(mol); } } void World::selectMoleculeOfAtom(atomId_t id){ ASSERT(atoms.count(id),"No such atom with given ID in selection of Molecules of Atom");\ selectMoleculeOfAtom(atoms[id]); } void World::unselectMolecule(molecule *mol){ ASSERT(mol,"invalid pointer in unselection of molecule"); unselectMolecule(mol->getId()); } void World::unselectMolecule(moleculeId_t id){ ASSERT(molecules.count(id),"No such molecule with ID in unselection"); selectedMolecules.erase(id); } void World::unselectAllMoleculess(MoleculeDescriptor descr){ internal_MoleculeIterator begin = getMoleculeIter_internal(descr); internal_MoleculeIterator end = moleculeEnd_internal(); void (World::*func)(molecule*) = &World::unselectMolecule; // needed for type resolution of overloaded function for_each(begin,end,bind1st(mem_fun(func),this)); // func is unselect... see above } void World::unselectMoleculeOfAtom(atom *atom){ ASSERT(atom,"Invalid atom pointer in selection of MoleculeOfAtom"); molecule *mol=atom->getMolecule(); // the atom might not be part of a molecule if(mol){ unselectMolecule(mol); } } void World::unselectMoleculeOfAtom(atomId_t id){ ASSERT(atoms.count(id),"No such atom with given ID in selection of Molecules of Atom");\ unselectMoleculeOfAtom(atoms[id]); } /******************* Iterators over Selection *****************************/ World::AtomSelectionIterator World::beginAtomSelection(){ return selectedAtoms.begin(); } World::AtomSelectionIterator World::endAtomSelection(){ return selectedAtoms.end(); } World::MoleculeSelectionIterator World::beginMoleculeSelection(){ return selectedMolecules.begin(); } World::MoleculeSelectionIterator World::endMoleculeSelection(){ return selectedMolecules.end(); } /******************************* Singleton Stuff **************************/ World::World() : Observable("World"), periode(new periodentafel), configuration(new config), Thermostats(new ThermoStatContainer), ExitFlag(0), atoms(this), selectedAtoms(this), currAtomId(0), lastAtomPoolSize(0), numAtomDefragSkips(0), molecules(this), selectedMolecules(this), currMoleculeId(0), molecules_deprecated(new MoleculeListClass(this)) { cell_size = new Box; Matrix domain; domain.at(0,0) = 20; domain.at(1,1) = 20; domain.at(2,2) = 20; cell_size->setM(domain); defaultName = "none"; molecules_deprecated->signOn(this); } World::~World() { molecules_deprecated->signOff(this); delete cell_size; delete molecules_deprecated; delete periode; delete configuration; delete Thermostats; MoleculeSet::iterator molIter; for(molIter=molecules.begin();molIter!=molecules.end();++molIter){ DeleteMolecule((*molIter).second); } molecules.clear(); AtomSet::iterator atIter; for(atIter=atoms.begin();atIter!=atoms.end();++atIter){ DeleteAtom((*atIter).second); } atoms.clear(); } // Explicit instantiation of the singleton mechanism at this point CONSTRUCT_SINGLETON(World) /******************************* deprecated Legacy Stuff ***********************/ MoleculeListClass *&World::getMolecules() { return molecules_deprecated; }