/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. 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 . */ /* * BreadthFirstSearchAdd.cpp * * Created on: Feb 16, 2011 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include "BreadthFirstSearchAdd.hpp" #include #include "Atom/atom.hpp" #include "Bond/bond.hpp" #include "CodePatterns/Assert.hpp" #include "CodePatterns/Info.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/Verbose.hpp" #include "molecule.hpp" #include "World.hpp" BreadthFirstSearchAdd::BreadthFirstSearchAdd(atom *&_Root, int _BondOrder, bool _IsAngstroem, const enum HydrogenSaturation _saturation) : BondOrder(_BondOrder), Root(_Root), saturation(_saturation), IsAngstroem(_IsAngstroem) { BFSStack.push_front(Root); } BreadthFirstSearchAdd::~BreadthFirstSearchAdd() {} void BreadthFirstSearchAdd::Init(atom *&_Root, int _BondOrder) { BondOrder = _BondOrder; Root = _Root; BFSStack.clear(); BFSStack.push_front(Root); } void BreadthFirstSearchAdd::InitNode(atomId_t atom_id) { PredecessorList[atom_id] = NULL; ShortestPathList[atom_id] = -1; if (AddedAtomList.find(atom_id) != AddedAtomList.end()) // mark already present atoms (i.e. Root and maybe others) as visited ColorList[atom_id] = GraphEdge::lightgray; else ColorList[atom_id] = GraphEdge::white; } void BreadthFirstSearchAdd::UnvisitedNode(molecule *Mol, atom *&Walker, atom *&OtherAtom, bond::ptr &Binder, bond::ptr &Bond) { if (Binder != Bond) // let other atom GraphEdge::white if it's via Root bond. In case it's cyclic it has to be reached again (yet Root is from OtherAtom already GraphEdge::black, thus no problem) ColorList[OtherAtom->getNr()] = GraphEdge::lightgray; PredecessorList[OtherAtom->getNr()] = Walker; // Walker is the predecessor ShortestPathList[OtherAtom->getNr()] = ShortestPathList[Walker->getNr()] + 1; LOG(2, "Coloring OtherAtom " << OtherAtom->getName() << " " << GraphEdge::getColorName(ColorList[OtherAtom->getNr()]) << ", its predecessor is " << Walker->getName() << " and its Shortest Path is " << ShortestPathList[OtherAtom->getNr()] << " egde(s) long."); if ((((ShortestPathList[OtherAtom->getNr()] < BondOrder) && (Binder != Bond)))) { // Check for maximum distance std::stringstream output; if (AddedAtomList[OtherAtom->getNr()] == NULL) { // add if it's not been so far AddedAtomList[OtherAtom->getNr()] = Mol->AddCopyAtom(OtherAtom); output << "Added OtherAtom " << OtherAtom->getName(); AddedBondList[Binder] = Mol->CopyBond(AddedAtomList[Walker->getNr()], AddedAtomList[OtherAtom->getNr()], Binder); output << " and bond " << *(AddedBondList[Binder]) << ", "; } else { // this code should actually never come into play (all GraphEdge::white atoms are not yet present in BondMolecule, that's why they are GraphEdge::white in the first place) output << "Not adding OtherAtom " << OtherAtom->getName(); if (AddedBondList[Binder] == NULL) { AddedBondList[Binder] = Mol->CopyBond(AddedAtomList[Walker->getNr()], AddedAtomList[OtherAtom->getNr()], Binder); output << ", added Bond " << *(AddedBondList[Binder]); } else output << ", not added Bond "; } output << ", putting OtherAtom into queue."; LOG(0, output.str()); BFSStack.push_front(OtherAtom); } else { // out of bond order, then replace if ((AddedAtomList[OtherAtom->getNr()] == NULL) && (Binder->Cyclic)) ColorList[OtherAtom->getNr()] = GraphEdge::white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic) { std::stringstream output; if (Binder == Bond) output << "Not Queueing, is the Root bond"; else if (ShortestPathList[OtherAtom->getNr()] >= BondOrder) output << "Not Queueing, is out of Bond Count of " << BondOrder; if (!Binder->Cyclic) output << ", is not part of a cyclic bond, saturating bond with Hydrogen."; LOG(3, output.str()); } if (AddedBondList[Binder] == NULL) { if ((AddedAtomList[OtherAtom->getNr()] != NULL)) { // .. whether we add or saturate AddedBondList[Binder] = Mol->CopyBond(AddedAtomList[Walker->getNr()], AddedAtomList[OtherAtom->getNr()], Binder); } else { if (saturation == DoSaturate) if (!Mol->AddHydrogenReplacementAtom(Binder, AddedAtomList[Walker->getNr()], Walker, OtherAtom, IsAngstroem)) exit(1); } } } } void BreadthFirstSearchAdd::VisitedNode(molecule *Mol, atom *&Walker, atom *&OtherAtom, bond::ptr &Binder, bond::ptr &Bond) { LOG(3, "Not Adding, has already been visited."); // This has to be a cyclic bond, check whether it's present ... if (AddedBondList[Binder] == NULL) { if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->getNr()] + 1) < BondOrder))) { AddedBondList[Binder] = Mol->CopyBond(AddedAtomList[Walker->getNr()], AddedAtomList[OtherAtom->getNr()], Binder); } else { // if it's root bond it has to broken (otherwise we would not create the fragments) if (saturation == DoSaturate) if(!Mol->AddHydrogenReplacementAtom(Binder, AddedAtomList[Walker->getNr()], Walker, OtherAtom, IsAngstroem)) exit(1); } } } void BreadthFirstSearchAdd::operator()(molecule *Mol, atom *_Root, bond::ptr Bond, int _BondOrder) { Info FunctionInfo("BreadthFirstSearchAdd"); atom *Walker = NULL, *OtherAtom = NULL; bond::ptr Binder; // add Root if not done yet if (AddedAtomList[_Root->getNr()] == NULL) // add Root if not yet present AddedAtomList[_Root->getNr()] = Mol->AddCopyAtom(_Root); Init(_Root, _BondOrder); // and go on ... Queue always contains all GraphEdge::lightgray vertices while (!BFSStack.empty()) { // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance. // e.g. if current atom is 2, push to end of stack are of length 3, but first all of length 2 would be popped. They again // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and // followed by n+1 till top of stack. Walker = BFSStack.front(); // pop oldest added BFSStack.pop_front(); const BondList& ListOfBonds = Walker->getListOfBonds(); LOG(1, "Current Walker is: " << Walker->getName() << ", and has " << ListOfBonds.size() << " bonds."); for (BondList::const_iterator Runner = ListOfBonds.begin(); Runner != ListOfBonds.end(); ++Runner) { if ((*Runner) != NULL) { // don't look at bond equal NULL Binder = (*Runner); OtherAtom = (*Runner)->GetOtherAtom(Walker); LOG(2, "Current OtherAtom is: " << OtherAtom->getName() << " for bond " << *(*Runner) << "."); if (ColorList[OtherAtom->getNr()] == GraphEdge::white) { UnvisitedNode(Mol, Walker, OtherAtom, Binder, Bond); } else { VisitedNode(Mol, Walker, OtherAtom, Binder, Bond); } } } ColorList[Walker->getNr()] = GraphEdge::black; LOG(1, "Coloring Walker " << Walker->getName() << " GraphEdge::black."); } }