/* * 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. */ /* * MoleculeLeafClass.cpp * * Created on: Oct 20, 2011 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include "MoleculeLeafClass.hpp" #include "CodePatterns/Log.hpp" #include "atom.hpp" #include "Element/element.hpp" #include "Fragmentation/Graph.hpp" #include "Fragmentation/KeySet.hpp" #include "molecule.hpp" /** Constructor for MoleculeLeafClass root leaf. * \param *Up Leaf on upper level * \param *PreviousLeaf NULL - We are the first leaf on this level, otherwise points to previous in list */ //MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *Up = NULL, MoleculeLeafClass *Previous = NULL) MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *PreviousLeaf = NULL) : Leaf(NULL), previous(PreviousLeaf) { // if (Up != NULL) // if (Up->DownLeaf == NULL) // are we the first down leaf for the upper leaf? // Up->DownLeaf = this; // UpLeaf = Up; // DownLeaf = NULL; if (previous != NULL) { MoleculeLeafClass *Walker = previous->next; previous->next = this; next = Walker; } else { next = NULL; } }; /** Destructor for MoleculeLeafClass. */ MoleculeLeafClass::~MoleculeLeafClass() { // if (DownLeaf != NULL) {// drop leaves further down // MoleculeLeafClass *Walker = DownLeaf; // MoleculeLeafClass *Next; // do { // Next = Walker->NextLeaf; // delete(Walker); // Walker = Next; // } while (Walker != NULL); // // Last Walker sets DownLeaf automatically to NULL // } // remove the leaf itself if (Leaf != NULL) { Leaf->removeAtomsinMolecule(); World::getInstance().destroyMolecule(Leaf); Leaf = NULL; } // remove this Leaf from level list if (previous != NULL) previous->next = next; // } else { // we are first in list (connects to UpLeaf->DownLeaf) // if ((NextLeaf != NULL) && (NextLeaf->UpLeaf == NULL)) // NextLeaf->UpLeaf = UpLeaf; // either null as we are top level or the upleaf of the first node // if (UpLeaf != NULL) // UpLeaf->DownLeaf = NextLeaf; // either null as we are only leaf or NextLeaf if we are just the first // } // UpLeaf = NULL; if (next != NULL) // are we last in list next->previous = previous; next = NULL; previous = NULL; }; /** Adds \a molecule leaf to the tree. * \param *ptr ptr to molecule to be added * \param *Previous previous MoleculeLeafClass referencing level and which on the level * \return true - success, false - something went wrong */ bool MoleculeLeafClass::AddLeaf(molecule *ptr, MoleculeLeafClass *Previous) { return false; }; /** Fills the root stack for sites to be used as root in fragmentation depending on order or adaptivity criteria * Again, as in \sa FillBondStructureFromReference steps recursively through each Leaf in this chain list of molecule's. * \param *out output stream for debugging * \param *&RootStack stack to be filled * \param *AtomMask defines true/false per global Atom::Nr to mask in/out each nuclear site * \param &FragmentCounter counts through the fragments in this MoleculeLeafClass * \param saturation whether to treat hydrogen special or not * \return true - stack is non-empty, fragmentation necessary, false - stack is empty, no more sites to update */ bool MoleculeLeafClass::FillRootStackForSubgraphs(KeyStack *&RootStack, bool *AtomMask, int &FragmentCounter, const enum HydrogenSaturation saturation) { atom *Father = NULL; if (RootStack != NULL) { // find first root candidates if (&(RootStack[FragmentCounter]) != NULL) { RootStack[FragmentCounter].clear(); for(molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end(); ++iter) { Father = (*iter)->GetTrueFather(); if (AtomMask[Father->getNr()]) // apply mask if ((saturation == DontSaturate) || ((*iter)->getType()->getAtomicNumber() != 1)) // skip hydrogen RootStack[FragmentCounter].push_front((*iter)->getNr()); } if (next != NULL) next->FillRootStackForSubgraphs(RootStack, AtomMask, ++FragmentCounter, saturation); } else { LOG(1, "Rootstack[" << FragmentCounter << "] is NULL."); return false; } FragmentCounter--; return true; } else { LOG(1, "Rootstack is NULL."); return false; } }; /** The indices per keyset are compared to the respective father's Atom::Nr in each subgraph and thus put into \a **&FragmentList. * \param *out output stream fro debugging * \param *reference reference molecule with the bond structure to be copied * \param *KeySetList list with all keysets * \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 **&FragmentList list to be allocated and returned * \param &FragmentCounter counts the fragments as we move along the list * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not * \retuen true - success, false - failure */ bool MoleculeLeafClass::AssignKeySetsToFragment(molecule *reference, Graph *KeySetList, atom ***&ListOfLocalAtoms, Graph **&FragmentList, int &FragmentCounter, bool FreeList) { bool status = true; int KeySetCounter = 0; LOG(1, "Begin of AssignKeySetsToFragment."); // fill ListOfLocalAtoms if NULL was given if (!Leaf->FillListOfLocalAtoms(ListOfLocalAtoms[FragmentCounter], reference->getAtomCount())) { LOG(1, "Filling of ListOfLocalAtoms failed."); return false; } // allocate fragment list if (FragmentList == NULL) { KeySetCounter = Count(); FragmentList = new Graph*[KeySetCounter]; for (int i=0;isize() != 0)) { // if there are some scanned keysets at all // assign scanned keysets if (FragmentList[FragmentCounter] == NULL) FragmentList[FragmentCounter] = new Graph; KeySet *TempSet = new KeySet; for (Graph::iterator runner = KeySetList->begin(); runner != KeySetList->end(); runner++) { // key sets contain global numbers! if (ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*((*runner).first.begin()))->getNr()] != NULL) {// as we may assume that that bond structure is unchanged, we only test the first key in each set // translate keyset to local numbers for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++) TempSet->insert(ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*sprinter)->getNr()]->getNr()); // insert into FragmentList FragmentList[FragmentCounter]->insert(GraphPair(*TempSet, pair (KeySetCounter++, (*runner).second.second))); } TempSet->clear(); } delete (TempSet); if (KeySetCounter == 0) {// if there are no keysets, delete the list LOG(1, "KeySetCounter is zero, deleting FragmentList."); delete (FragmentList[FragmentCounter]); } else LOG(1, KeySetCounter << " keysets were assigned to subgraph " << FragmentCounter << "."); FragmentCounter++; if (next != NULL) next->AssignKeySetsToFragment(reference, KeySetList, ListOfLocalAtoms, FragmentList, FragmentCounter, FreeList); FragmentCounter--; } else LOG(1, "KeySetList is NULL or empty."); if ((FreeList) && (ListOfLocalAtoms != NULL)) { // free the index lookup list delete[](ListOfLocalAtoms[FragmentCounter]); } LOG(1, "End of AssignKeySetsToFragment."); return status; }; /** Translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf) * \param *out output stream for debugging * \param **FragmentList Graph with local numbers per fragment * \param &FragmentCounter counts the fragments as we move along the list * \param &TotalNumberOfKeySets global key set counter * \param &TotalGraph Graph to be filled with global numbers */ void MoleculeLeafClass::TranslateIndicesToGlobalIDs(Graph **FragmentList, int &FragmentCounter, int &TotalNumberOfKeySets, Graph &TotalGraph) { LOG(1, "Begin of TranslateIndicesToGlobalIDs."); KeySet *TempSet = new KeySet; if (FragmentList[FragmentCounter] != NULL) { for (Graph::iterator runner = FragmentList[FragmentCounter]->begin(); runner != FragmentList[FragmentCounter]->end(); runner++) { for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++) TempSet->insert((Leaf->FindAtom(*sprinter))->GetTrueFather()->getNr()); TotalGraph.insert(GraphPair(*TempSet, pair (TotalNumberOfKeySets++, (*runner).second.second))); TempSet->clear(); } delete (TempSet); } else { LOG(1, "FragmentList is NULL."); } if (next != NULL) next->TranslateIndicesToGlobalIDs(FragmentList, ++FragmentCounter, TotalNumberOfKeySets, TotalGraph); FragmentCounter--; LOG(1, "End of TranslateIndicesToGlobalIDs."); }; /** Simply counts the number of items in the list, from given MoleculeLeafClass. * \return number of items */ int MoleculeLeafClass::Count() const { if (next != NULL) return next->Count() + 1; else return 1; };