Changes in src/molecule_graph.cpp [f66195:99593f]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/molecule_graph.cpp
rf66195 r99593f 8 8 #include "atom.hpp" 9 9 #include "bond.hpp" 10 #include "bondgraph.hpp" 10 11 #include "config.hpp" 11 12 #include "element.hpp" 12 13 #include "helpers.hpp" 14 #include "linkedcell.hpp" 13 15 #include "lists.hpp" 14 16 #include "memoryallocator.hpp" 15 17 #include "molecule.hpp" 16 18 19 struct BFSAccounting 20 { 21 atom **PredecessorList; 22 int *ShortestPathList; 23 enum Shading *ColorList; 24 class StackClass<atom *> *BFSStack; 25 class StackClass<atom *> *TouchedStack; 26 int AtomCount; 27 int BondOrder; 28 atom *Root; 29 bool BackStepping; 30 int CurrentGraphNr; 31 int ComponentNr; 32 }; 33 34 /** Accounting data for Depth First Search. 35 */ 36 struct DFSAccounting 37 { 38 class StackClass<atom *> *AtomStack; 39 class StackClass<bond *> *BackEdgeStack; 40 int CurrentGraphNr; 41 int ComponentNumber; 42 atom *Root; 43 bool BackStepping; 44 }; 45 17 46 /************************************* Functions for class molecule *********************************/ 18 19 47 20 48 /** Creates an adjacency list of the molecule. 21 49 * We obtain an outside file with the indices of atoms which are bondmembers. 22 50 */ 23 void molecule::CreateAdjacencyList 2(ofstream *out, ifstream *input)51 void molecule::CreateAdjacencyListFromDbondFile(ofstream *out, ifstream *input) 24 52 { 25 53 26 54 // 1 We will parse bonds out of the dbond file created by tremolo. 27 int atom1, atom2, temp; 28 atom *Walker, *OtherWalker; 29 30 if (!input) 31 { 32 cout << Verbose(1) << "Opening silica failed \n"; 33 }; 34 35 *input >> ws >> atom1; 36 *input >> ws >> atom2; 37 cout << Verbose(1) << "Scanning file\n"; 38 while (!input->eof()) // Check whether we read everything already 39 { 40 *input >> ws >> atom1; 41 *input >> ws >> atom2; 42 if(atom2<atom1) //Sort indices of atoms in order 43 { 44 temp=atom1; 45 atom1=atom2; 46 atom2=temp; 47 }; 48 49 Walker=start; 50 while(Walker-> nr != atom1) // Find atom corresponding to first index 51 { 52 Walker = Walker->next; 53 }; 54 OtherWalker = Walker->next; 55 while(OtherWalker->nr != atom2) // Find atom corresponding to second index 56 { 57 OtherWalker= OtherWalker->next; 58 }; 59 AddBond(Walker, OtherWalker); //Add the bond between the two atoms with respective indices. 60 61 } 62 63 CreateListOfBondsPerAtom(out); 64 65 }; 66 55 int atom1, atom2; 56 atom *Walker, *OtherWalker; 57 58 if (!input) { 59 cout << Verbose(1) << "Opening silica failed \n"; 60 }; 61 62 *input >> ws >> atom1; 63 *input >> ws >> atom2; 64 cout << Verbose(1) << "Scanning file\n"; 65 while (!input->eof()) // Check whether we read everything already 66 { 67 *input >> ws >> atom1; 68 *input >> ws >> atom2; 69 70 if (atom2 < atom1) //Sort indices of atoms in order 71 flip(atom1, atom2); 72 Walker = FindAtom(atom1); 73 OtherWalker = FindAtom(atom2); 74 AddBond(Walker, OtherWalker); //Add the bond between the two atoms with respective indices. 75 } 76 } 77 ; 67 78 68 79 /** Creates an adjacency list of the molecule. … … 77 88 * -# put each atom into its corresponding cell 78 89 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true 79 * -# create the list of bonds via CreateListOfBondsPerAtom()80 90 * -# correct the bond degree iteratively (single->double->triple bond) 81 91 * -# finally print the bond list to \a *out if desired … … 83 93 * \param bonddistance length of linked cells (i.e. maximum minimal length checked) 84 94 * \param IsAngstroem whether coordinate system is gauged to Angstroem or Bohr radii 85 */ 86 void molecule::CreateAdjacencyList(ofstream *out, double bonddistance, bool IsAngstroem) 87 { 88 89 atom *Walker = NULL, *OtherWalker = NULL, *Candidate = NULL; 90 int No, NoBonds, CandidateBondNo; 91 int NumberCells, divisor[NDIM], n[NDIM], N[NDIM], index, Index, j; 92 molecule **CellList; 93 double distance, MinDistance, MaxDistance; 94 double *matrix = ReturnFullMatrixforSymmetric(cell_size); 95 Vector x; 96 int FalseBondDegree = 0; 95 * \param *minmaxdistance function to give upper and lower bound on whether particle is bonded to some other 96 * \param *BG BondGraph with the member function above or NULL, if just standard covalent should be used. 97 */ 98 void molecule::CreateAdjacencyList(ofstream *out, double bonddistance, bool IsAngstroem, void (BondGraph::*minmaxdistance)(BondedParticle * const , BondedParticle * const , double &, double &, bool), BondGraph *BG) 99 { 100 atom *Walker = NULL; 101 atom *OtherWalker = NULL; 102 atom **AtomMap = NULL; 103 int n[NDIM]; 104 double MinDistance, MaxDistance; 105 LinkedCell *LC = NULL; 106 bool free_BG = false; 107 108 if (BG == NULL) { 109 BG = new BondGraph(IsAngstroem); 110 free_BG = true; 111 } 97 112 98 113 BondDistance = bonddistance; // * ((IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem); 99 114 *out << Verbose(0) << "Begin of CreateAdjacencyList." << endl; 100 115 // remove every bond from the list 101 if ((first->next != last) && (last->previous != first)) { // there are bonds present 102 cleanup(first,last); 103 } 116 bond *Binder = NULL; 117 while (last->previous != first) { 118 Binder = last->previous; 119 Binder->leftatom->UnregisterBond(Binder); 120 Binder->rightatom->UnregisterBond(Binder); 121 removewithoutcheck(Binder); 122 } 123 BondCount = 0; 104 124 105 125 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering) 106 126 CountAtoms(out); 107 *out << Verbose(1) << "AtomCount " << AtomCount << "." << endl; 108 109 if (AtomCount != 0) { 110 // 1. find divisor for each axis, such that a sphere with radius of at least bonddistance can be placed into each cell 111 j=-1; 112 for (int i=0;i<NDIM;i++) { 113 j += i+1; 114 divisor[i] = (int)floor(cell_size[j]/bonddistance); // take smaller value such that size of linked cell is at least bonddistance 115 //*out << Verbose(1) << "divisor[" << i << "] = " << divisor[i] << "." << endl; 116 } 117 // 2a. allocate memory for the cell list 118 NumberCells = divisor[0]*divisor[1]*divisor[2]; 119 *out << Verbose(1) << "Allocating " << NumberCells << " cells." << endl; 120 CellList = Malloc<molecule*>(NumberCells, "molecule::CreateAdjacencyList - ** CellList"); 121 for (int i=NumberCells;i--;) 122 CellList[i] = NULL; 123 124 // 2b. put all atoms into its corresponding list 127 *out << Verbose(1) << "AtomCount " << AtomCount << " and bonddistance is " << bonddistance << "." << endl; 128 129 if ((AtomCount > 1) && (bonddistance > 1.)) { 130 *out << Verbose(2) << "Creating Linked Cell structure ... " << endl; 131 LC = new LinkedCell(this, bonddistance); 132 133 // create a list to map Tesselpoint::nr to atom * 134 *out << Verbose(2) << "Creating TesselPoint to atom map ... " << endl; 135 AtomMap = Calloc<atom *> (AtomCount, "molecule::CreateAdjacencyList - **AtomCount"); 125 136 Walker = start; 126 while (Walker->next != end) {137 while (Walker->next != end) { 127 138 Walker = Walker->next; 128 //*out << Verbose(1) << "Current atom is " << *Walker << " with coordinates "; 129 //Walker->x.Output(out); 130 //*out << "." << endl; 131 // compute the cell by the atom's coordinates 132 j=-1; 133 for (int i=0;i<NDIM;i++) { 134 j += i+1; 135 x.CopyVector(&(Walker->x)); 136 x.KeepPeriodic(out, matrix); 137 n[i] = (int)floor(x.x[i]/cell_size[j]*(double)divisor[i]); 138 } 139 index = n[2] + (n[1] + n[0] * divisor[1]) * divisor[2]; 140 //*out << Verbose(1) << "Atom " << *Walker << " goes into cell number [" << n[0] << "," << n[1] << "," << n[2] << "] = " << index << "." << endl; 141 // add copy atom to this cell 142 if (CellList[index] == NULL) // allocate molecule if not done 143 CellList[index] = new molecule(elemente); 144 OtherWalker = CellList[index]->AddCopyAtom(Walker); // add a copy of walker to this atom, father will be walker for later reference 145 //*out << Verbose(1) << "Copy Atom is " << *OtherWalker << "." << endl; 146 } 147 //for (int i=0;i<NumberCells;i++) 148 //*out << Verbose(1) << "Cell number " << i << ": " << CellList[i] << "." << endl; 149 139 AtomMap[Walker->nr] = Walker; 140 } 150 141 151 142 // 3a. go through every cell 152 for (N[0]=divisor[0];N[0]--;) 153 for (N[1]=divisor[1];N[1]--;) 154 for (N[2]=divisor[2];N[2]--;) { 155 Index = N[2] + (N[1] + N[0] * divisor[1]) * divisor[2]; 156 if (CellList[Index] != NULL) { // if there atoms in this cell 157 //*out << Verbose(1) << "Current cell is " << Index << "." << endl; 158 // 3b. for every atom therein 159 Walker = CellList[Index]->start; 160 while (Walker->next != CellList[Index]->end) { // go through every atom 161 Walker = Walker->next; 143 *out << Verbose(2) << "Celling ... " << endl; 144 for (LC->n[0] = 0; LC->n[0] < LC->N[0]; LC->n[0]++) 145 for (LC->n[1] = 0; LC->n[1] < LC->N[1]; LC->n[1]++) 146 for (LC->n[2] = 0; LC->n[2] < LC->N[2]; LC->n[2]++) { 147 const LinkedNodes *List = LC->GetCurrentCell(); 148 //*out << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << " containing " << List->size() << " points." << endl; 149 if (List != NULL) { 150 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) { 151 Walker = AtomMap[(*Runner)->nr]; 162 152 //*out << Verbose(0) << "Current Atom is " << *Walker << "." << endl; 163 153 // 3c. check for possible bond between each atom in this and every one in the 27 cells 164 for (n[0]=-1;n[0]<=1;n[0]++) 165 for (n[1]=-1;n[1]<=1;n[1]++) 166 for (n[2]=-1;n[2]<=1;n[2]++) { 167 // compute the index of this comparison cell and make it periodic 168 index = ((N[2]+n[2]+divisor[2])%divisor[2]) + (((N[1]+n[1]+divisor[1])%divisor[1]) + ((N[0]+n[0]+divisor[0])%divisor[0]) * divisor[1]) * divisor[2]; 169 //*out << Verbose(1) << "Number of comparison cell is " << index << "." << endl; 170 if (CellList[index] != NULL) { // if there are any atoms in this cell 171 OtherWalker = CellList[index]->start; 172 while(OtherWalker->next != CellList[index]->end) { // go through every atom in this cell 173 OtherWalker = OtherWalker->next; 174 //*out << Verbose(0) << "Current comparison atom is " << *OtherWalker << "." << endl; 175 /// \todo periodic check is missing here! 176 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl; 177 MinDistance = OtherWalker->type->CovalentRadius + Walker->type->CovalentRadius; 178 MinDistance *= (IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem; 179 MaxDistance = MinDistance + BONDTHRESHOLD; 180 MinDistance -= BONDTHRESHOLD; 181 distance = OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size); 182 if ((OtherWalker->father->nr > Walker->father->nr) && (distance <= MaxDistance*MaxDistance) && (distance >= MinDistance*MinDistance)) { // create bond if distance is smaller 183 //*out << Verbose(1) << "Adding Bond between " << *Walker << " and " << *OtherWalker << " in distance " << sqrt(distance) << "." << endl; 184 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount 185 } else { 186 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl; 154 for (n[0] = -1; n[0] <= 1; n[0]++) 155 for (n[1] = -1; n[1] <= 1; n[1]++) 156 for (n[2] = -1; n[2] <= 1; n[2]++) { 157 const LinkedNodes *OtherList = LC->GetRelativeToCurrentCell(n); 158 //*out << Verbose(2) << "Current relative cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << " containing " << List->size() << " points." << endl; 159 if (OtherList != NULL) { 160 for (LinkedNodes::const_iterator OtherRunner = OtherList->begin(); OtherRunner != OtherList->end(); OtherRunner++) { 161 if ((*OtherRunner)->nr > Walker->nr) { 162 OtherWalker = AtomMap[(*OtherRunner)->nr]; 163 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl; 164 (BG->*minmaxdistance)(Walker, OtherWalker, MinDistance, MaxDistance, IsAngstroem); 165 const double distance = OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size); 166 const bool status = (distance <= MaxDistance * MaxDistance) && (distance >= MinDistance * MinDistance); 167 if ((OtherWalker->father->nr > Walker->father->nr) && (status)) { // create bond if distance is smaller 168 //*out << Verbose(1) << "Adding Bond between " << *Walker << " and " << *OtherWalker << " in distance " << sqrt(distance) << "." << endl; 169 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount 170 } else { 171 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl; 172 } 187 173 } 188 174 } … … 192 178 } 193 179 } 194 195 196 197 // 4. free the cell again 198 for (int i=NumberCells;i--;) 199 if (CellList[i] != NULL) { 200 delete(CellList[i]); 201 } 202 Free(&CellList); 203 204 // create the adjacency list per atom 205 CreateListOfBondsPerAtom(out); 206 207 // correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees, 208 // iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene 209 // preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of 210 // double bonds as was expected. 211 if (BondCount != 0) { 212 NoCyclicBonds = 0; 213 *out << Verbose(1) << "Correcting Bond degree of each bond ... "; 214 do { 215 No = 0; // No acts as breakup flag (if 1 we still continue) 216 Walker = start; 217 while (Walker->next != end) { // go through every atom 218 Walker = Walker->next; 219 // count valence of first partner 220 NoBonds = 0; 221 for(j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) 222 NoBonds += ListOfBondsPerAtom[Walker->nr][j]->BondDegree; 223 *out << Verbose(3) << "Walker " << *Walker << ": " << (int)Walker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl; 224 if ((int)(Walker->type->NoValenceOrbitals) > NoBonds) { // we have a mismatch, check all bonding partners for mismatch 225 Candidate = NULL; 226 CandidateBondNo = -1; 227 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through each of its bond partners 228 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker); 229 // count valence of second partner 230 NoBonds = 0; 231 for(j=0;j<NumberOfBondsPerAtom[OtherWalker->nr];j++) 232 NoBonds += ListOfBondsPerAtom[OtherWalker->nr][j]->BondDegree; 233 *out << Verbose(3) << "OtherWalker " << *OtherWalker << ": " << (int)OtherWalker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl; 234 if ((int)(OtherWalker->type->NoValenceOrbitals) > NoBonds) { // check if possible candidate 235 if ((Candidate == NULL) || (NumberOfBondsPerAtom[Candidate->nr] > NumberOfBondsPerAtom[OtherWalker->nr])) { // pick the one with fewer number of bonds first 236 Candidate = OtherWalker; 237 CandidateBondNo = i; 238 *out << Verbose(3) << "New candidate is " << *Candidate << "." << endl; 239 } 240 } 241 } 242 if ((Candidate != NULL) && (CandidateBondNo != -1)) { 243 ListOfBondsPerAtom[Walker->nr][CandidateBondNo]->BondDegree++; 244 *out << Verbose(2) << "Increased bond degree for bond " << *ListOfBondsPerAtom[Walker->nr][CandidateBondNo] << "." << endl; 245 } else 246 *out << Verbose(2) << "Could not find correct degree for atom " << *Walker << "." << endl; 247 FalseBondDegree++; 248 } 249 } 250 } while (No); 251 *out << " done." << endl; 252 } else 253 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl; 254 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << bonddistance << ", " << FalseBondDegree << " bonds could not be corrected." << endl; 180 Free(&AtomMap); 181 delete (LC); 182 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << BondDistance << "." << endl; 183 184 // correct bond degree by comparing valence and bond degree 185 *out << Verbose(2) << "Correcting bond degree ... " << endl; 186 CorrectBondDegree(out); 255 187 256 188 // output bonds for debugging (if bond chain list was correctly installed) 257 *out << Verbose(1) << endl << "From contents of bond chain list:"; 258 bond *Binder = first; 259 while(Binder->next != last) { 260 Binder = Binder->next; 261 *out << *Binder << "\t" << endl; 262 } 263 *out << endl; 189 ActOnAllAtoms(&atom::OutputBondOfAtom, out); 264 190 } else 265 191 *out << Verbose(1) << "AtomCount is " << AtomCount << ", thus no bonds, no connections!." << endl; 266 192 *out << Verbose(0) << "End of CreateAdjacencyList." << endl; 267 Free(&matrix); 268 269 }; 193 if (free_BG) 194 delete(BG); 195 } 196 ; 197 198 /** Prints a list of all bonds to \a *out. 199 * \param output stream 200 */ 201 void molecule::OutputBondsList(ofstream *out) const 202 { 203 *out << Verbose(1) << endl << "From contents of bond chain list:"; 204 bond *Binder = first; 205 while (Binder->next != last) { 206 Binder = Binder->next; 207 *out << *Binder << "\t" << endl; 208 } 209 *out << endl; 210 } 211 ; 212 213 /** correct bond degree by comparing valence and bond degree. 214 * correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees, 215 * iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene 216 * preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of 217 * double bonds as was expected. 218 * \param *out output stream for debugging 219 * \return number of bonds that could not be corrected 220 */ 221 int molecule::CorrectBondDegree(ofstream *out) const 222 { 223 int No = 0, OldNo = -1; 224 225 if (BondCount != 0) { 226 *out << Verbose(1) << "Correcting Bond degree of each bond ... " << endl; 227 do { 228 OldNo = No; 229 No = SumPerAtom(&atom::CorrectBondDegree, out); 230 } while (OldNo != No); 231 *out << " done." << endl; 232 } else { 233 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl; 234 } 235 *out << No << " bonds could not be corrected." << endl; 236 237 return (No); 238 } 239 ; 270 240 271 241 /** Counts all cyclic bonds and returns their number. … … 276 246 int molecule::CountCyclicBonds(ofstream *out) 277 247 { 278 int No= 0;248 NoCyclicBonds = 0; 279 249 int *MinimumRingSize = NULL; 280 250 MoleculeLeafClass *Subgraphs = NULL; … … 286 256 while (Subgraphs->next != NULL) { 287 257 Subgraphs = Subgraphs->next; 288 delete (Subgraphs->previous);289 } 290 delete (Subgraphs);291 delete[] (MinimumRingSize);292 } 293 while (Binder->next != last) {258 delete (Subgraphs->previous); 259 } 260 delete (Subgraphs); 261 delete[] (MinimumRingSize); 262 } 263 while (Binder->next != last) { 294 264 Binder = Binder->next; 295 265 if (Binder->Cyclic) 296 No++; 297 } 298 delete(BackEdgeStack); 299 return No; 300 }; 266 NoCyclicBonds++; 267 } 268 delete (BackEdgeStack); 269 return NoCyclicBonds; 270 } 271 ; 272 301 273 /** Returns Shading as a char string. 302 274 * \param color the Shading 303 275 * \return string of the flag 304 276 */ 305 string molecule::GetColor(enum Shading color) 306 { 307 switch (color) {277 string molecule::GetColor(enum Shading color) const 278 { 279 switch (color) { 308 280 case white: 309 281 return "white"; … … 322 294 break; 323 295 }; 324 }; 296 } 297 ; 298 299 /** Sets atom::GraphNr and atom::LowpointNr to BFSAccounting::CurrentGraphNr. 300 * \param *out output stream for debugging 301 * \param *Walker current node 302 * \param &BFS structure with accounting data for BFS 303 */ 304 void DepthFirstSearchAnalysis_SetWalkersGraphNr(ofstream *out, atom *&Walker, struct DFSAccounting &DFS) 305 { 306 if (!DFS.BackStepping) { // if we don't just return from (8) 307 Walker->GraphNr = DFS.CurrentGraphNr; 308 Walker->LowpointNr = DFS.CurrentGraphNr; 309 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl; 310 DFS.AtomStack->Push(Walker); 311 DFS.CurrentGraphNr++; 312 } 313 } 314 ; 315 316 /** During DFS goes along unvisited bond and touches other atom. 317 * Sets bond::type, if 318 * -# BackEdge: set atom::LowpointNr and push on \a BackEdgeStack 319 * -# TreeEgde: set atom::Ancestor and continue with Walker along this edge 320 * Continue until molecule::FindNextUnused() finds no more unused bonds. 321 * \param *out output stream for debugging 322 * \param *mol molecule with atoms and finding unused bonds 323 * \param *&Binder current edge 324 * \param &DFS DFS accounting data 325 */ 326 void DepthFirstSearchAnalysis_ProbeAlongUnusedBond(ofstream *out, const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS) 327 { 328 atom *OtherAtom = NULL; 329 330 do { // (3) if Walker has no unused egdes, go to (5) 331 DFS.BackStepping = false; // reset backstepping flag for (8) 332 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused 333 Binder = mol->FindNextUnused(Walker); 334 if (Binder == NULL) 335 break; 336 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl; 337 // (4) Mark Binder used, ... 338 Binder->MarkUsed(black); 339 OtherAtom = Binder->GetOtherAtom(Walker); 340 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl; 341 if (OtherAtom->GraphNr != -1) { 342 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3) 343 Binder->Type = BackEdge; 344 DFS.BackEdgeStack->Push(Binder); 345 Walker->LowpointNr = (Walker->LowpointNr < OtherAtom->GraphNr) ? Walker->LowpointNr : OtherAtom->GraphNr; 346 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl; 347 } else { 348 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2) 349 Binder->Type = TreeEdge; 350 OtherAtom->Ancestor = Walker; 351 Walker = OtherAtom; 352 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl; 353 break; 354 } 355 Binder = NULL; 356 } while (1); // (3) 357 } 358 ; 359 360 /** Checks whether we have a new component. 361 * if atom::LowpointNr of \a *&Walker is greater than atom::GraphNr of its atom::Ancestor, we have a new component. 362 * Meaning that if we touch upon a node who suddenly has a smaller atom::LowpointNr than its ancestor, then we 363 * have a found a new branch in the graph tree. 364 * \param *out output stream for debugging 365 * \param *mol molecule with atoms and finding unused bonds 366 * \param *&Walker current node 367 * \param &DFS DFS accounting data 368 */ 369 void DepthFirstSearchAnalysis_CheckForaNewComponent(ofstream *out, const molecule * const mol, atom *&Walker, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker) 370 { 371 atom *OtherAtom = NULL; 372 373 // (5) if Ancestor of Walker is ... 374 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl; 375 376 if (Walker->Ancestor->GraphNr != DFS.Root->GraphNr) { 377 // (6) (Ancestor of Walker is not Root) 378 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) { 379 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8) 380 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr; 381 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl; 382 } else { 383 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component 384 Walker->Ancestor->SeparationVertex = true; 385 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl; 386 mol->SetNextComponentNumber(Walker->Ancestor, DFS.ComponentNumber); 387 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << DFS.ComponentNumber << "." << endl; 388 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber); 389 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << DFS.ComponentNumber << "." << endl; 390 do { 391 OtherAtom = DFS.AtomStack->PopLast(); 392 LeafWalker->Leaf->AddCopyAtom(OtherAtom); 393 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber); 394 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << DFS.ComponentNumber << "." << endl; 395 } while (OtherAtom != Walker); 396 DFS.ComponentNumber++; 397 } 398 // (8) Walker becomes its Ancestor, go to (3) 399 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl; 400 Walker = Walker->Ancestor; 401 DFS.BackStepping = true; 402 } 403 } 404 ; 405 406 /** Cleans the root stack when we have found a component. 407 * If we are not DFSAccounting::BackStepping, then we clear the root stack by putting everything into a 408 * component down till we meet DFSAccounting::Root. 409 * \param *out output stream for debugging 410 * \param *mol molecule with atoms and finding unused bonds 411 * \param *&Walker current node 412 * \param *&Binder current edge 413 * \param &DFS DFS accounting data 414 */ 415 void DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(ofstream *out, const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker) 416 { 417 atom *OtherAtom = NULL; 418 419 if (!DFS.BackStepping) { // coming from (8) want to go to (3) 420 // (9) remove all from stack till Walker (including), these and Root form a component 421 //DFS.AtomStack->Output(out); 422 mol->SetNextComponentNumber(DFS.Root, DFS.ComponentNumber); 423 *out << Verbose(3) << "(9) Root[" << DFS.Root->Name << "]'s Component is " << DFS.ComponentNumber << "." << endl; 424 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber); 425 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << DFS.ComponentNumber << "." << endl; 426 do { 427 OtherAtom = DFS.AtomStack->PopLast(); 428 LeafWalker->Leaf->AddCopyAtom(OtherAtom); 429 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber); 430 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << DFS.ComponentNumber << "." << endl; 431 } while (OtherAtom != Walker); 432 DFS.ComponentNumber++; 433 434 // (11) Root is separation vertex, set Walker to Root and go to (4) 435 Walker = DFS.Root; 436 Binder = mol->FindNextUnused(Walker); 437 *out << Verbose(1) << "(10) Walker is Root[" << DFS.Root->Name << "], next Unused Bond is " << Binder << "." << endl; 438 if (Binder != NULL) { // Root is separation vertex 439 *out << Verbose(1) << "(11) Root is a separation vertex." << endl; 440 Walker->SeparationVertex = true; 441 } 442 } 443 } 444 ; 445 446 /** Initializes DFSAccounting structure. 447 * \param *out output stream for debugging 448 * \param &DFS accounting structure to allocate 449 * \param *mol molecule with AtomCount, BondCount and all atoms 450 */ 451 void DepthFirstSearchAnalysis_Init(ofstream *out, struct DFSAccounting &DFS, const molecule * const mol) 452 { 453 DFS.AtomStack = new StackClass<atom *> (mol->AtomCount); 454 DFS.CurrentGraphNr = 0; 455 DFS.ComponentNumber = 0; 456 DFS.BackStepping = false; 457 mol->ResetAllBondsToUnused(); 458 mol->SetAtomValueToValue(-1, &atom::GraphNr); 459 mol->ActOnAllAtoms(&atom::InitComponentNr); 460 DFS.BackEdgeStack->ClearStack(); 461 } 462 ; 463 464 /** Free's DFSAccounting structure. 465 * \param *out output stream for debugging 466 * \param &DFS accounting structure to free 467 */ 468 void DepthFirstSearchAnalysis_Finalize(ofstream *out, struct DFSAccounting &DFS) 469 { 470 delete (DFS.AtomStack); 471 // delete (DFS.BackEdgeStack); // DON'T free, see DepthFirstSearchAnalysis(), is returned as allocated 472 } 473 ; 325 474 326 475 /** Performs a Depth-First search on this molecule. … … 332 481 * \return list of each disconnected subgraph as an individual molecule class structure 333 482 */ 334 MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, class StackClass<bond *> *&BackEdgeStack) 335 { 336 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);483 MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, class StackClass<bond *> *&BackEdgeStack) const 484 { 485 struct DFSAccounting DFS; 337 486 BackEdgeStack = new StackClass<bond *> (BondCount); 487 DFS.BackEdgeStack = BackEdgeStack; 338 488 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL); 339 489 MoleculeLeafClass *LeafWalker = SubGraphs; 340 int CurrentGraphNr = 0, OldGraphNr; 341 int ComponentNumber = 0; 342 atom *Walker = NULL, *OtherAtom = NULL, *Root = start->next; 490 int OldGraphNr = 0; 491 atom *Walker = NULL; 343 492 bond *Binder = NULL; 344 bool BackStepping = false;345 493 346 494 *out << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl; 347 348 ResetAllBondsToUnused(); 349 ResetAllAtomNumbers(); 350 InitComponentNumbers(); 351 BackEdgeStack->ClearStack(); 352 while (Root != end) { // if there any atoms at all 353 // (1) mark all edges unused, empty stack, set atom->GraphNr = 0 for all 354 AtomStack->ClearStack(); 495 DepthFirstSearchAnalysis_Init(out, DFS, this); 496 497 DFS.Root = start->next; 498 while (DFS.Root != end) { // if there any atoms at all 499 // (1) mark all edges unused, empty stack, set atom->GraphNr = -1 for all 500 DFS.AtomStack->ClearStack(); 355 501 356 502 // put into new subgraph molecule and add this to list of subgraphs 357 503 LeafWalker = new MoleculeLeafClass(LeafWalker); 358 504 LeafWalker->Leaf = new molecule(elemente); 359 LeafWalker->Leaf->AddCopyAtom( Root);360 361 OldGraphNr = CurrentGraphNr;362 Walker = Root;505 LeafWalker->Leaf->AddCopyAtom(DFS.Root); 506 507 OldGraphNr = DFS.CurrentGraphNr; 508 Walker = DFS.Root; 363 509 do { // (10) 364 510 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom 365 if (!BackStepping) { // if we don't just return from (8) 366 Walker->GraphNr = CurrentGraphNr; 367 Walker->LowpointNr = CurrentGraphNr; 368 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl; 369 AtomStack->Push(Walker); 370 CurrentGraphNr++; 371 } 372 do { // (3) if Walker has no unused egdes, go to (5) 373 BackStepping = false; // reset backstepping flag for (8) 374 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused 375 Binder = FindNextUnused(Walker); 376 if (Binder == NULL) 377 break; 378 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl; 379 // (4) Mark Binder used, ... 380 Binder->MarkUsed(black); 381 OtherAtom = Binder->GetOtherAtom(Walker); 382 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl; 383 if (OtherAtom->GraphNr != -1) { 384 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3) 385 Binder->Type = BackEdge; 386 BackEdgeStack->Push(Binder); 387 Walker->LowpointNr = ( Walker->LowpointNr < OtherAtom->GraphNr ) ? Walker->LowpointNr : OtherAtom->GraphNr; 388 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl; 389 } else { 390 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2) 391 Binder->Type = TreeEdge; 392 OtherAtom->Ancestor = Walker; 393 Walker = OtherAtom; 394 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl; 395 break; 396 } 397 Binder = NULL; 398 } while (1); // (3) 511 DepthFirstSearchAnalysis_SetWalkersGraphNr(out, Walker, DFS); 512 513 DepthFirstSearchAnalysis_ProbeAlongUnusedBond(out, this, Walker, Binder, DFS); 514 399 515 if (Binder == NULL) { 400 516 *out << Verbose(2) << "No more Unused Bonds." << endl; … … 402 518 } else 403 519 Binder = NULL; 404 } while (1); 520 } while (1); // (2) 405 521 406 522 // if we came from backstepping, yet there were no more unused bonds, we end up here with no Ancestor, because Walker is Root! Then we are finished! 407 if ((Walker == Root) && (Binder == NULL))523 if ((Walker == DFS.Root) && (Binder == NULL)) 408 524 break; 409 525 410 // (5) if Ancestor of Walker is ... 411 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl; 412 if (Walker->Ancestor->GraphNr != Root->GraphNr) { 413 // (6) (Ancestor of Walker is not Root) 414 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) { 415 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8) 416 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr; 417 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl; 418 } else { 419 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component 420 Walker->Ancestor->SeparationVertex = true; 421 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl; 422 SetNextComponentNumber(Walker->Ancestor, ComponentNumber); 423 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << ComponentNumber << "." << endl; 424 SetNextComponentNumber(Walker, ComponentNumber); 425 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << ComponentNumber << "." << endl; 426 do { 427 OtherAtom = AtomStack->PopLast(); 428 LeafWalker->Leaf->AddCopyAtom(OtherAtom); 429 SetNextComponentNumber(OtherAtom, ComponentNumber); 430 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl; 431 } while (OtherAtom != Walker); 432 ComponentNumber++; 433 } 434 // (8) Walker becomes its Ancestor, go to (3) 435 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl; 436 Walker = Walker->Ancestor; 437 BackStepping = true; 438 } 439 if (!BackStepping) { // coming from (8) want to go to (3) 440 // (9) remove all from stack till Walker (including), these and Root form a component 441 AtomStack->Output(out); 442 SetNextComponentNumber(Root, ComponentNumber); 443 *out << Verbose(3) << "(9) Root[" << Root->Name << "]'s Component is " << ComponentNumber << "." << endl; 444 SetNextComponentNumber(Walker, ComponentNumber); 445 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << ComponentNumber << "." << endl; 446 do { 447 OtherAtom = AtomStack->PopLast(); 448 LeafWalker->Leaf->AddCopyAtom(OtherAtom); 449 SetNextComponentNumber(OtherAtom, ComponentNumber); 450 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl; 451 } while (OtherAtom != Walker); 452 ComponentNumber++; 453 454 // (11) Root is separation vertex, set Walker to Root and go to (4) 455 Walker = Root; 456 Binder = FindNextUnused(Walker); 457 *out << Verbose(1) << "(10) Walker is Root[" << Root->Name << "], next Unused Bond is " << Binder << "." << endl; 458 if (Binder != NULL) { // Root is separation vertex 459 *out << Verbose(1) << "(11) Root is a separation vertex." << endl; 460 Walker->SeparationVertex = true; 461 } 462 } 463 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges 526 DepthFirstSearchAnalysis_CheckForaNewComponent(out, this, Walker, DFS, LeafWalker); 527 528 DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(out, this, Walker, Binder, DFS, LeafWalker); 529 530 } while ((DFS.BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges 464 531 465 532 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph 466 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << CurrentGraphNr << "." << endl;533 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << DFS.CurrentGraphNr << "." << endl; 467 534 LeafWalker->Leaf->Output(out); 468 535 *out << endl; 469 536 470 537 // step on to next root 471 while (( Root != end) && (Root->GraphNr != -1)) {538 while ((DFS.Root != end) && (DFS.Root->GraphNr != -1)) { 472 539 //*out << Verbose(1) << "Current next subgraph root candidate is " << Root->Name << "." << endl; 473 if ( Root->GraphNr != -1) // if already discovered, step on474 Root =Root->next;540 if (DFS.Root->GraphNr != -1) // if already discovered, step on 541 DFS.Root = DFS.Root->next; 475 542 } 476 543 } 477 544 // set cyclic bond criterium on "same LP" basis 478 Binder = first; 479 while(Binder->next != last) { 545 CyclicBondAnalysis(); 546 547 OutputGraphInfoPerAtom(out); 548 549 OutputGraphInfoPerBond(out); 550 551 // free all and exit 552 DepthFirstSearchAnalysis_Finalize(out, DFS); 553 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl; 554 return SubGraphs; 555 } 556 ; 557 558 /** Scans through all bonds and set bond::Cyclic to true where atom::LowpointNr of both ends is equal: LP criterion. 559 */ 560 void molecule::CyclicBondAnalysis() const 561 { 562 NoCyclicBonds = 0; 563 bond *Binder = first; 564 while (Binder->next != last) { 480 565 Binder = Binder->next; 481 566 if (Binder->rightatom->LowpointNr == Binder->leftatom->LowpointNr) { // cyclic ?? … … 484 569 } 485 570 } 486 487 571 } 572 ; 573 574 /** Output graph information per atom. 575 * \param *out output stream 576 */ 577 void molecule::OutputGraphInfoPerAtom(ofstream *out) const 578 { 488 579 *out << Verbose(1) << "Final graph info for each atom is:" << endl; 489 Walker = start; 490 while (Walker->next != end) { 491 Walker = Walker->next; 492 *out << Verbose(2) << "Atom " << Walker->Name << " is " << ((Walker->SeparationVertex) ? "a" : "not a") << " separation vertex, components are "; 493 OutputComponentNumber(out, Walker); 494 *out << " with Lowpoint " << Walker->LowpointNr << " and Graph Nr. " << Walker->GraphNr << "." << endl; 495 } 496 580 ActOnAllAtoms(&atom::OutputGraphInfo, out); 581 } 582 ; 583 584 /** Output graph information per bond. 585 * \param *out output stream 586 */ 587 void molecule::OutputGraphInfoPerBond(ofstream *out) const 588 { 497 589 *out << Verbose(1) << "Final graph info for each bond is:" << endl; 498 Binder = first;499 while (Binder->next != last) {590 bond *Binder = first; 591 while (Binder->next != last) { 500 592 Binder = Binder->next; 501 593 *out << Verbose(2) << ((Binder->Type == TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <"; 502 594 *out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp."; 503 OutputComponentNumber(out, Binder->leftatom);595 Binder->leftatom->OutputComponentNumber(out); 504 596 *out << " === "; 505 597 *out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp."; 506 OutputComponentNumber(out, Binder->rightatom);598 Binder->rightatom->OutputComponentNumber(out); 507 599 *out << ">." << endl; 508 600 if (Binder->Cyclic) // cyclic ?? 509 601 *out << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl; 510 602 } 511 512 // free all and exit 513 delete(AtomStack); 514 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl; 515 return SubGraphs; 603 } 604 ; 605 606 /** Initialise each vertex as white with no predecessor, empty queue, color Root lightgray. 607 * \param *out output stream for debugging 608 * \param &BFS accounting structure 609 * \param AtomCount number of entries in the array to allocate 610 */ 611 void InitializeBFSAccounting(ofstream *out, struct BFSAccounting &BFS, int AtomCount) 612 { 613 BFS.AtomCount = AtomCount; 614 BFS.PredecessorList = Calloc<atom*> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: **PredecessorList"); 615 BFS.ShortestPathList = Malloc<int> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ShortestPathList"); 616 BFS.ColorList = Calloc<enum Shading> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ColorList"); 617 BFS.BFSStack = new StackClass<atom *> (AtomCount); 618 619 for (int i = AtomCount; i--;) 620 BFS.ShortestPathList[i] = -1; 516 621 }; 622 623 /** Free's accounting structure. 624 * \param *out output stream for debugging 625 * \param &BFS accounting structure 626 */ 627 void FinalizeBFSAccounting(ofstream *out, struct BFSAccounting &BFS) 628 { 629 Free(&BFS.PredecessorList); 630 Free(&BFS.ShortestPathList); 631 Free(&BFS.ColorList); 632 delete (BFS.BFSStack); 633 BFS.AtomCount = 0; 634 }; 635 636 /** Clean the accounting structure. 637 * \param *out output stream for debugging 638 * \param &BFS accounting structure 639 */ 640 void CleanBFSAccounting(ofstream *out, struct BFSAccounting &BFS) 641 { 642 atom *Walker = NULL; 643 while (!BFS.TouchedStack->IsEmpty()) { 644 Walker = BFS.TouchedStack->PopFirst(); 645 BFS.PredecessorList[Walker->nr] = NULL; 646 BFS.ShortestPathList[Walker->nr] = -1; 647 BFS.ColorList[Walker->nr] = white; 648 } 649 }; 650 651 /** Resets shortest path list and BFSStack. 652 * \param *out output stream for debugging 653 * \param *&Walker current node, pushed onto BFSAccounting::BFSStack and BFSAccounting::TouchedStack 654 * \param &BFS accounting structure 655 */ 656 void ResetBFSAccounting(ofstream *out, atom *&Walker, struct BFSAccounting &BFS) 657 { 658 BFS.ShortestPathList[Walker->nr] = 0; 659 BFS.BFSStack->ClearStack(); // start with empty BFS stack 660 BFS.BFSStack->Push(Walker); 661 BFS.TouchedStack->Push(Walker); 662 }; 663 664 /** Performs a BFS from \a *Root, trying to find the same node and hence a cycle. 665 * \param *out output stream for debugging 666 * \param *&BackEdge the edge from root that we don't want to move along 667 * \param &BFS accounting structure 668 */ 669 void CyclicStructureAnalysis_CyclicBFSFromRootToRoot(ofstream *out, bond *&BackEdge, struct BFSAccounting &BFS) 670 { 671 atom *Walker = NULL; 672 atom *OtherAtom = NULL; 673 do { // look for Root 674 Walker = BFS.BFSStack->PopFirst(); 675 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *BFS.Root << "." << endl; 676 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) { 677 if ((*Runner) != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder) 678 OtherAtom = (*Runner)->GetOtherAtom(Walker); 679 #ifdef ADDHYDROGEN 680 if (OtherAtom->type->Z != 1) { 681 #endif 682 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *(*Runner) << "." << endl; 683 if (BFS.ColorList[OtherAtom->nr] == white) { 684 BFS.TouchedStack->Push(OtherAtom); 685 BFS.ColorList[OtherAtom->nr] = lightgray; 686 BFS.PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor 687 BFS.ShortestPathList[OtherAtom->nr] = BFS.ShortestPathList[Walker->nr] + 1; 688 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << BFS.ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl; 689 //if (BFS.ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance 690 *out << Verbose(3) << "Putting OtherAtom into queue." << endl; 691 BFS.BFSStack->Push(OtherAtom); 692 //} 693 } else { 694 *out << Verbose(3) << "Not Adding, has already been visited." << endl; 695 } 696 if (OtherAtom == BFS.Root) 697 break; 698 #ifdef ADDHYDROGEN 699 } else { 700 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl; 701 BFS.ColorList[OtherAtom->nr] = black; 702 } 703 #endif 704 } else { 705 *out << Verbose(2) << "Bond " << *(*Runner) << " not Visiting, is the back edge." << endl; 706 } 707 } 708 BFS.ColorList[Walker->nr] = black; 709 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl; 710 if (OtherAtom == BFS.Root) { // if we have found the root, check whether this cycle wasn't already found beforehand 711 // step through predecessor list 712 while (OtherAtom != BackEdge->rightatom) { 713 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet 714 break; 715 else 716 OtherAtom = BFS.PredecessorList[OtherAtom->nr]; 717 } 718 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already 719 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl; 720 do { 721 OtherAtom = BFS.TouchedStack->PopLast(); 722 if (BFS.PredecessorList[OtherAtom->nr] == Walker) { 723 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl; 724 BFS.PredecessorList[OtherAtom->nr] = NULL; 725 BFS.ShortestPathList[OtherAtom->nr] = -1; 726 BFS.ColorList[OtherAtom->nr] = white; 727 BFS.BFSStack->RemoveItem(OtherAtom); 728 } 729 } while ((!BFS.TouchedStack->IsEmpty()) && (BFS.PredecessorList[OtherAtom->nr] == NULL)); 730 BFS.TouchedStack->Push(OtherAtom); // last was wrongly popped 731 OtherAtom = BackEdge->rightatom; // set to not Root 732 } else 733 OtherAtom = BFS.Root; 734 } 735 } while ((!BFS.BFSStack->IsEmpty()) && (OtherAtom != BFS.Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]))); 736 }; 737 738 /** Climb back the BFSAccounting::PredecessorList and find cycle members. 739 * \param *out output stream for debugging 740 * \param *&OtherAtom 741 * \param *&BackEdge denotes the edge we did not want to travel along when doing CyclicBFSFromRootToRoot() 742 * \param &BFS accounting structure 743 * \param *&MinimumRingSize minimum distance from this node possible without encountering oneself, set on return for each atom 744 * \param &MinRingSize global minimum distance from one node without encountering oneself, set on return 745 */ 746 void CyclicStructureAnalysis_RetrieveCycleMembers(ofstream *out, atom *&OtherAtom, bond *&BackEdge, struct BFSAccounting &BFS, int *&MinimumRingSize, int &MinRingSize) 747 { 748 atom *Walker = NULL; 749 int NumCycles = 0; 750 int RingSize = -1; 751 752 if (OtherAtom == BFS.Root) { 753 // now climb back the predecessor list and thus find the cycle members 754 NumCycles++; 755 RingSize = 1; 756 BFS.Root->GetTrueFather()->IsCyclic = true; 757 *out << Verbose(1) << "Found ring contains: "; 758 Walker = BFS.Root; 759 while (Walker != BackEdge->rightatom) { 760 *out << Walker->Name << " <-> "; 761 Walker = BFS.PredecessorList[Walker->nr]; 762 Walker->GetTrueFather()->IsCyclic = true; 763 RingSize++; 764 } 765 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl; 766 // walk through all and set MinimumRingSize 767 Walker = BFS.Root; 768 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize; 769 while (Walker != BackEdge->rightatom) { 770 Walker = BFS.PredecessorList[Walker->nr]; 771 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr]) 772 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize; 773 } 774 if ((RingSize < MinRingSize) || (MinRingSize == -1)) 775 MinRingSize = RingSize; 776 } else { 777 *out << Verbose(1) << "No ring containing " << *BFS.Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl; 778 } 779 }; 780 781 /** From a given node performs a BFS to touch the next cycle, for whose nodes \a *&MinimumRingSize is set and set it accordingly. 782 * \param *out output stream for debugging 783 * \param *&Root node to look for closest cycle from, i.e. \a *&MinimumRingSize is set for this node 784 * \param *&MinimumRingSize minimum distance from this node possible without encountering oneself, set on return for each atom 785 * \param AtomCount number of nodes in graph 786 */ 787 void CyclicStructureAnalysis_BFSToNextCycle(ofstream *out, atom *&Root, atom *&Walker, int *&MinimumRingSize, int AtomCount) 788 { 789 struct BFSAccounting BFS; 790 atom *OtherAtom = Walker; 791 792 InitializeBFSAccounting(out, BFS, AtomCount); 793 794 ResetBFSAccounting(out, Walker, BFS); 795 while (OtherAtom != NULL) { // look for Root 796 Walker = BFS.BFSStack->PopFirst(); 797 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl; 798 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) { 799 // "removed (*Runner) != BackEdge) || " from next if, is u 800 if ((Walker->ListOfBonds.size() == 1)) { // only walk along DFS spanning tree (otherwise we always find SP of 1 being backedge Binder), but terminal hydrogens may be connected via backedge, hence extra check 801 OtherAtom = (*Runner)->GetOtherAtom(Walker); 802 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl; 803 if (BFS.ColorList[OtherAtom->nr] == white) { 804 BFS.TouchedStack->Push(OtherAtom); 805 BFS.ColorList[OtherAtom->nr] = lightgray; 806 BFS.PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor 807 BFS.ShortestPathList[OtherAtom->nr] = BFS.ShortestPathList[Walker->nr] + 1; 808 //*out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl; 809 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring 810 MinimumRingSize[Root->GetTrueFather()->nr] = BFS.ShortestPathList[OtherAtom->nr] + MinimumRingSize[OtherAtom->GetTrueFather()->nr]; 811 OtherAtom = NULL; //break; 812 break; 813 } else 814 BFS.BFSStack->Push(OtherAtom); 815 } else { 816 //*out << Verbose(3) << "Not Adding, has already been visited." << endl; 817 } 818 } else { 819 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl; 820 } 821 } 822 BFS.ColorList[Walker->nr] = black; 823 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl; 824 } 825 //CleanAccountingLists(TouchedStack, PredecessorList, ShortestPathList, ColorList); 826 827 FinalizeBFSAccounting(out, BFS); 828 } 829 ; 830 831 /** All nodes that are not in cycles get assigned a \a *&MinimumRingSizeby BFS to next cycle. 832 * \param *out output stream for debugging 833 * \param *&MinimumRingSize array with minimum distance without encountering onself for each atom 834 * \param &MinRingSize global minium distance 835 * \param &NumCyles number of cycles in graph 836 * \param *mol molecule with atoms 837 */ 838 void CyclicStructureAnalysis_AssignRingSizetoNonCycleMembers(ofstream *out, int *&MinimumRingSize, int &MinRingSize, int &NumCycles, const molecule * const mol) 839 { 840 atom *Root = NULL; 841 atom *Walker = NULL; 842 if (MinRingSize != -1) { // if rings are present 843 // go over all atoms 844 Root = mol->start; 845 while (Root->next != mol->end) { 846 Root = Root->next; 847 848 if (MinimumRingSize[Root->GetTrueFather()->nr] == mol->AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is 849 Walker = Root; 850 851 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl; 852 CyclicStructureAnalysis_BFSToNextCycle(out, Root, Walker, MinimumRingSize, mol->AtomCount); 853 854 } 855 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl; 856 } 857 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl; 858 } else 859 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl; 860 } 861 ; 517 862 518 863 /** Analyses the cycles found and returns minimum of all cycle lengths. … … 526 871 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond 527 872 */ 528 void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize) 529 { 530 atom **PredecessorList = Malloc<atom*>(AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList"); 531 int *ShortestPathList = Malloc<int>(AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList"); 532 enum Shading *ColorList = Malloc<enum Shading>(AtomCount, "molecule::CyclicStructureAnalysis: *ColorList"); 533 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount); // will hold the current ring 534 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount); // contains all "touched" atoms (that need to be reset after BFS loop) 535 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL; 536 bond *Binder = NULL, *BackEdge = NULL; 537 int RingSize, NumCycles, MinRingSize = -1; 538 539 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray 540 for (int i=AtomCount;i--;) { 541 PredecessorList[i] = NULL; 542 ShortestPathList[i] = -1; 543 ColorList[i] = white; 544 } 545 546 *out << Verbose(1) << "Back edge list - "; 547 BackEdgeStack->Output(out); 873 void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize) const 874 { 875 struct BFSAccounting BFS; 876 atom *Walker = NULL; 877 atom *OtherAtom = NULL; 878 bond *BackEdge = NULL; 879 int NumCycles = 0; 880 int MinRingSize = -1; 881 882 InitializeBFSAccounting(out, BFS, AtomCount); 883 884 //*out << Verbose(1) << "Back edge list - "; 885 //BackEdgeStack->Output(out); 548 886 549 887 *out << Verbose(1) << "Analysing cycles ... " << endl; … … 552 890 BackEdge = BackEdgeStack->PopFirst(); 553 891 // this is the target 554 Root = BackEdge->leftatom;892 BFS.Root = BackEdge->leftatom; 555 893 // this is the source point 556 894 Walker = BackEdge->rightatom; 557 ShortestPathList[Walker->nr] = 0; 558 BFSStack->ClearStack(); // start with empty BFS stack 559 BFSStack->Push(Walker); 560 TouchedStack->Push(Walker); 895 896 ResetBFSAccounting(out, Walker, BFS); 897 561 898 *out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl; 562 899 OtherAtom = NULL; 563 do { // look for Root 564 Walker = BFSStack->PopFirst(); 565 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl; 566 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { 567 Binder = ListOfBondsPerAtom[Walker->nr][i]; 568 if (Binder != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder) 569 OtherAtom = Binder->GetOtherAtom(Walker); 570 #ifdef ADDHYDROGEN 571 if (OtherAtom->type->Z != 1) { 572 #endif 573 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl; 574 if (ColorList[OtherAtom->nr] == white) { 575 TouchedStack->Push(OtherAtom); 576 ColorList[OtherAtom->nr] = lightgray; 577 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor 578 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1; 579 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl; 580 //if (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance 581 *out << Verbose(3) << "Putting OtherAtom into queue." << endl; 582 BFSStack->Push(OtherAtom); 583 //} 584 } else { 585 *out << Verbose(3) << "Not Adding, has already been visited." << endl; 586 } 587 if (OtherAtom == Root) 588 break; 589 #ifdef ADDHYDROGEN 590 } else { 591 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl; 592 ColorList[OtherAtom->nr] = black; 593 } 594 #endif 595 } else { 596 *out << Verbose(2) << "Bond " << *Binder << " not Visiting, is the back edge." << endl; 597 } 598 } 599 ColorList[Walker->nr] = black; 600 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl; 601 if (OtherAtom == Root) { // if we have found the root, check whether this cycle wasn't already found beforehand 602 // step through predecessor list 603 while (OtherAtom != BackEdge->rightatom) { 604 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet 605 break; 606 else 607 OtherAtom = PredecessorList[OtherAtom->nr]; 608 } 609 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already 610 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl;\ 611 do { 612 OtherAtom = TouchedStack->PopLast(); 613 if (PredecessorList[OtherAtom->nr] == Walker) { 614 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl; 615 PredecessorList[OtherAtom->nr] = NULL; 616 ShortestPathList[OtherAtom->nr] = -1; 617 ColorList[OtherAtom->nr] = white; 618 BFSStack->RemoveItem(OtherAtom); 619 } 620 } while ((!TouchedStack->IsEmpty()) && (PredecessorList[OtherAtom->nr] == NULL)); 621 TouchedStack->Push(OtherAtom); // last was wrongly popped 622 OtherAtom = BackEdge->rightatom; // set to not Root 623 } else 624 OtherAtom = Root; 625 } 626 } while ((!BFSStack->IsEmpty()) && (OtherAtom != Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]))); 627 628 if (OtherAtom == Root) { 629 // now climb back the predecessor list and thus find the cycle members 630 NumCycles++; 631 RingSize = 1; 632 Root->GetTrueFather()->IsCyclic = true; 633 *out << Verbose(1) << "Found ring contains: "; 634 Walker = Root; 635 while (Walker != BackEdge->rightatom) { 636 *out << Walker->Name << " <-> "; 637 Walker = PredecessorList[Walker->nr]; 638 Walker->GetTrueFather()->IsCyclic = true; 639 RingSize++; 640 } 641 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl; 642 // walk through all and set MinimumRingSize 643 Walker = Root; 644 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize; 645 while (Walker != BackEdge->rightatom) { 646 Walker = PredecessorList[Walker->nr]; 647 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr]) 648 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize; 649 } 650 if ((RingSize < MinRingSize) || (MinRingSize == -1)) 651 MinRingSize = RingSize; 652 } else { 653 *out << Verbose(1) << "No ring containing " << *Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl; 654 } 655 656 // now clean the lists 657 while (!TouchedStack->IsEmpty()){ 658 Walker = TouchedStack->PopFirst(); 659 PredecessorList[Walker->nr] = NULL; 660 ShortestPathList[Walker->nr] = -1; 661 ColorList[Walker->nr] = white; 662 } 663 } 664 if (MinRingSize != -1) { 665 // go over all atoms 666 Root = start; 667 while(Root->next != end) { 668 Root = Root->next; 669 670 if (MinimumRingSize[Root->GetTrueFather()->nr] == AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is 671 Walker = Root; 672 ShortestPathList[Walker->nr] = 0; 673 BFSStack->ClearStack(); // start with empty BFS stack 674 BFSStack->Push(Walker); 675 TouchedStack->Push(Walker); 676 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl; 677 OtherAtom = Walker; 678 while (OtherAtom != NULL) { // look for Root 679 Walker = BFSStack->PopFirst(); 680 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl; 681 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { 682 Binder = ListOfBondsPerAtom[Walker->nr][i]; 683 if ((Binder != BackEdge) || (NumberOfBondsPerAtom[Walker->nr] == 1)) { // only walk along DFS spanning tree (otherwise we always find SP of 1 being backedge Binder), but terminal hydrogens may be connected via backedge, hence extra check 684 OtherAtom = Binder->GetOtherAtom(Walker); 685 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl; 686 if (ColorList[OtherAtom->nr] == white) { 687 TouchedStack->Push(OtherAtom); 688 ColorList[OtherAtom->nr] = lightgray; 689 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor 690 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1; 691 //*out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl; 692 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring 693 MinimumRingSize[Root->GetTrueFather()->nr] = ShortestPathList[OtherAtom->nr]+MinimumRingSize[OtherAtom->GetTrueFather()->nr]; 694 OtherAtom = NULL; //break; 695 break; 696 } else 697 BFSStack->Push(OtherAtom); 698 } else { 699 //*out << Verbose(3) << "Not Adding, has already been visited." << endl; 700 } 701 } else { 702 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl; 703 } 704 } 705 ColorList[Walker->nr] = black; 706 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl; 707 } 708 709 // now clean the lists 710 while (!TouchedStack->IsEmpty()){ 711 Walker = TouchedStack->PopFirst(); 712 PredecessorList[Walker->nr] = NULL; 713 ShortestPathList[Walker->nr] = -1; 714 ColorList[Walker->nr] = white; 715 } 716 } 717 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl; 718 } 719 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl; 720 } else 721 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl; 722 723 Free(&PredecessorList); 724 Free(&ShortestPathList); 725 Free(&ColorList); 726 delete(BFSStack); 900 CyclicStructureAnalysis_CyclicBFSFromRootToRoot(out, BackEdge, BFS); 901 902 CyclicStructureAnalysis_RetrieveCycleMembers(out, OtherAtom, BackEdge, BFS, MinimumRingSize, MinRingSize); 903 904 CleanBFSAccounting(out, BFS); 905 } 906 FinalizeBFSAccounting(out, BFS); 907 908 CyclicStructureAnalysis_AssignRingSizetoNonCycleMembers(out, MinimumRingSize, MinRingSize, NumCycles, this); 727 909 }; 728 910 … … 732 914 * \param nr number to use 733 915 */ 734 void molecule::SetNextComponentNumber(atom *vertex, int nr) 735 { 736 int i=0;916 void molecule::SetNextComponentNumber(atom *vertex, int nr) const 917 { 918 size_t i = 0; 737 919 if (vertex != NULL) { 738 for (;i<NumberOfBondsPerAtom[vertex->nr];i++) {739 if (vertex->ComponentNr[i] == -1) { 920 for (; i < vertex->ListOfBonds.size(); i++) { 921 if (vertex->ComponentNr[i] == -1) { // check if not yet used 740 922 vertex->ComponentNr[i] = nr; 741 923 break; 742 } 743 else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time 744 break; // breaking here will not cause error! 745 } 746 if (i == NumberOfBondsPerAtom[vertex->nr]) 924 } else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time 925 break; // breaking here will not cause error! 926 } 927 if (i == vertex->ListOfBonds.size()) 747 928 cerr << "Error: All Component entries are already occupied!" << endl; 748 929 } else 749 cerr << "Error: Given vertex is NULL!" << endl; 750 }; 751 752 /** Output a list of flags, stating whether the bond was visited or not. 753 * \param *out output stream for debugging 754 */ 755 void molecule::OutputComponentNumber(ofstream *out, atom *vertex) 756 { 757 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++) 758 *out << vertex->ComponentNr[i] << " "; 759 }; 760 761 /** Allocates memory for all atom::*ComponentNr in this molecule and sets each entry to -1. 762 */ 763 void molecule::InitComponentNumbers() 764 { 765 atom *Walker = start; 766 while(Walker->next != end) { 767 Walker = Walker->next; 768 if (Walker->ComponentNr != NULL) 769 Free(&Walker->ComponentNr); 770 Walker->ComponentNr = Malloc<int>(NumberOfBondsPerAtom[Walker->nr], "molecule::InitComponentNumbers: *Walker->ComponentNr"); 771 for (int i=NumberOfBondsPerAtom[Walker->nr];i--;) 772 Walker->ComponentNr[i] = -1; 773 } 774 }; 930 cerr << "Error: Given vertex is NULL!" << endl; 931 } 932 ; 775 933 776 934 /** Returns next unused bond for this atom \a *vertex or NULL of none exists. … … 778 936 * \return bond class or NULL 779 937 */ 780 bond * molecule::FindNextUnused(atom *vertex) 781 { 782 for (int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)783 if ( ListOfBondsPerAtom[vertex->nr][i]->IsUsed() == white)784 return (ListOfBondsPerAtom[vertex->nr][i]);938 bond * molecule::FindNextUnused(atom *vertex) const 939 { 940 for (BondList::const_iterator Runner = vertex->ListOfBonds.begin(); Runner != vertex->ListOfBonds.end(); (++Runner)) 941 if ((*Runner)->IsUsed() == white) 942 return ((*Runner)); 785 943 return NULL; 786 }; 944 } 945 ; 787 946 788 947 /** Resets bond::Used flag of all bonds in this molecule. 789 948 * \return true - success, false - -failure 790 949 */ 791 void molecule::ResetAllBondsToUnused() 950 void molecule::ResetAllBondsToUnused() const 792 951 { 793 952 bond *Binder = first; … … 796 955 Binder->ResetUsed(); 797 956 } 798 }; 799 800 /** Resets atom::nr to -1 of all atoms in this molecule. 801 */ 802 void molecule::ResetAllAtomNumbers() 803 { 804 atom *Walker = start; 805 while (Walker->next != end) { 806 Walker = Walker->next; 807 Walker->GraphNr = -1; 808 } 809 }; 957 } 958 ; 810 959 811 960 /** Output a list of flags, stating whether the bond was visited or not. … … 816 965 { 817 966 *out << Verbose(4) << "Already Visited Bonds:\t"; 818 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << " "; 967 for (int i = 1; i <= list[0]; i++) 968 *out << Verbose(0) << list[i] << " "; 819 969 *out << endl; 820 } ;821 970 } 971 ; 822 972 823 973 /** Storing the bond structure of a molecule to file. … … 830 980 { 831 981 ofstream AdjacencyFile; 832 atom *Walker = NULL;833 982 stringstream line; 834 983 bool status = true; … … 838 987 *out << Verbose(1) << "Saving adjacency list ... "; 839 988 if (AdjacencyFile != NULL) { 840 Walker = start; 841 while(Walker->next != end) { 842 Walker = Walker->next; 843 AdjacencyFile << Walker->nr << "\t"; 844 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) 845 AdjacencyFile << ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker)->nr << "\t"; 846 AdjacencyFile << endl; 847 } 989 ActOnAllAtoms(&atom::OutputAdjacency, &AdjacencyFile); 848 990 AdjacencyFile.close(); 849 991 *out << Verbose(1) << "done." << endl; … … 854 996 855 997 return status; 856 }; 998 } 999 ; 1000 1001 bool CheckAdjacencyFileAgainstMolecule_Init(ofstream *out, char *path, ifstream &File, int *&CurrentBonds) 1002 { 1003 stringstream filename; 1004 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE; 1005 File.open(filename.str().c_str(), ios::out); 1006 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... "; 1007 if (File == NULL) 1008 return false; 1009 1010 // allocate storage structure 1011 CurrentBonds = Calloc<int> (8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom 1012 return true; 1013 } 1014 ; 1015 1016 void CheckAdjacencyFileAgainstMolecule_Finalize(ofstream *out, ifstream &File, int *&CurrentBonds) 1017 { 1018 File.close(); 1019 File.clear(); 1020 Free(&CurrentBonds); 1021 } 1022 ; 1023 1024 void CheckAdjacencyFileAgainstMolecule_CompareBonds(ofstream *out, bool &status, int &NonMatchNumber, atom *&Walker, size_t &CurrentBondsOfAtom, int AtomNr, int *&CurrentBonds, atom **ListOfAtoms) 1025 { 1026 size_t j = 0; 1027 int id = -1; 1028 1029 //*out << Verbose(2) << "Walker is " << *Walker << ", bond partners: "; 1030 if (CurrentBondsOfAtom == Walker->ListOfBonds.size()) { 1031 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) { 1032 id = (*Runner)->GetOtherAtom(Walker)->nr; 1033 j = 0; 1034 for (; (j < CurrentBondsOfAtom) && (CurrentBonds[j++] != id);) 1035 ; // check against all parsed bonds 1036 if (CurrentBonds[j - 1] != id) { // no match ? Then mark in ListOfAtoms 1037 ListOfAtoms[AtomNr] = NULL; 1038 NonMatchNumber++; 1039 status = false; 1040 //*out << "[" << id << "]\t"; 1041 } else { 1042 //*out << id << "\t"; 1043 } 1044 } 1045 //*out << endl; 1046 } else { 1047 *out << "Number of bonds for Atom " << *Walker << " does not match, parsed " << CurrentBondsOfAtom << " against " << Walker->ListOfBonds.size() << "." << endl; 1048 status = false; 1049 } 1050 } 1051 ; 857 1052 858 1053 /** Checks contents of adjacency file against bond structure in structure molecule. … … 865 1060 { 866 1061 ifstream File; 867 stringstream filename;868 1062 bool status = true; 869 char *buffer = Malloc<char>(MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer"); 870 871 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE; 872 File.open(filename.str().c_str(), ios::out); 873 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... "; 874 if (File != NULL) { 875 // allocate storage structure 876 int NonMatchNumber = 0; // will number of atoms with differing bond structure 877 int *CurrentBonds = Malloc<int>(8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom 878 int CurrentBondsOfAtom; 879 880 // Parse the file line by line and count the bonds 881 while (!File.eof()) { 882 File.getline(buffer, MAXSTRINGSIZE); 883 stringstream line; 884 line.str(buffer); 885 int AtomNr = -1; 886 line >> AtomNr; 887 CurrentBondsOfAtom = -1; // we count one too far due to line end 888 // parse into structure 889 if ((AtomNr >= 0) && (AtomNr < AtomCount)) { 890 while (!line.eof()) 891 line >> CurrentBonds[ ++CurrentBondsOfAtom ]; 892 // compare against present bonds 893 //cout << Verbose(2) << "Walker is " << *Walker << ", bond partners: "; 894 if (CurrentBondsOfAtom == NumberOfBondsPerAtom[AtomNr]) { 895 for(int i=0;i<NumberOfBondsPerAtom[AtomNr];i++) { 896 int id = ListOfBondsPerAtom[AtomNr][i]->GetOtherAtom(ListOfAtoms[AtomNr])->nr; 897 int j = 0; 898 for (;(j<CurrentBondsOfAtom) && (CurrentBonds[j++] != id);); // check against all parsed bonds 899 if (CurrentBonds[j-1] != id) { // no match ? Then mark in ListOfAtoms 900 ListOfAtoms[AtomNr] = NULL; 901 NonMatchNumber++; 902 status = false; 903 //out << "[" << id << "]\t"; 904 } else { 905 //out << id << "\t"; 906 } 907 } 908 //out << endl; 909 } else { 910 *out << "Number of bonds for Atom " << *ListOfAtoms[AtomNr] << " does not match, parsed " << CurrentBondsOfAtom << " against " << NumberOfBondsPerAtom[AtomNr] << "." << endl; 911 status = false; 912 } 913 } 914 } 915 File.close(); 916 File.clear(); 917 if (status) { // if equal we parse the KeySetFile 918 *out << Verbose(1) << "done: Equal." << endl; 919 status = true; 920 } else 921 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl; 922 Free(&CurrentBonds); 923 } else { 1063 atom *Walker = NULL; 1064 char *buffer = NULL; 1065 int *CurrentBonds = NULL; 1066 int NonMatchNumber = 0; // will number of atoms with differing bond structure 1067 size_t CurrentBondsOfAtom = -1; 1068 1069 if (!CheckAdjacencyFileAgainstMolecule_Init(out, path, File, CurrentBonds)) { 924 1070 *out << Verbose(1) << "Adjacency file not found." << endl; 925 status = false; 926 } 927 *out << endl; 1071 return true; 1072 } 1073 1074 buffer = Malloc<char> (MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer"); 1075 // Parse the file line by line and count the bonds 1076 while (!File.eof()) { 1077 File.getline(buffer, MAXSTRINGSIZE); 1078 stringstream line; 1079 line.str(buffer); 1080 int AtomNr = -1; 1081 line >> AtomNr; 1082 CurrentBondsOfAtom = -1; // we count one too far due to line end 1083 // parse into structure 1084 if ((AtomNr >= 0) && (AtomNr < AtomCount)) { 1085 Walker = ListOfAtoms[AtomNr]; 1086 while (!line.eof()) 1087 line >> CurrentBonds[++CurrentBondsOfAtom]; 1088 // compare against present bonds 1089 CheckAdjacencyFileAgainstMolecule_CompareBonds(out, status, NonMatchNumber, Walker, CurrentBondsOfAtom, AtomNr, CurrentBonds, ListOfAtoms); 1090 } 1091 } 928 1092 Free(&buffer); 929 1093 CheckAdjacencyFileAgainstMolecule_Finalize(out, File, CurrentBonds); 1094 1095 if (status) { // if equal we parse the KeySetFile 1096 *out << Verbose(1) << "done: Equal." << endl; 1097 } else 1098 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl; 930 1099 return status; 931 } ;932 1100 } 1101 ; 933 1102 934 1103 /** Picks from a global stack with all back edges the ones in the fragment. … … 939 1108 * \return true - everything ok, false - ReferenceStack was empty 940 1109 */ 941 bool molecule::PickLocalBackEdges(ofstream *out, atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack) 1110 bool molecule::PickLocalBackEdges(ofstream *out, atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack) const 942 1111 { 943 1112 bool status = true; … … 947 1116 } 948 1117 bond *Binder = ReferenceStack->PopFirst(); 949 bond *FirstBond = Binder; 1118 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely 950 1119 atom *Walker = NULL, *OtherAtom = NULL; 951 1120 ReferenceStack->Push(Binder); 952 1121 953 do { 954 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; 1122 do { // go through all bonds and push local ones 1123 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule 955 1124 if (Walker != NULL) // if this Walker exists in the subgraph ... 956 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through the local list of bonds957 OtherAtom = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);958 if (OtherAtom == ListOfLocalAtoms[ Binder->rightatom->nr]) { // found the bond959 LocalStack->Push( ListOfBondsPerAtom[Walker->nr][i]);960 *out << Verbose(3) << "Found local edge " << *( ListOfBondsPerAtom[Walker->nr][i]) << "." << endl;1125 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) { 1126 OtherAtom = (*Runner)->GetOtherAtom(Walker); 1127 if (OtherAtom == ListOfLocalAtoms[(*Runner)->rightatom->nr]) { // found the bond 1128 LocalStack->Push((*Runner)); 1129 *out << Verbose(3) << "Found local edge " << *(*Runner) << "." << endl; 961 1130 break; 962 1131 } 963 1132 } 964 Binder = ReferenceStack->PopFirst(); 1133 Binder = ReferenceStack->PopFirst(); // loop the stack for next item 965 1134 *out << Verbose(3) << "Current candidate edge " << Binder << "." << endl; 966 1135 ReferenceStack->Push(Binder); … … 968 1137 969 1138 return status; 970 }; 971 1139 } 1140 ; 1141 1142 void BreadthFirstSearchAdd_Init(struct BFSAccounting &BFS, atom *&Root, int AtomCount, int BondOrder, atom **AddedAtomList = NULL) 1143 { 1144 BFS.AtomCount = AtomCount; 1145 BFS.BondOrder = BondOrder; 1146 BFS.PredecessorList = Calloc<atom*> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: **PredecessorList"); 1147 BFS.ShortestPathList = Calloc<int> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ShortestPathList"); 1148 BFS.ColorList = Malloc<enum Shading> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ColorList"); 1149 BFS.BFSStack = new StackClass<atom *> (AtomCount); 1150 1151 BFS.Root = Root; 1152 BFS.BFSStack->ClearStack(); 1153 BFS.BFSStack->Push(Root); 1154 1155 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray 1156 for (int i = AtomCount; i--;) { 1157 BFS.ShortestPathList[i] = -1; 1158 if ((AddedAtomList != NULL) && (AddedAtomList[i] != NULL)) // mark already present atoms (i.e. Root and maybe others) as visited 1159 BFS.ColorList[i] = lightgray; 1160 else 1161 BFS.ColorList[i] = white; 1162 } 1163 //BFS.ShortestPathList[Root->nr] = 0; //is set due to Calloc() 1164 } 1165 ; 1166 1167 void BreadthFirstSearchAdd_Free(struct BFSAccounting &BFS) 1168 { 1169 Free(&BFS.PredecessorList); 1170 Free(&BFS.ShortestPathList); 1171 Free(&BFS.ColorList); 1172 delete (BFS.BFSStack); 1173 BFS.AtomCount = 0; 1174 } 1175 ; 1176 1177 void BreadthFirstSearchAdd_UnvisitedNode(ofstream *out, molecule *Mol, struct BFSAccounting &BFS, atom *&Walker, atom *&OtherAtom, bond *&Binder, bond *&Bond, atom **&AddedAtomList, bond **&AddedBondList, bool IsAngstroem) 1178 { 1179 if (Binder != Bond) // let other atom white if it's via Root bond. In case it's cyclic it has to be reached again (yet Root is from OtherAtom already black, thus no problem) 1180 BFS.ColorList[OtherAtom->nr] = lightgray; 1181 BFS.PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor 1182 BFS.ShortestPathList[OtherAtom->nr] = BFS.ShortestPathList[Walker->nr] + 1; 1183 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " " << ((BFS.ColorList[OtherAtom->nr] == white) ? "white" : "lightgray") << ", its predecessor is " << Walker->Name << " and its Shortest Path is " << BFS.ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl; 1184 if ((((BFS.ShortestPathList[OtherAtom->nr] < BFS.BondOrder) && (Binder != Bond)))) { // Check for maximum distance 1185 *out << Verbose(3); 1186 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far 1187 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom); 1188 *out << "Added OtherAtom " << OtherAtom->Name; 1189 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder); 1190 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", "; 1191 } else { // this code should actually never come into play (all white atoms are not yet present in BondMolecule, that's why they are white in the first place) 1192 *out << "Not adding OtherAtom " << OtherAtom->Name; 1193 if (AddedBondList[Binder->nr] == NULL) { 1194 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder); 1195 *out << ", added Bond " << *(AddedBondList[Binder->nr]); 1196 } else 1197 *out << ", not added Bond "; 1198 } 1199 *out << ", putting OtherAtom into queue." << endl; 1200 BFS.BFSStack->Push(OtherAtom); 1201 } else { // out of bond order, then replace 1202 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic)) 1203 BFS.ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic) 1204 if (Binder == Bond) 1205 *out << Verbose(3) << "Not Queueing, is the Root bond"; 1206 else if (BFS.ShortestPathList[OtherAtom->nr] >= BFS.BondOrder) 1207 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BFS.BondOrder; 1208 if (!Binder->Cyclic) 1209 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl; 1210 if (AddedBondList[Binder->nr] == NULL) { 1211 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate 1212 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder); 1213 } else { 1214 #ifdef ADDHYDROGEN 1215 if (!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, IsAngstroem)) 1216 exit(1); 1217 #endif 1218 } 1219 } 1220 } 1221 } 1222 ; 1223 1224 void BreadthFirstSearchAdd_VisitedNode(ofstream *out, molecule *Mol, struct BFSAccounting &BFS, atom *&Walker, atom *&OtherAtom, bond *&Binder, bond *&Bond, atom **&AddedAtomList, bond **&AddedBondList, bool IsAngstroem) 1225 { 1226 *out << Verbose(3) << "Not Adding, has already been visited." << endl; 1227 // This has to be a cyclic bond, check whether it's present ... 1228 if (AddedBondList[Binder->nr] == NULL) { 1229 if ((Binder != Bond) && (Binder->Cyclic) && (((BFS.ShortestPathList[Walker->nr] + 1) < BFS.BondOrder))) { 1230 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder); 1231 } else { // if it's root bond it has to broken (otherwise we would not create the fragments) 1232 #ifdef ADDHYDROGEN 1233 if(!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, IsAngstroem)) 1234 exit(1); 1235 #endif 1236 } 1237 } 1238 } 1239 ; 972 1240 973 1241 /** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList. … … 985 1253 void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem) 986 1254 { 987 atom **PredecessorList = Malloc<atom*>(AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList"); 988 int *ShortestPathList = Malloc<int>(AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList"); 989 enum Shading *ColorList = Malloc<enum Shading>(AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList"); 990 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount); 1255 struct BFSAccounting BFS; 991 1256 atom *Walker = NULL, *OtherAtom = NULL; 992 1257 bond *Binder = NULL; 993 1258 994 1259 // add Root if not done yet 995 AtomStack->ClearStack(); 996 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present 1260 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present 997 1261 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root); 998 AtomStack->Push(Root); 999 1000 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray 1001 for (int i=AtomCount;i--;) { 1002 PredecessorList[i] = NULL; 1003 ShortestPathList[i] = -1; 1004 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited 1005 ColorList[i] = lightgray; 1006 else 1007 ColorList[i] = white; 1008 } 1009 ShortestPathList[Root->nr] = 0; 1262 1263 BreadthFirstSearchAdd_Init(BFS, Root, BondOrder, AtomCount, AddedAtomList); 1010 1264 1011 1265 // and go on ... Queue always contains all lightgray vertices 1012 while (! AtomStack->IsEmpty()) {1266 while (!BFS.BFSStack->IsEmpty()) { 1013 1267 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance. 1014 1268 // 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 1015 1269 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and 1016 1270 // followed by n+1 till top of stack. 1017 Walker = AtomStack->PopFirst(); // pop oldest added 1018 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << NumberOfBondsPerAtom[Walker->nr] << " bonds." << endl; 1019 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { 1020 Binder = ListOfBondsPerAtom[Walker->nr][i]; 1021 if (Binder != NULL) { // don't look at bond equal NULL 1022 OtherAtom = Binder->GetOtherAtom(Walker); 1023 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl; 1024 if (ColorList[OtherAtom->nr] == white) { 1025 if (Binder != Bond) // let other atom white if it's via Root bond. In case it's cyclic it has to be reached again (yet Root is from OtherAtom already black, thus no problem) 1026 ColorList[OtherAtom->nr] = lightgray; 1027 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor 1028 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1; 1029 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " " << ((ColorList[OtherAtom->nr] == white) ? "white" : "lightgray") << ", its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl; 1030 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && (Binder != Bond))) ) { // Check for maximum distance 1031 *out << Verbose(3); 1032 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far 1033 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom); 1034 *out << "Added OtherAtom " << OtherAtom->Name; 1035 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree); 1036 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic; 1037 AddedBondList[Binder->nr]->Type = Binder->Type; 1038 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", "; 1039 } else { // this code should actually never come into play (all white atoms are not yet present in BondMolecule, that's why they are white in the first place) 1040 *out << "Not adding OtherAtom " << OtherAtom->Name; 1041 if (AddedBondList[Binder->nr] == NULL) { 1042 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree); 1043 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic; 1044 AddedBondList[Binder->nr]->Type = Binder->Type; 1045 *out << ", added Bond " << *(AddedBondList[Binder->nr]); 1046 } else 1047 *out << ", not added Bond "; 1048 } 1049 *out << ", putting OtherAtom into queue." << endl; 1050 AtomStack->Push(OtherAtom); 1051 } else { // out of bond order, then replace 1052 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic)) 1053 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic) 1054 if (Binder == Bond) 1055 *out << Verbose(3) << "Not Queueing, is the Root bond"; 1056 else if (ShortestPathList[OtherAtom->nr] >= BondOrder) 1057 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder; 1058 if (!Binder->Cyclic) 1059 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl; 1060 if (AddedBondList[Binder->nr] == NULL) { 1061 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate 1062 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree); 1063 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic; 1064 AddedBondList[Binder->nr]->Type = Binder->Type; 1065 } else { 1066 #ifdef ADDHYDROGEN 1067 if (!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem)) 1068 exit(1); 1069 #endif 1070 } 1071 } 1072 } 1271 Walker = BFS.BFSStack->PopFirst(); // pop oldest added 1272 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << Walker->ListOfBonds.size() << " bonds." << endl; 1273 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) { 1274 if ((*Runner) != NULL) { // don't look at bond equal NULL 1275 Binder = (*Runner); 1276 OtherAtom = (*Runner)->GetOtherAtom(Walker); 1277 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *(*Runner) << "." << endl; 1278 if (BFS.ColorList[OtherAtom->nr] == white) { 1279 BreadthFirstSearchAdd_UnvisitedNode(out, Mol, BFS, Walker, OtherAtom, Binder, Bond, AddedAtomList, AddedBondList, IsAngstroem); 1073 1280 } else { 1074 *out << Verbose(3) << "Not Adding, has already been visited." << endl; 1075 // This has to be a cyclic bond, check whether it's present ... 1076 if (AddedBondList[Binder->nr] == NULL) { 1077 if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) { 1078 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree); 1079 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic; 1080 AddedBondList[Binder->nr]->Type = Binder->Type; 1081 } else { // if it's root bond it has to broken (otherwise we would not create the fragments) 1082 #ifdef ADDHYDROGEN 1083 if(!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem)) 1084 exit(1); 1085 #endif 1086 } 1087 } 1281 BreadthFirstSearchAdd_VisitedNode(out, Mol, BFS, Walker, OtherAtom, Binder, Bond, AddedAtomList, AddedBondList, IsAngstroem); 1088 1282 } 1089 1283 } 1090 1284 } 1091 ColorList[Walker->nr] = black;1285 BFS.ColorList[Walker->nr] = black; 1092 1286 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl; 1093 1287 } 1094 Free(&PredecessorList); 1095 Free(&ShortestPathList); 1096 Free(&ColorList); 1097 delete(AtomStack); 1098 }; 1099 1100 /** Adds bond structure to this molecule from \a Father molecule. 1101 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father 1102 * with end points present in this molecule, bond is created in this molecule. 1103 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount. 1104 * \param *out output stream for debugging 1105 * \param *Father father molecule 1106 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father 1107 * \todo not checked, not fully working probably 1108 */ 1109 bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father) 1110 { 1111 atom *Walker = NULL, *OtherAtom = NULL; 1112 bool status = true; 1113 atom **ParentList = Malloc<atom*>(Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList"); 1114 1115 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl; 1116 1288 BreadthFirstSearchAdd_Free(BFS); 1289 } 1290 ; 1291 1292 /** Adds a bond as a copy to a given one 1293 * \param *left leftatom of new bond 1294 * \param *right rightatom of new bond 1295 * \param *CopyBond rest of fields in bond are copied from this 1296 * \return pointer to new bond 1297 */ 1298 bond * molecule::CopyBond(atom *left, atom *right, bond *CopyBond) 1299 { 1300 bond *Binder = AddBond(left, right, CopyBond->BondDegree); 1301 Binder->Cyclic = CopyBond->Cyclic; 1302 Binder->Type = CopyBond->Type; 1303 return Binder; 1304 } 1305 ; 1306 1307 void BuildInducedSubgraph_Init(ofstream *out, atom **&ParentList, int AtomCount) 1308 { 1117 1309 // reset parent list 1310 ParentList = Calloc<atom*> (AtomCount, "molecule::BuildInducedSubgraph_Init: **ParentList"); 1118 1311 *out << Verbose(3) << "Resetting ParentList." << endl; 1119 for (int i=Father->AtomCount;i--;) 1120 ParentList[i] = NULL; 1121 1312 } 1313 ; 1314 1315 void BuildInducedSubgraph_FillParentList(ofstream *out, const molecule *mol, const molecule *Father, atom **&ParentList) 1316 { 1122 1317 // fill parent list with sons 1123 1318 *out << Verbose(3) << "Filling Parent List." << endl; 1124 Walker =start;1125 while (Walker->next != end) {1319 atom *Walker = mol->start; 1320 while (Walker->next != mol->end) { 1126 1321 Walker = Walker->next; 1127 1322 ParentList[Walker->father->nr] = Walker; 1128 1323 // Outputting List for debugging 1129 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl; 1130 } 1131 1324 *out << Verbose(4) << "Son[" << Walker->father->nr << "] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl; 1325 } 1326 1327 } 1328 ; 1329 1330 void BuildInducedSubgraph_Finalize(ofstream *out, atom **&ParentList) 1331 { 1332 Free(&ParentList); 1333 } 1334 ; 1335 1336 bool BuildInducedSubgraph_CreateBondsFromParent(ofstream *out, molecule *mol, const molecule *Father, atom **&ParentList) 1337 { 1338 bool status = true; 1339 atom *Walker = NULL; 1340 atom *OtherAtom = NULL; 1132 1341 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds 1133 1342 *out << Verbose(3) << "Creating bonds." << endl; … … 1139 1348 status = false; 1140 1349 } else { 1141 for ( int i=0;i<Father->NumberOfBondsPerAtom[Walker->nr];i++) {1142 OtherAtom = Father->ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);1350 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) { 1351 OtherAtom = (*Runner)->GetOtherAtom(Walker); 1143 1352 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond 1144 *out << Verbose(4) << "Endpoints of Bond " << Father->ListOfBondsPerAtom[Walker->nr][i]<< " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;1145 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], Father->ListOfBondsPerAtom[Walker->nr][i]->BondDegree);1353 *out << Verbose(4) << "Endpoints of Bond " << (*Runner) << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl; 1354 mol->AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], (*Runner)->BondDegree); 1146 1355 } 1147 1356 } … … 1149 1358 } 1150 1359 } 1151 1152 Free(&ParentList); 1360 return status; 1361 } 1362 ; 1363 1364 /** Adds bond structure to this molecule from \a Father molecule. 1365 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father 1366 * with end points present in this molecule, bond is created in this molecule. 1367 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount. 1368 * \param *out output stream for debugging 1369 * \param *Father father molecule 1370 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father 1371 * \todo not checked, not fully working probably 1372 */ 1373 bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father) 1374 { 1375 bool status = true; 1376 atom **ParentList = NULL; 1377 1378 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl; 1379 BuildInducedSubgraph_Init(out, ParentList, Father->AtomCount); 1380 BuildInducedSubgraph_FillParentList(out, this, Father, ParentList); 1381 status = BuildInducedSubgraph_CreateBondsFromParent(out, this, Father, ParentList); 1382 BuildInducedSubgraph_Finalize(out, ParentList); 1153 1383 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl; 1154 1384 return status; 1155 } ;1156 1385 } 1386 ; 1157 1387 1158 1388 /** For a given keyset \a *Fragment, checks whether it is connected in the current molecule. … … 1173 1403 // count number of atoms in graph 1174 1404 size = 0; 1175 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)1405 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) 1176 1406 size++; 1177 1407 if (size > 1) 1178 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {1408 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) { 1179 1409 Walker = FindAtom(*runner); 1180 1410 BondStatus = false; 1181 for (KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {1411 for (KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) { 1182 1412 Walker2 = FindAtom(*runners); 1183 for ( int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {1184 if ( ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker) == Walker2) {1413 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) { 1414 if ((*Runner)->GetOtherAtom(Walker) == Walker2) { 1185 1415 BondStatus = true; 1186 1416 break;
Note:
See TracChangeset
for help on using the changeset viewer.