/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * Copyright (C) 2013 Frederik Heber. All rights reserved. * * * This file is part of MoleCuilder. * * MoleCuilder is free software: you can redistribute it and/or modify * it 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. * * MoleCuilder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MoleCuilder. If not, see . */ /* * World.cpp * * Created on: Feb 3, 2010 * Author: crueger */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include "World.hpp" #include #include "Actions/ActionTrait.hpp" #include "Actions/ManipulateAtomsProcess.hpp" #include "Atom/atom.hpp" #include "Box.hpp" #include "CodePatterns/Assert.hpp" #include "config.hpp" #include "Descriptors/AtomDescriptor.hpp" #include "Descriptors/AtomDescriptor_impl.hpp" #include "Descriptors/AtomSelectionDescriptor.hpp" #include "Descriptors/MoleculeDescriptor.hpp" #include "Descriptors/MoleculeDescriptor_impl.hpp" #include "Descriptors/MoleculeSelectionDescriptor.hpp" #include "Descriptors/SelectiveConstIterator_impl.hpp" #include "Descriptors/SelectiveIterator_impl.hpp" #include "Element/periodentafel.hpp" #include "Fragmentation/Homology/HomologyContainer.hpp" #include "Graph/BondGraph.hpp" #include "Graph/DepthFirstSearchAnalysis.hpp" #include "Helpers/defs.hpp" #include "LinearAlgebra/RealSpaceMatrix.hpp" #include "LinkedCell/LinkedCell_Controller.hpp" #include "LinkedCell/PointCloudAdaptor.hpp" #include "molecule.hpp" #include "MoleculeListClass.hpp" #include "Thermostats/ThermoStatContainer.hpp" #include "WorldTime.hpp" #include "IdPool_impl.hpp" #include "CodePatterns/IteratorAdaptors.hpp" #include "CodePatterns/Singleton_impl.hpp" #include "CodePatterns/Observer/Channels.hpp" #include "CodePatterns/Observer/ObservedContainer_impl.hpp" using namespace MoleCuilder; /******************************* Notifications ************************/ atom* World::_lastchangedatom = NULL; molecule* World::_lastchangedmol = NULL; /******************************* getter and setter ************************/ periodentafel *&World::getPeriode() { return periode; } BondGraph *&World::getBondGraph() { return BG; } HomologyContainer &World::getHomologies() { return *homologies; } void World::resetHomologies(HomologyContainer *&_homologies) { HomologyContainer *oldhomologies = homologies; // install new instance, resetting given pointer homologies = _homologies; _homologies = NULL; // delete old instance which also informs all observers delete oldhomologies; } void World::setBondGraph(BondGraph *_BG){ delete (BG); BG = _BG; } config *&World::getConfig(){ return configuration; } // Atoms atom* World::getAtom(AtomDescriptor descriptor){ return descriptor.find(); } World::AtomComposite World::getAllAtoms(AtomDescriptor descriptor){ return descriptor.findAll(); } World::AtomComposite 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 RealSpaceMatrix &mat){ OBSERVE; *cell_size = mat; } void World::setDomain(double * matrix) { OBSERVE; RealSpaceMatrix M = ReturnFullMatrixforSymmetric(matrix); cell_size->setM(M); } LinkedCell::LinkedCell_View World::getLinkedCell(double distance) { ASSERT( distance >= 0, "World::getLinkedCell() - distance is not positive."); if (distance < 1.) { ELOG(2, "Linked cell grid with length less than 1. is very memory-intense!"); distance = 1.; } // we have to grope past the ObservedContainer mechanism and transmorph the map // into a traversable list for the adaptor PointCloudAdaptor< AtomSet::set_t, MapValueIterator > atomset( &(atoms.getContent()), std::string("WorldsAtoms")); return LCcontroller->getView(distance, atomset); } const unsigned World::getTime() const { return WorldTime::getTime(); } void World::setTime(const unsigned int _step) { if (_step != WorldTime::getTime()) { // set new time WorldTime::getInstance().setTime(_step); // TODO: removed when BondGraph creates the adjacency // 1. remove all of World's molecules for (MoleculeIterator iter = getMoleculeIter(); getMoleculeIter() != moleculeEnd(); iter = getMoleculeIter()) { getMolecules()->erase(*iter); destroyMolecule(*iter); } // 2. (re-)create bondgraph AtomComposite Set = getAllAtoms(); BG->CreateAdjacency(Set); // 3. scan for connected subgraphs => molecules DepthFirstSearchAnalysis DFS; DFS(); DFS.UpdateMoleculeStructure(); } } std::string World::getDefaultName() { return defaultName; } void World::setDefaultName(std::string name) { OBSERVE; 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 = moleculeIdPool.getNextId(); 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); _lastchangedmol = mol; NOTIFY(MoleculeInserted); return mol; } void World::destroyMolecule(molecule* mol){ OBSERVE; ASSERT(mol,"Molecule that was meant to be destroyed did not exist"); destroyMolecule(mol->getId()); } void World::destroyMolecule(moleculeId_t id){ molecule *mol = molecules[id]; ASSERT(mol,"Molecule id that was meant to be destroyed did not exist"); // give notice about immediate removal { OBSERVE; _lastchangedmol = mol; NOTIFY(MoleculeRemoved); } mol->signOff(this); DeleteMolecule(mol); if (isMoleculeSelected(id)) selectedMolecules.erase(id); molecules.erase(id); moleculeIdPool.releaseId(id); } atom *World::createAtom(){ OBSERVE; atomId_t id = atomIdPool.getNextId(); 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; _lastchangedatom = res; NOTIFY(AtomInserted); return res; } int World::registerAtom(atom *atom){ OBSERVE; atomId_t id = atomIdPool.getNextId(); atom->setId(id); atom->setWorld(this); atoms[atom->getId()] = atom; _lastchangedatom = atom; NOTIFY(AtomInserted); return atom->getId(); } void World::destroyAtom(atom* atom){ int id = atom->getId(); destroyAtom(id); } void World::destroyAtom(atomId_t id) { atom *atom = atoms[id]; ASSERT(atom,"Atom ID that was meant to be destroyed did not exist"); // give notice about immediate removal { OBSERVE; _lastchangedatom = atom; NOTIFY(AtomRemoved); } DeleteAtom(atom); if (isAtomSelected(id)) selectedAtoms.erase(id); atoms.erase(id); atomIdPool.releaseId(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(atomIdPool.reserveId(newId)){ atoms.erase(oldId); atoms.insert(pair(newId,target)); return true; } else{ return false; } } } bool World::changeMoleculeId(moleculeId_t oldId, moleculeId_t newId, molecule* 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 = molecules[oldId]; ASSERT(target,"Molecule with that ID not found"); return target->changeId(newId); } else{ if(moleculeIdPool.reserveId(newId)){ molecules.erase(oldId); molecules.insert(pair(newId,target)); return true; } else{ return false; } } } ManipulateAtomsProcess* World::manipulateAtoms(boost::function op,std::string name,AtomDescriptor descr){ ActionTrait manipulateTrait(name); return new ManipulateAtomsProcess(op, descr,manipulateTrait); } 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); } /******************************* Iterators ********************************/ // external parts with observers CONSTRUCT_SELECTIVE_ITERATOR(atom*,World::AtomSet,AtomDescriptor) CONSTRUCT_SELECTIVE_CONST_ITERATOR(atom*,World::AtomSet,AtomDescriptor) World::AtomIterator World::getAtomIter(AtomDescriptor descr){ return AtomIterator(descr,atoms); } World::AtomConstIterator World::getAtomIter(AtomDescriptor descr) const{ return AtomConstIterator(descr,atoms); } World::AtomIterator World::getAtomIter(){ return AtomIterator(AllAtoms(),atoms); } World::AtomConstIterator World::getAtomIter() const{ return AtomConstIterator(AllAtoms(),atoms); } World::AtomIterator World::atomEnd(){ return AtomIterator(AllAtoms(),atoms,atoms.end()); } World::AtomConstIterator World::atomEnd() const{ return AtomConstIterator(AllAtoms(),atoms,atoms.end()); } CONSTRUCT_SELECTIVE_ITERATOR(molecule*,World::MoleculeSet,MoleculeDescriptor) CONSTRUCT_SELECTIVE_CONST_ITERATOR(molecule*,World::MoleculeSet,MoleculeDescriptor) World::MoleculeIterator World::getMoleculeIter(MoleculeDescriptor descr){ return MoleculeIterator(descr,molecules); } World::MoleculeConstIterator World::getMoleculeIter(MoleculeDescriptor descr) const{ return MoleculeConstIterator(descr,molecules); } World::MoleculeIterator World::getMoleculeIter(){ return MoleculeIterator(AllMolecules(),molecules); } World::MoleculeConstIterator World::getMoleculeIter() const{ return MoleculeConstIterator(AllMolecules(),molecules); } World::MoleculeIterator World::moleculeEnd(){ return MoleculeIterator(AllMolecules(),molecules,molecules.end()); } World::MoleculeConstIterator World::moleculeEnd() const{ return MoleculeConstIterator(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(){ OBSERVE; NOTIFY(SelectionChanged); selectedAtoms.clear(); } void World::invertAtomSelection(){ // get all atoms not selected AtomComposite invertedSelection(getAllAtoms()); bool (World::*predicate)(const atom*) const = &World::isSelected; // needed for type resolution of overloaded function AtomComposite::iterator iter = std::remove_if(invertedSelection.begin(), invertedSelection.end(), std::bind1st(std::mem_fun(predicate), this)); invertedSelection.erase(iter, invertedSelection.end()); // apply new selection selectedAtoms.clear(); void (World::*selector)(const atom*) = &World::selectAtom; // needed for type resolution of overloaded function std::for_each(invertedSelection.begin(),invertedSelection.end(), std::bind1st(std::mem_fun(selector),this)); // func is select... see above } void World::selectAtom(const atom *_atom){ OBSERVE; NOTIFY(SelectionChanged); // atom * is unchanged in this function, but we do store entity as changeable ASSERT(_atom,"Invalid pointer in selection of atom"); selectedAtoms[_atom->getId()]=const_cast(_atom); } void World::selectAtom(const atomId_t id){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(atoms.count(id),"Atom Id selected that was not in the world"); selectedAtoms[id]=atoms[id]; } void World::selectAllAtoms(AtomDescriptor descr){ OBSERVE; NOTIFY(SelectionChanged); internal_AtomIterator begin = getAtomIter_internal(descr); internal_AtomIterator end = atomEnd_internal(); void (World::*func)(const 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(const molecule *_mol){ OBSERVE; NOTIFY(SelectionChanged); 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)(const 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(const moleculeId_t id){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(molecules.count(id),"No molecule with the given id upon Selection of atoms from molecule"); selectAtomsOfMolecule(molecules[id]); } void World::unselectAtom(const atom *_atom){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(_atom,"Invalid pointer in unselection of atom"); unselectAtom(_atom->getId()); } void World::unselectAtom(const atomId_t id){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(atoms.count(id),"Atom Id unselected that was not in the world"); selectedAtoms.erase(id); } void World::unselectAllAtoms(AtomDescriptor descr){ OBSERVE; NOTIFY(SelectionChanged); internal_AtomIterator begin = getAtomIter_internal(descr); internal_AtomIterator end = atomEnd_internal(); void (World::*func)(const 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(const molecule *_mol){ OBSERVE; NOTIFY(SelectionChanged); 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)(const atom*) = &World::unselectAtom; // needed for type resolution of overloaded function for_each(mol->begin(),mol->end(),bind1st(mem_fun(func),this)); // func is unselect... see above } void World::unselectAtomsOfMolecule(const moleculeId_t id){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(molecules.count(id),"No molecule with the given id upon Selection of atoms from molecule"); unselectAtomsOfMolecule(molecules[id]); } size_t World::countSelectedAtoms() const { size_t count = 0; for (AtomSet::const_iterator iter = selectedAtoms.begin(); iter != selectedAtoms.end(); ++iter) count++; return count; } bool World::isSelected(const atom *_atom) const { return isAtomSelected(_atom->getId()); } bool World::isAtomSelected(const atomId_t no) const { return selectedAtoms.find(no) != selectedAtoms.end(); } const std::vector World::getSelectedAtoms() const { std::vector returnAtoms; returnAtoms.resize(countSelectedAtoms()); int count = 0; for (AtomSet::const_iterator iter = selectedAtoms.begin(); iter != selectedAtoms.end(); ++iter) returnAtoms[count++] = iter->second; return returnAtoms; } // Molecules void World::clearMoleculeSelection(){ OBSERVE; NOTIFY(SelectionChanged); selectedMolecules.clear(); } void World::invertMoleculeSelection(){ // get all molecules not selected typedef std::vector MoleculeVector_t; MoleculeVector_t invertedSelection(getAllMolecules()); bool (World::*predicate)(const molecule*) const = &World::isSelected; // needed for type resolution of overloaded function MoleculeVector_t::iterator iter = std::remove_if(invertedSelection.begin(), invertedSelection.end(), std::bind1st(std::mem_fun(predicate), this)); invertedSelection.erase(iter, invertedSelection.end()); // apply new selection selectedMolecules.clear(); void (World::*selector)(const molecule*) = &World::selectMolecule; // needed for type resolution of overloaded function std::for_each(invertedSelection.begin(),invertedSelection.end(), std::bind1st(std::mem_fun(selector),this)); // func is select... see above } void World::selectMolecule(const molecule *_mol){ OBSERVE; NOTIFY(SelectionChanged); // molecule * is unchanged in this function, but we do store entity as changeable ASSERT(_mol,"Invalid pointer to molecule in selection"); selectedMolecules[_mol->getId()]=const_cast(_mol); } void World::selectMolecule(const moleculeId_t id){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(molecules.count(id),"Molecule Id selected that was not in the world"); selectedMolecules[id]=molecules[id]; } void World::selectAllMolecules(MoleculeDescriptor descr){ OBSERVE; NOTIFY(SelectionChanged); internal_MoleculeIterator begin = getMoleculeIter_internal(descr); internal_MoleculeIterator end = moleculeEnd_internal(); void (World::*func)(const 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(const atom *_atom){ OBSERVE; NOTIFY(SelectionChanged); 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(const atomId_t id){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(atoms.count(id),"No such atom with given ID in selection of Molecules of Atom");\ selectMoleculeOfAtom(atoms[id]); } void World::unselectMolecule(const molecule *_mol){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(_mol,"invalid pointer in unselection of molecule"); unselectMolecule(_mol->getId()); } void World::unselectMolecule(const moleculeId_t id){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(molecules.count(id),"No such molecule with ID in unselection"); selectedMolecules.erase(id); } void World::unselectAllMolecules(MoleculeDescriptor descr){ OBSERVE; NOTIFY(SelectionChanged); internal_MoleculeIterator begin = getMoleculeIter_internal(descr); internal_MoleculeIterator end = moleculeEnd_internal(); void (World::*func)(const 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(const atom *_atom){ OBSERVE; NOTIFY(SelectionChanged); 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(const atomId_t id){ OBSERVE; NOTIFY(SelectionChanged); ASSERT(atoms.count(id),"No such atom with given ID in selection of Molecules of Atom");\ unselectMoleculeOfAtom(atoms[id]); } size_t World::countSelectedMolecules() const { size_t count = 0; for (MoleculeSet::const_iterator iter = selectedMolecules.begin(); iter != selectedMolecules.end(); ++iter) count++; return count; } bool World::isSelected(const molecule *_mol) const { return isMoleculeSelected(_mol->getId()); } bool World::isMoleculeSelected(const moleculeId_t no) const { return selectedMolecules.find(no) != selectedMolecules.end(); } const std::vector World::getSelectedMolecules() const { std::vector returnMolecules; returnMolecules.resize(countSelectedMolecules()); int count = 0; for (MoleculeSet::const_iterator iter = selectedMolecules.begin(); iter != selectedMolecules.end(); ++iter) returnMolecules[count++] = iter->second; return returnMolecules; } /******************* Iterators over Selection *****************************/ World::AtomSelectionIterator World::beginAtomSelection(){ return selectedAtoms.begin(); } World::AtomSelectionIterator World::endAtomSelection(){ return selectedAtoms.end(); } World::AtomSelectionConstIterator World::beginAtomSelection() const{ return selectedAtoms.begin(); } World::AtomSelectionConstIterator World::endAtomSelection() const{ return selectedAtoms.end(); } World::MoleculeSelectionIterator World::beginMoleculeSelection(){ return selectedMolecules.begin(); } World::MoleculeSelectionIterator World::endMoleculeSelection(){ return selectedMolecules.end(); } World::MoleculeSelectionConstIterator World::beginMoleculeSelection() const{ return selectedMolecules.begin(); } World::MoleculeSelectionConstIterator World::endMoleculeSelection() const{ return selectedMolecules.end(); } /******************************* Singleton Stuff **************************/ World::World() : Observable("World"), BG(new BondGraph(true)), // assume Angstroem for the moment periode(new periodentafel(true)), configuration(new config), homologies(new HomologyContainer()), Thermostats(new ThermoStatContainer), ExitFlag(0), atoms(this), selectedAtoms(this), atomIdPool(0, 20, 100), molecules(this), selectedMolecules(this), moleculeIdPool(0, 20,100), molecules_deprecated(new MoleculeListClass(this)) { cell_size = new Box; RealSpaceMatrix domain; domain.at(0,0) = 20; domain.at(1,1) = 20; domain.at(2,2) = 20; cell_size->setM(domain); LCcontroller = new LinkedCell::LinkedCell_Controller(*cell_size); defaultName = "none"; Channels *OurChannel = new Channels; NotificationChannels.insert( std::make_pair( static_cast(this), OurChannel) ); for (size_t type = 0; type < (size_t)NotificationType_MAX; ++type) OurChannel->addChannel(type); molecules_deprecated->signOn(this); } World::~World() { molecules_deprecated->signOff(this); delete LCcontroller; delete cell_size; delete molecules_deprecated; 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(); delete BG; delete periode; delete configuration; delete Thermostats; } // Explicit instantiation of the singleton mechanism at this point // moleculeId_t und atomId_t sind gleicher Basistyp, deswegen nur einen von beiden konstruieren CONSTRUCT_IDPOOL(atomId_t, uniqueId) CONSTRUCT_IDPOOL(moleculeId_t, continuousId) CONSTRUCT_SINGLETON(World) CONSTRUCT_OBSERVEDCONTAINER(World::AtomSTLSet) CONSTRUCT_OBSERVEDCONTAINER(World::MoleculeSTLSet) /******************************* deprecated Legacy Stuff ***********************/ MoleculeListClass *&World::getMolecules() { return molecules_deprecated; }