source: src/moleculelist.cpp@ 1a6bda

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 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 1a6bda was 4c2643, checked in by Frederik Heber <heber@…>, 14 years ago

Fix: MoleculeListClass::OutputConfigForListOfFragments with zero edge length of domain.

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