source: src/moleculelist.cpp@ 1907a7

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 Candidate_v1.7.0 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 1907a7 was 1907a7, checked in by Frederik Heber <heber@…>, 17 years ago

Basic implementation of Multiple molecules.

builder.cpp:

molecules.hpp:

moleculelist.cpp:

  • replaced listofmolecules array by STL list everywhere (only smaller changes necessary)
  • new merging function: SimpleMerge, SimpleAdd, SimpleMultiMerge, SimpleMultiAdd, (EmbedMerge, ScatterMerge ... both not finished). Add does not while merge does delete the src molecules.
  • new function: Enumerate(). Output of all molecules with number of atoms and chemical formula
  • new function: NumberOfActiveMolecules(). Counts the number of molecules in the list with ActiveFlag set.
  • new function: insert(). Inserts a molecule into the list with a unique index

molecules.cpp:

  • new function: SetNameFromFilename. Takes basename of a filename and sets name accordingly.
  • new function: UnlinkAtom. Only removes atom from list, does not delete it from memory.

atom.cpp:

  • Output() also accepts specific comment instead of "# molecule nr ..."
  • Property mode set to 100755
File size: 38.2 KB
Line 
1/** \file MoleculeListClass.cpp
2 *
3 * Function implementations for the class MoleculeListClass.
4 *
5 */
6
7#include "molecules.hpp"
8
9/*********************************** Functions for class MoleculeListClass *************************/
10
11/** Constructor for MoleculeListClass.
12 */
13MoleculeListClass::MoleculeListClass()
14{
15 // empty lists
16 ListOfMolecules.clear();
17 MaxIndex = 1;
18};
19
20/** Destructor for MoleculeListClass.
21 */
22MoleculeListClass::~MoleculeListClass()
23{
24 cout << Verbose(3) << this << ": Freeing ListOfMolcules." << endl;
25 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
26 cout << Verbose(4) << "ListOfMolecules: Freeing " << *ListRunner << "." << endl;
27 delete (*ListRunner);
28 }
29 cout << Verbose(4) << "Freeing ListOfMolecules." << endl;
30 ListOfMolecules.clear(); // empty list
31};
32
33/** Insert a new molecule into the list and set its number.
34 * \param *mol molecule to add to list.
35 * \return true - add successful
36 */
37bool MoleculeListClass::insert(molecule *mol)
38{
39 mol->IndexNr = MaxIndex++;
40 ListOfMolecules.push_back(mol);
41};
42
43/** Compare whether two molecules are equal.
44 * \param *a molecule one
45 * \param *n molecule two
46 * \return lexical value (-1, 0, +1)
47 */
48int MolCompare(const void *a, const void *b)
49{
50 int *aList = NULL, *bList = NULL;
51 int Count, Counter, aCounter, bCounter;
52 int flag;
53 atom *aWalker = NULL;
54 atom *bWalker = NULL;
55
56 // sort each atom list and put the numbers into a list, then go through
57 //cout << "Comparing fragment no. " << *(molecule **)a << " to " << *(molecule **)b << "." << endl;
58 if ((**(molecule **) a).AtomCount < (**(molecule **) b).AtomCount) {
59 return -1;
60 } else {
61 if ((**(molecule **) a).AtomCount > (**(molecule **) b).AtomCount)
62 return +1;
63 else {
64 Count = (**(molecule **) a).AtomCount;
65 aList = new int[Count];
66 bList = new int[Count];
67
68 // fill the lists
69 aWalker = (**(molecule **) a).start;
70 bWalker = (**(molecule **) b).start;
71 Counter = 0;
72 aCounter = 0;
73 bCounter = 0;
74 while ((aWalker->next != (**(molecule **) a).end) && (bWalker->next != (**(molecule **) b).end)) {
75 aWalker = aWalker->next;
76 bWalker = bWalker->next;
77 if (aWalker->GetTrueFather() == NULL)
78 aList[Counter] = Count + (aCounter++);
79 else
80 aList[Counter] = aWalker->GetTrueFather()->nr;
81 if (bWalker->GetTrueFather() == NULL)
82 bList[Counter] = Count + (bCounter++);
83 else
84 bList[Counter] = bWalker->GetTrueFather()->nr;
85 Counter++;
86 }
87 // check if AtomCount was for real
88 flag = 0;
89 if ((aWalker->next == (**(molecule **) a).end) && (bWalker->next != (**(molecule **) b).end)) {
90 flag = -1;
91 } else {
92 if ((aWalker->next != (**(molecule **) a).end) && (bWalker->next == (**(molecule **) b).end))
93 flag = 1;
94 }
95 if (flag == 0) {
96 // sort the lists
97 gsl_heapsort(aList, Count, sizeof(int), CompareDoubles);
98 gsl_heapsort(bList, Count, sizeof(int), CompareDoubles);
99 // compare the lists
100
101 flag = 0;
102 for (int i = 0; i < Count; i++) {
103 if (aList[i] < bList[i]) {
104 flag = -1;
105 } else {
106 if (aList[i] > bList[i])
107 flag = 1;
108 }
109 if (flag != 0)
110 break;
111 }
112 }
113 delete[] (aList);
114 delete[] (bList);
115 return flag;
116 }
117 }
118 return -1;
119};
120
121/** Output of a list of all molecules.
122 * \param *out output stream
123 */
124void MoleculeListClass::Enumerate(ofstream *out)
125{
126 int i=1;
127 element* Elemental = NULL;
128 atom *Walker = NULL;
129 int Counts[MAX_ELEMENTS];
130
131 // header
132 *out << "Index\tName\tNo.Atoms\tformula" << endl;
133 cout << Verbose(0) << "-----------------------------------------------" << endl;
134 if (ListOfMolecules.size() == 0)
135 *out << "\tNone" << endl;
136 else {
137 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
138 // reset element counts
139 for (int j = 0; j<MAX_ELEMENTS;j++)
140 Counts[j] = 0;
141 // count atoms per element
142 Walker = (*ListRunner)->start;
143 while (Walker->next != (*ListRunner)->end) {
144 Walker = Walker->next;
145 Counts[Walker->type->Z]++;
146 }
147 // output Index, Name, number of atoms, chemical formula
148 *out << ((*ListRunner)->ActiveFlag ? "*" : " ") << (*ListRunner)->IndexNr << "\t" << (*ListRunner)->name << "\t\t" << (*ListRunner)->AtomCount << "\t";
149 Elemental = (*ListRunner)->elemente->end;
150 while(Elemental != (*ListRunner)->elemente->start) {
151 Elemental = Elemental->previous;
152 if (Counts[Elemental->Z] != 0)
153 *out << Elemental->symbol << Counts[Elemental->Z];
154 }
155 *out << endl;
156 }
157 }
158};
159
160/** Returns the molecule with the given index \a index.
161 * \param index index of the desired molecule
162 * \return pointer to molecule structure, NULL if not found
163 */
164molecule * MoleculeListClass::ReturnIndex(int index)
165{
166 int count = 1;
167 MoleculeList::iterator ListRunner = ListOfMolecules.begin();
168 for(; ((ListRunner != ListOfMolecules.end()) && (count < index)); ListRunner++);
169 if (count == index)
170 return (*ListRunner);
171 else
172 return NULL;
173};
174
175/** Simple merge of two molecules into one.
176 * \param *mol destination molecule
177 * \param *srcmol source molecule
178 * \return true - merge successful, false - merge failed (probably due to non-existant indices
179 */
180bool MoleculeListClass::SimpleMerge(molecule *mol, molecule *srcmol)
181{
182 if (srcmol == NULL)
183 return false;
184
185 // put all molecules of src into mol
186 atom *Walker = srcmol->start;
187 atom *NextAtom = Walker->next;
188 while (NextAtom != srcmol->end) {
189 Walker = NextAtom;
190 NextAtom = Walker->next;
191 srcmol->UnlinkAtom(Walker);
192 mol->AddAtom(Walker);
193 }
194
195 // remove src
196 ListOfMolecules.remove(srcmol);
197 delete(srcmol);
198 return true;
199};
200
201/** Simple add of one molecules into another.
202 * \param *mol destination molecule
203 * \param *srcmol source molecule
204 * \return true - merge successful, false - merge failed (probably due to non-existant indices
205 */
206bool MoleculeListClass::SimpleAdd(molecule *mol, molecule *srcmol)
207{
208 if (srcmol == NULL)
209 return false;
210
211 // put all molecules of src into mol
212 atom *Walker = srcmol->start;
213 atom *NextAtom = Walker->next;
214 while (NextAtom != srcmol->end) {
215 Walker = NextAtom;
216 NextAtom = Walker->next;
217 Walker = mol->AddCopyAtom(Walker);
218 Walker->father = Walker;
219 }
220
221 return true;
222};
223
224/** Simple merge of a given set of molecules into one.
225 * \param *mol destination molecule
226 * \param *src index of set of source molecule
227 * \param N number of source molecules
228 * \return true - merge successful, false - some merges failed (probably due to non-existant indices)
229 */
230bool MoleculeListClass::SimpleMultiMerge(molecule *mol, int *src, int N)
231{
232 bool status = true;
233 // check presence of all source molecules
234 for (int i=0;i<N;i++) {
235 molecule *srcmol = ReturnIndex(src[i]);
236 status = status && SimpleMerge(mol, srcmol);
237 }
238 return status;
239};
240
241/** Simple add of a given set of molecules into one.
242 * \param *mol destination molecule
243 * \param *src index of set of source molecule
244 * \param N number of source molecules
245 * \return true - merge successful, false - some merges failed (probably due to non-existant indices)
246 */
247bool MoleculeListClass::SimpleMultiAdd(molecule *mol, int *src, int N)
248{
249 bool status = true;
250 // check presence of all source molecules
251 for (int i=0;i<N;i++) {
252 molecule *srcmol = ReturnIndex(src[i]);
253 status = status && SimpleAdd(mol, srcmol);
254 }
255 return status;
256};
257
258/** Scatter merge of a given set of molecules into one.
259 * Scatter merge distributes the molecules in such a manner that they don't overlap.
260 * \param *mol destination molecule
261 * \param *src index of set of source molecule
262 * \param N number of source molecules
263 * \return true - merge successful, false - merge failed (probably due to non-existant indices
264 * \TODO find scatter center for each src molecule
265 */
266bool MoleculeListClass::ScatterMerge(molecule *mol, int *src, int N)
267{
268 // check presence of all source molecules
269 for (int i=0;i<N;i++) {
270 // get pointer to src molecule
271 molecule *srcmol = ReturnIndex(src[i]);
272 if (srcmol == NULL)
273 return false;
274 }
275 // adapt each Center
276 for (int i=0;i<N;i++) {
277 // get pointer to src molecule
278 molecule *srcmol = ReturnIndex(src[i]);
279 //srcmol->Center.Zero();
280 srcmol->Translate(&srcmol->Center);
281 }
282 // perform a simple multi merge
283 SimpleMultiMerge(mol, src, N);
284 return true;
285};
286
287/** Embedding merge of a given set of molecules into one.
288 * Embedding merge inserts one molecule into the other.
289 * \param *mol destination molecule
290 * \param *srcmol source molecule
291 * \return true - merge successful, false - merge failed (probably due to non-existant indices
292 * \TODO find embedding center
293 */
294bool MoleculeListClass::EmbedMerge(molecule *mol, molecule *srcmol)
295{
296 if (srcmol == NULL)
297 return false;
298
299 // calculate center for merge
300 //srcmol->Center.Zero();
301
302 // perform simple merge
303 SimpleMerge(mol, srcmol);
304 return true;
305};
306
307/** Simple output of the pointers in ListOfMolecules.
308 * \param *out output stream
309 */
310void MoleculeListClass::Output(ofstream *out)
311{
312 *out << Verbose(1) << "MoleculeList: ";
313 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
314 *out << *ListRunner << "\t";
315 *out << endl;
316};
317
318/** Calculates necessary hydrogen correction due to unwanted interaction between saturated ones.
319 * If for a pair of two hydrogen atoms a and b, at least is a saturated one, and a and b are not
320 * bonded to the same atom, then we add for this pair a correction term constructed from a Morse
321 * potential function fit to QM calculations with respecting to the interatomic hydrogen distance.
322 * \param *out output stream for debugging
323 * \param *path path to file
324 */
325bool MoleculeListClass::AddHydrogenCorrection(ofstream *out, char *path)
326{
327 atom *Walker = NULL;
328 atom *Runner = NULL;
329 double ***FitConstant = NULL, **correction = NULL;
330 int a, b;
331 ofstream output;
332 ifstream input;
333 string line;
334 stringstream zeile;
335 double distance;
336 char ParsedLine[1023];
337 double tmp;
338 char *FragmentNumber = NULL;
339
340 cout << Verbose(1) << "Saving hydrogen saturation correction ... ";
341 // 0. parse in fit constant files that should have the same dimension as the final energy files
342 // 0a. find dimension of matrices with constants
343 line = path;
344 line.append("/");
345 line += FRAGMENTPREFIX;
346 line += "1";
347 line += FITCONSTANTSUFFIX;
348 input.open(line.c_str());
349 if (input == NULL) {
350 cerr << endl << "Unable to open " << line << ", is the directory correct?"
351 << endl;
352 return false;
353 }
354 a = 0;
355 b = -1; // we overcount by one
356 while (!input.eof()) {
357 input.getline(ParsedLine, 1023);
358 zeile.str(ParsedLine);
359 int i = 0;
360 while (!zeile.eof()) {
361 zeile >> distance;
362 i++;
363 }
364 if (i > a)
365 a = i;
366 b++;
367 }
368 cout << "I recognized " << a << " columns and " << b << " rows, ";
369 input.close();
370
371 // 0b. allocate memory for constants
372 FitConstant = (double ***) Malloc(sizeof(double **) * 3, "MoleculeListClass::AddHydrogenCorrection: ***FitConstant");
373 for (int k = 0; k < 3; k++) {
374 FitConstant[k] = (double **) Malloc(sizeof(double *) * a, "MoleculeListClass::AddHydrogenCorrection: **FitConstant[]");
375 for (int i = a; i--;) {
376 FitConstant[k][i] = (double *) Malloc(sizeof(double) * b, "MoleculeListClass::AddHydrogenCorrection: *FitConstant[][]");
377 }
378 }
379 // 0c. parse in constants
380 for (int i = 0; i < 3; i++) {
381 line = path;
382 line.append("/");
383 line += FRAGMENTPREFIX;
384 sprintf(ParsedLine, "%d", i + 1);
385 line += ParsedLine;
386 line += FITCONSTANTSUFFIX;
387 input.open(line.c_str());
388 if (input == NULL) {
389 cerr << endl << "Unable to open " << line << ", is the directory correct?" << endl;
390 return false;
391 }
392 int k = 0, l;
393 while ((!input.eof()) && (k < b)) {
394 input.getline(ParsedLine, 1023);
395 //cout << "Current Line: " << ParsedLine << endl;
396 zeile.str(ParsedLine);
397 zeile.clear();
398 l = 0;
399 while ((!zeile.eof()) && (l < a)) {
400 zeile >> FitConstant[i][l][k];
401 //cout << FitConstant[i][l][k] << "\t";
402 l++;
403 }
404 //cout << endl;
405 k++;
406 }
407 input.close();
408 }
409 for (int k = 0; k < 3; k++) {
410 cout << "Constants " << k << ":" << endl;
411 for (int j = 0; j < b; j++) {
412 for (int i = 0; i < a; i++) {
413 cout << FitConstant[k][i][j] << "\t";
414 }
415 cout << endl;
416 }
417 cout << endl;
418 }
419
420 // 0d. allocate final correction matrix
421 correction = (double **) Malloc(sizeof(double *) * a, "MoleculeListClass::AddHydrogenCorrection: **correction");
422 for (int i = a; i--;)
423 correction[i] = (double *) Malloc(sizeof(double) * b, "MoleculeListClass::AddHydrogenCorrection: *correction[]");
424
425 // 1a. go through every molecule in the list
426 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
427 // 1b. zero final correction matrix
428 for (int k = a; k--;)
429 for (int j = b; j--;)
430 correction[k][j] = 0.;
431 // 2. take every hydrogen that is a saturated one
432 Walker = (*ListRunner)->start;
433 while (Walker->next != (*ListRunner)->end) {
434 Walker = Walker->next;
435 //cout << Verbose(1) << "Walker: " << *Walker << " with first bond " << *(*Runner)->ListOfBondsPerAtom[Walker->nr][0] << "." << endl;
436 if ((Walker->type->Z == 1) && ((Walker->father == NULL)
437 || (Walker->father->type->Z != 1))) { // if it's a hydrogen
438 Runner = (*ListRunner)->start;
439 while (Runner->next != (*ListRunner)->end) {
440 Runner = Runner->next;
441 //cout << Verbose(2) << "Runner: " << *Runner << " with first bond " << *(*Runner)->ListOfBondsPerAtom[Runner->nr][0] << "." << endl;
442 // 3. take every other hydrogen that is the not the first and not bound to same bonding partner
443 if ((Runner->type->Z == 1) && (Runner->nr > Walker->nr) && ((*ListRunner)->ListOfBondsPerAtom[Runner->nr][0]->GetOtherAtom(Runner) != (*ListRunner)->ListOfBondsPerAtom[Walker->nr][0]->GetOtherAtom(Walker))) { // (hydrogens have only one bonding partner!)
444 // 4. evaluate the morse potential for each matrix component and add up
445 distance = Runner->x.Distance(&Walker->x);
446 //cout << "Fragment " << (*ListRunner)->name << ": " << *Runner << "<= " << distance << "=>" << *Walker << ":" << endl;
447 for (int k = 0; k < a; k++) {
448 for (int j = 0; j < b; j++) {
449 switch (k) {
450 case 1:
451 case 7:
452 case 11:
453 tmp = pow(FitConstant[0][k][j] * (1. - exp(-FitConstant[1][k][j] * (distance - FitConstant[2][k][j]))), 2);
454 break;
455 default:
456 tmp = FitConstant[0][k][j] * pow(distance, FitConstant[1][k][j]) + FitConstant[2][k][j];
457 };
458 correction[k][j] -= tmp; // ground state is actually lower (disturbed by additional interaction)
459 //cout << tmp << "\t";
460 }
461 //cout << endl;
462 }
463 //cout << endl;
464 }
465 }
466 }
467 }
468 // 5. write final matrix to file
469 line = path;
470 line.append("/");
471 line += FRAGMENTPREFIX;
472 FragmentNumber = FixedDigitNumber(ListOfMolecules.size(), (*ListRunner)->IndexNr);
473 line += FragmentNumber;
474 delete (FragmentNumber);
475 line += HCORRECTIONSUFFIX;
476 output.open(line.c_str());
477 output << "Time\t\tTotal\t\tKinetic\t\tNonLocal\tCorrelation\tExchange\tPseudo\t\tHartree\t\t-Gauss\t\tEwald\t\tIonKin\t\tETotal" << endl;
478 for (int j = 0; j < b; j++) {
479 for (int i = 0; i < a; i++)
480 output << correction[i][j] << "\t";
481 output << endl;
482 }
483 output.close();
484 }
485 line = path;
486 line.append("/");
487 line += HCORRECTIONSUFFIX;
488 output.open(line.c_str());
489 output << "Time\t\tTotal\t\tKinetic\t\tNonLocal\tCorrelation\tExchange\tPseudo\t\tHartree\t\t-Gauss\t\tEwald\t\tIonKin\t\tETotal" << endl;
490 for (int j = 0; j < b; j++) {
491 for (int i = 0; i < a; i++)
492 output << 0 << "\t";
493 output << endl;
494 }
495 output.close();
496 // 6. free memory of parsed matrices
497 FitConstant = (double ***) Malloc(sizeof(double **) * a, "MoleculeListClass::AddHydrogenCorrection: ***FitConstant");
498 for (int k = 0; k < 3; k++) {
499 FitConstant[k] = (double **) Malloc(sizeof(double *) * a, "MoleculeListClass::AddHydrogenCorrection: **FitConstant[]");
500 for (int i = a; i--;) {
501 FitConstant[k][i] = (double *) Malloc(sizeof(double) * b, "MoleculeListClass::AddHydrogenCorrection: *FitConstant[][]");
502 }
503 }
504 cout << "done." << endl;
505 return true;
506};
507
508/** Store force indices, i.e. the connection between the nuclear index in the total molecule config and the respective atom in fragment config.
509 * \param *out output stream for debugging
510 * \param *path path to file
511 * \param *SortIndex Index to map from the BFS labeling to the sequence how of Ion_Type in the config
512 * \return true - file written successfully, false - writing failed
513 */
514bool MoleculeListClass::StoreForcesFile(ofstream *out, char *path,
515 int *SortIndex)
516{
517 bool status = true;
518 ofstream ForcesFile;
519 stringstream line;
520 atom *Walker = NULL;
521 element *runner = NULL;
522
523 // open file for the force factors
524 *out << Verbose(1) << "Saving force factors ... ";
525 line << path << "/" << FRAGMENTPREFIX << FORCESFILE;
526 ForcesFile.open(line.str().c_str(), ios::out);
527 if (ForcesFile != NULL) {
528 //cout << Verbose(1) << "Final AtomicForcesList: ";
529 //output << prefix << "Forces" << endl;
530 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
531 runner = (*ListRunner)->elemente->start;
532 while (runner->next != (*ListRunner)->elemente->end) { // go through every element
533 runner = runner->next;
534 if ((*ListRunner)->ElementsInMolecule[runner->Z]) { // if this element got atoms
535 Walker = (*ListRunner)->start;
536 while (Walker->next != (*ListRunner)->end) { // go through every atom of this element
537 Walker = Walker->next;
538 if (Walker->type->Z == runner->Z) {
539 if ((Walker->GetTrueFather() != NULL) && (Walker->GetTrueFather() != Walker)) {// if there is a rea
540 //cout << "Walker is " << *Walker << " with true father " << *( Walker->GetTrueFather()) << ", it
541 ForcesFile << SortIndex[Walker->GetTrueFather()->nr] << "\t";
542 } else
543 // otherwise a -1 to indicate an added saturation hydrogen
544 ForcesFile << "-1\t";
545 }
546 }
547 }
548 }
549 ForcesFile << endl;
550 }
551 ForcesFile.close();
552 *out << Verbose(1) << "done." << endl;
553 } else {
554 status = false;
555 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
556 }
557 ForcesFile.close();
558
559 return status;
560};
561
562/** Writes a config file for each molecule in the given \a **FragmentList.
563 * \param *out output stream for debugging
564 * \param *configuration standard configuration to attach atoms in fragment molecule to.
565 * \param *SortIndex Index to map from the BFS labeling to the sequence how of Ion_Type in the config
566 * \return true - success (each file was written), false - something went wrong.
567 */
568bool MoleculeListClass::OutputConfigForListOfFragments(ofstream *out,
569 config *configuration, int *SortIndex)
570{
571 ofstream outputFragment;
572 char FragmentName[MAXSTRINGSIZE];
573 char PathBackup[MAXSTRINGSIZE];
574 bool result = true;
575 bool intermediateResult = true;
576 atom *Walker = NULL;
577 Vector BoxDimension;
578 char *FragmentNumber = NULL;
579 char *path = NULL;
580 int FragmentCounter = 0;
581 ofstream output;
582
583 // store the fragments as config and as xyz
584 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
585 // save default path as it is changed for each fragment
586 path = configuration->GetDefaultPath();
587 if (path != NULL)
588 strcpy(PathBackup, path);
589 else
590 cerr << "OutputConfigForListOfFragments: NULL default path obtained from config!" << endl;
591
592 // correct periodic
593 (*ListRunner)->ScanForPeriodicCorrection(out);
594
595 // output xyz file
596 FragmentNumber = FixedDigitNumber(ListOfMolecules.size(), FragmentCounter++);
597 sprintf(FragmentName, "%s/%s%s.conf.xyz", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
598 outputFragment.open(FragmentName, ios::out);
599 *out << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as XYZ ...";
600 if ((intermediateResult = (*ListRunner)->OutputXYZ(&outputFragment)))
601 *out << " done." << endl;
602 else
603 *out << " failed." << endl;
604 result = result && intermediateResult;
605 outputFragment.close();
606 outputFragment.clear();
607
608 // list atoms in fragment for debugging
609 *out << Verbose(2) << "Contained atoms: ";
610 Walker = (*ListRunner)->start;
611 while (Walker->next != (*ListRunner)->end) {
612 Walker = Walker->next;
613 *out << Walker->Name << " ";
614 }
615 *out << endl;
616
617 // center on edge
618 (*ListRunner)->CenterEdge(out, &BoxDimension);
619 (*ListRunner)->SetBoxDimension(&BoxDimension); // update Box of atoms by boundary
620 int j = -1;
621 for (int k = 0; k < NDIM; k++) {
622 j += k + 1;
623 BoxDimension.x[k] = 2.5 * (configuration->GetIsAngstroem() ? 1. : 1. / AtomicLengthToAngstroem);
624 (*ListRunner)->cell_size[j] += BoxDimension.x[k] * 2.;
625 }
626 (*ListRunner)->Translate(&BoxDimension);
627
628 // also calculate necessary orbitals
629 (*ListRunner)->CountElements(); // this is a bugfix, atoms should shoulds actually be added correctly to this fragment
630 (*ListRunner)->CalculateOrbitals(*configuration);
631
632 // change path in config
633 //strcpy(PathBackup, configuration->configpath);
634 sprintf(FragmentName, "%s/%s%s/", PathBackup, FRAGMENTPREFIX, FragmentNumber);
635 configuration->SetDefaultPath(FragmentName);
636
637 // and save as config
638 sprintf(FragmentName, "%s/%s%s.conf", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
639 *out << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as config ...";
640 if ((intermediateResult = configuration->Save(FragmentName, (*ListRunner)->elemente, (*ListRunner))))
641 *out << " done." << endl;
642 else
643 *out << " failed." << endl;
644 result = result && intermediateResult;
645
646 // restore old config
647 configuration->SetDefaultPath(PathBackup);
648
649 // and save as mpqc input file
650 sprintf(FragmentName, "%s/%s%s.conf", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
651 *out << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as mpqc input ...";
652 if ((intermediateResult = configuration->SaveMPQC(FragmentName, (*ListRunner))))
653 *out << " done." << endl;
654 else
655 *out << " failed." << endl;
656
657 result = result && intermediateResult;
658 //outputFragment.close();
659 //outputFragment.clear();
660 delete (FragmentNumber);
661 //Free((void **)&FragmentNumber, "MoleculeListClass::OutputConfigForListOfFragments: *FragmentNumber");
662 }
663 cout << " done." << endl;
664
665 // printing final number
666 *out << "Final number of fragments: " << FragmentCounter << "." << endl;
667
668 return result;
669};
670
671/** Counts the number of molecules with the molecule::ActiveFlag set.
672 * \return number of molecules with ActiveFlag set to true.
673 */
674int MoleculeListClass::NumberOfActiveMolecules()
675{
676 int count = 0;
677 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
678 count += ((*ListRunner)->ActiveFlag ? 1 : 0);
679 return count;
680};
681
682
683/******************************************* Class MoleculeLeafClass ************************************************/
684
685/** Constructor for MoleculeLeafClass root leaf.
686 * \param *Up Leaf on upper level
687 * \param *PreviousLeaf NULL - We are the first leaf on this level, otherwise points to previous in list
688 */
689//MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *Up = NULL, MoleculeLeafClass *Previous = NULL)
690MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *PreviousLeaf = NULL)
691{
692 // if (Up != NULL)
693 // if (Up->DownLeaf == NULL) // are we the first down leaf for the upper leaf?
694 // Up->DownLeaf = this;
695 // UpLeaf = Up;
696 // DownLeaf = NULL;
697 Leaf = NULL;
698 previous = PreviousLeaf;
699 if (previous != NULL) {
700 MoleculeLeafClass *Walker = previous->next;
701 previous->next = this;
702 next = Walker;
703 } else {
704 next = NULL;
705 }
706};
707
708/** Destructor for MoleculeLeafClass.
709 */
710MoleculeLeafClass::~MoleculeLeafClass()
711{
712 // if (DownLeaf != NULL) {// drop leaves further down
713 // MoleculeLeafClass *Walker = DownLeaf;
714 // MoleculeLeafClass *Next;
715 // do {
716 // Next = Walker->NextLeaf;
717 // delete(Walker);
718 // Walker = Next;
719 // } while (Walker != NULL);
720 // // Last Walker sets DownLeaf automatically to NULL
721 // }
722 // remove the leaf itself
723 if (Leaf != NULL) {
724 delete (Leaf);
725 Leaf = NULL;
726 }
727 // remove this Leaf from level list
728 if (previous != NULL)
729 previous->next = next;
730 // } else { // we are first in list (connects to UpLeaf->DownLeaf)
731 // if ((NextLeaf != NULL) && (NextLeaf->UpLeaf == NULL))
732 // NextLeaf->UpLeaf = UpLeaf; // either null as we are top level or the upleaf of the first node
733 // if (UpLeaf != NULL)
734 // UpLeaf->DownLeaf = NextLeaf; // either null as we are only leaf or NextLeaf if we are just the first
735 // }
736 // UpLeaf = NULL;
737 if (next != NULL) // are we last in list
738 next->previous = previous;
739 next = NULL;
740 previous = NULL;
741};
742
743/** Adds \a molecule leaf to the tree.
744 * \param *ptr ptr to molecule to be added
745 * \param *Previous previous MoleculeLeafClass referencing level and which on the level
746 * \return true - success, false - something went wrong
747 */
748bool MoleculeLeafClass::AddLeaf(molecule *ptr, MoleculeLeafClass *Previous)
749{
750 return false;
751};
752
753/** Fills the bond structure of this chain list subgraphs that are derived from a complete \a *reference molecule.
754 * Calls this routine in each MoleculeLeafClass::next subgraph if it's not NULL.
755 * \param *out output stream for debugging
756 * \param *reference reference molecule with the bond structure to be copied
757 * \param &FragmentCounter Counter needed to address \a **ListOfLocalAtoms
758 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in \a *reference, may be NULL on start, then it is filled
759 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
760 * \return true - success, false - faoilure
761 */
762bool MoleculeLeafClass::FillBondStructureFromReference(ofstream *out, molecule *reference, int &FragmentCounter, atom ***&ListOfLocalAtoms, bool FreeList)
763{
764 atom *Walker = NULL, *OtherWalker = NULL;
765 bond *Binder = NULL;
766 bool status = true;
767 int AtomNo;
768
769 *out << Verbose(1) << "Begin of FillBondStructureFromReference." << endl;
770 // fill ListOfLocalAtoms if NULL was given
771 if (!FillListOfLocalAtoms(out, ListOfLocalAtoms, FragmentCounter, reference->AtomCount, FreeList)) {
772 *out << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl;
773 return false;
774 }
775
776 if (status) {
777 *out << Verbose(1) << "Creating adjacency list for subgraph " << this
778 << "." << endl;
779 Walker = Leaf->start;
780 while (Walker->next != Leaf->end) {
781 Walker = Walker->next;
782 AtomNo = Walker->GetTrueFather()->nr; // global id of the current walker
783 for (int i = 0; i < reference->NumberOfBondsPerAtom[AtomNo]; i++) { // go through father's bonds and copy them all
784 Binder = reference->ListOfBondsPerAtom[AtomNo][i];
785 OtherWalker = ListOfLocalAtoms[FragmentCounter][Binder->GetOtherAtom(Walker->GetTrueFather())->nr]; // local copy of current bond partner of walker
786 if (OtherWalker != NULL) {
787 if (OtherWalker->nr > Walker->nr)
788 Leaf->AddBond(Walker, OtherWalker, Binder->BondDegree);
789 } else {
790 *out << Verbose(1) << "OtherWalker = ListOfLocalAtoms[" << FragmentCounter << "][" << Binder->GetOtherAtom(Walker->GetTrueFather())->nr << "] is NULL!" << endl;
791 status = false;
792 }
793 }
794 }
795 Leaf->CreateListOfBondsPerAtom(out);
796 FragmentCounter++;
797 if (next != NULL)
798 status = next->FillBondStructureFromReference(out, reference, FragmentCounter, ListOfLocalAtoms);
799 FragmentCounter--;
800 }
801
802 if ((FreeList) && (ListOfLocalAtoms != NULL)) {
803 // free the index lookup list
804 Free((void **) &ListOfLocalAtoms[FragmentCounter], "MoleculeLeafClass::FillBondStructureFromReference - **ListOfLocalAtoms[]");
805 if (FragmentCounter == 0) // first fragments frees the initial pointer to list
806 Free((void **) &ListOfLocalAtoms, "MoleculeLeafClass::FillBondStructureFromReference - ***ListOfLocalAtoms");
807 }
808 FragmentCounter--;
809 *out << Verbose(1) << "End of FillBondStructureFromReference." << endl;
810 return status;
811};
812
813/** Fills the root stack for sites to be used as root in fragmentation depending on order or adaptivity criteria
814 * Again, as in \sa FillBondStructureFromReference steps recursively through each Leaf in this chain list of molecule's.
815 * \param *out output stream for debugging
816 * \param *&RootStack stack to be filled
817 * \param *AtomMask defines true/false per global Atom::nr to mask in/out each nuclear site
818 * \param &FragmentCounter counts through the fragments in this MoleculeLeafClass
819 * \return true - stack is non-empty, fragmentation necessary, false - stack is empty, no more sites to update
820 */
821bool MoleculeLeafClass::FillRootStackForSubgraphs(ofstream *out,
822 KeyStack *&RootStack, bool *AtomMask, int &FragmentCounter)
823{
824 atom *Walker = NULL, *Father = NULL;
825
826 if (RootStack != NULL) {
827 // find first root candidates
828 if (&(RootStack[FragmentCounter]) != NULL) {
829 RootStack[FragmentCounter].clear();
830 Walker = Leaf->start;
831 while (Walker->next != Leaf->end) { // go through all (non-hydrogen) atoms
832 Walker = Walker->next;
833 Father = Walker->GetTrueFather();
834 if (AtomMask[Father->nr]) // apply mask
835#ifdef ADDHYDROGEN
836 if (Walker->type->Z != 1) // skip hydrogen
837#endif
838 RootStack[FragmentCounter].push_front(Walker->nr);
839 }
840 if (next != NULL)
841 next->FillRootStackForSubgraphs(out, RootStack, AtomMask, ++FragmentCounter);
842 } else {
843 *out << Verbose(1) << "Rootstack[" << FragmentCounter << "] is NULL." << endl;
844 return false;
845 }
846 FragmentCounter--;
847 return true;
848 } else {
849 *out << Verbose(1) << "Rootstack is NULL." << endl;
850 return false;
851 }
852};
853
854/** Fills a lookup list of father's Atom::nr -> atom for each subgraph.
855 * \param *out output stream fro debugging
856 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
857 * \param FragmentCounter counts the fragments as we move along the list
858 * \param GlobalAtomCount number of atoms in the complete molecule
859 * \param &FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
860 * \return true - succes, false - failure
861 */
862bool MoleculeLeafClass::FillListOfLocalAtoms(ofstream *out, atom ***&ListOfLocalAtoms, const int FragmentCounter, const int GlobalAtomCount, bool &FreeList)
863{
864 bool status = true;
865
866 int Counter = Count();
867 if (ListOfLocalAtoms == NULL) { // allocated initial pointer
868 // allocate and set each field to NULL
869 ListOfLocalAtoms = (atom ***) Malloc(sizeof(atom **) * Counter, "MoleculeLeafClass::FillBondStructureFromReference - ***ListOfLocalAtoms");
870 if (ListOfLocalAtoms != NULL) {
871 for (int i = Counter; i--;)
872 ListOfLocalAtoms[i] = NULL;
873 FreeList = FreeList && true;
874 } else
875 status = false;
876 }
877
878 if ((ListOfLocalAtoms != NULL) && (ListOfLocalAtoms[FragmentCounter] == NULL)) { // allocate and fill list of this fragment/subgraph
879 status = status && CreateFatherLookupTable(out, Leaf->start, Leaf->end, ListOfLocalAtoms[FragmentCounter], GlobalAtomCount);
880 FreeList = FreeList && true;
881 }
882
883 return status;
884};
885
886/** The indices per keyset are compared to the respective father's Atom::nr in each subgraph and thus put into \a **&FragmentList.
887 * \param *out output stream fro debugging
888 * \param *reference reference molecule with the bond structure to be copied
889 * \param *KeySetList list with all keysets
890 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
891 * \param **&FragmentList list to be allocated and returned
892 * \param &FragmentCounter counts the fragments as we move along the list
893 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
894 * \retuen true - success, false - failure
895 */
896bool MoleculeLeafClass::AssignKeySetsToFragment(ofstream *out,
897 molecule *reference, Graph *KeySetList, atom ***&ListOfLocalAtoms,
898 Graph **&FragmentList, int &FragmentCounter, bool FreeList)
899{
900 bool status = true;
901 int KeySetCounter = 0;
902
903 *out << Verbose(1) << "Begin of AssignKeySetsToFragment." << endl;
904 // fill ListOfLocalAtoms if NULL was given
905 if (!FillListOfLocalAtoms(out, ListOfLocalAtoms, FragmentCounter, reference->AtomCount, FreeList)) {
906 *out << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl;
907 return false;
908 }
909
910 // allocate fragment list
911 if (FragmentList == NULL) {
912 KeySetCounter = Count();
913 FragmentList = (Graph **) Malloc(sizeof(Graph *) * KeySetCounter, "MoleculeLeafClass::AssignKeySetsToFragment - **FragmentList");
914 for (int i = KeySetCounter; i--;)
915 FragmentList[i] = NULL;
916 KeySetCounter = 0;
917 }
918
919 if ((KeySetList != NULL) && (KeySetList->size() != 0)) { // if there are some scanned keysets at all
920 // assign scanned keysets
921 if (FragmentList[FragmentCounter] == NULL)
922 FragmentList[FragmentCounter] = new Graph;
923 KeySet *TempSet = new KeySet;
924 for (Graph::iterator runner = KeySetList->begin(); runner != KeySetList->end(); runner++) { // key sets contain global numbers!
925 if (ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*((*runner).first.begin()))->nr] != NULL) {// as we may assume that that bond structure is unchanged, we only test the first key in each set
926 // translate keyset to local numbers
927 for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
928 TempSet->insert(ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*sprinter)->nr]->nr);
929 // insert into FragmentList
930 FragmentList[FragmentCounter]->insert(GraphPair(*TempSet, pair<int, double> (KeySetCounter++, (*runner).second.second)));
931 }
932 TempSet->clear();
933 }
934 delete (TempSet);
935 if (KeySetCounter == 0) {// if there are no keysets, delete the list
936 *out << Verbose(1) << "KeySetCounter is zero, deleting FragmentList." << endl;
937 delete (FragmentList[FragmentCounter]);
938 } else
939 *out << Verbose(1) << KeySetCounter << " keysets were assigned to subgraph " << FragmentCounter << "." << endl;
940 FragmentCounter++;
941 if (next != NULL)
942 next->AssignKeySetsToFragment(out, reference, KeySetList, ListOfLocalAtoms, FragmentList, FragmentCounter, FreeList);
943 FragmentCounter--;
944 } else
945 *out << Verbose(1) << "KeySetList is NULL or empty." << endl;
946
947 if ((FreeList) && (ListOfLocalAtoms != NULL)) {
948 // free the index lookup list
949 Free((void **) &ListOfLocalAtoms[FragmentCounter], "MoleculeLeafClass::AssignKeySetsToFragment - **ListOfLocalAtoms[]");
950 if (FragmentCounter == 0) // first fragments frees the initial pointer to list
951 Free((void **) &ListOfLocalAtoms, "MoleculeLeafClass::AssignKeySetsToFragment - ***ListOfLocalAtoms");
952 }
953 *out << Verbose(1) << "End of AssignKeySetsToFragment." << endl;
954 return status;
955};
956
957/** Translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
958 * \param *out output stream for debugging
959 * \param **FragmentList Graph with local numbers per fragment
960 * \param &FragmentCounter counts the fragments as we move along the list
961 * \param &TotalNumberOfKeySets global key set counter
962 * \param &TotalGraph Graph to be filled with global numbers
963 */
964void MoleculeLeafClass::TranslateIndicesToGlobalIDs(ofstream *out,
965 Graph **FragmentList, int &FragmentCounter, int &TotalNumberOfKeySets,
966 Graph &TotalGraph)
967{
968 *out << Verbose(1) << "Begin of TranslateIndicesToGlobalIDs." << endl;
969 KeySet *TempSet = new KeySet;
970 if (FragmentList[FragmentCounter] != NULL) {
971 for (Graph::iterator runner = FragmentList[FragmentCounter]->begin(); runner != FragmentList[FragmentCounter]->end(); runner++) {
972 for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
973 TempSet->insert((Leaf->FindAtom(*sprinter))->GetTrueFather()->nr);
974 TotalGraph.insert(GraphPair(*TempSet, pair<int, double> (TotalNumberOfKeySets++, (*runner).second.second)));
975 TempSet->clear();
976 }
977 delete (TempSet);
978 } else {
979 *out << Verbose(1) << "FragmentList is NULL." << endl;
980 }
981 if (next != NULL)
982 next->TranslateIndicesToGlobalIDs(out, FragmentList, ++FragmentCounter, TotalNumberOfKeySets, TotalGraph);
983 FragmentCounter--;
984 *out << Verbose(1) << "End of TranslateIndicesToGlobalIDs." << endl;
985};
986
987/** Simply counts the number of items in the list, from given MoleculeLeafClass.
988 * \return number of items
989 */
990int MoleculeLeafClass::Count() const
991{
992 if (next != NULL)
993 return next->Count() + 1;
994 else
995 return 1;
996};
997
Note: See TracBrowser for help on using the repository browser.