source: src/builder.cpp@ 570125

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 570125 was 08ef35, checked in by Frederik Heber <heber@…>, 16 years ago

New function ConvexizeNonconvexEnvelope() to calculate the volume of a non-convex envelope.

The central idea is that the volume of a convex envelope is easy to determine as a sum of pyramids with respect to a center inside the envelope. Hence, if we can "reduce" the non-convex envelope to a convex one in such a way that we know the added volume, we may determine the volume of a non-convex envelope.
The nice side effect is that we may use our Find_non_convex_border() algorithm to calculate also the convex envelope.

  • We go through all BoundaryPoints and check whether one of its Baselines does not fulfill the ConvexCriterion. If so, we remove it, as it can not be a boundary point on the convex envelope, and re-construct the attached triangles. The added volume is a general tetraeder, whose formula is known.
  • FIX: Find_convex_border() - We check whether AddPoint is successful or not.
  • builder.cpp: case 'o' - changed to use ConvexizeNonconvexEnvelope() instead of Find_convex_border()
  • Tesselation:AddPoint() - now takes second argument which is the index for BPS and always set BPS to either the newly created or the already present point. Return argument discerns between new and already present point.
  • Tesselation::BPS, BLS, BTS are now public not private. We have to access them from ConvexizeNonconvexEnvelope()
  • Property mode set to 100755
File size: 88.9 KB
Line 
1/** \file builder.cpp
2 *
3 * By stating absolute positions or binding angles and distances atomic positions of a molecule can be constructed.
4 * The output is the complete configuration file for PCP for direct use.
5 * Features:
6 * -# Atomic data is retrieved from a file, if not found requested and stored there for later re-use
7 * -# step-by-step construction of the molecule beginning either at a centre of with a certain atom
8 *
9 */
10
11/*! \mainpage Molecuilder - a molecular set builder
12 *
13 * This introductory shall briefly make aquainted with the program, helping in installing and a first run.
14 *
15 * \section about About the Program
16 *
17 * Molecuilder is a short program, written in C++, that enables the construction of a coordinate set for the
18 * atoms making up an molecule by the successive statement of binding angles and distances and referencing to
19 * already constructed atoms.
20 *
21 * A configuration file may be written that is compatible to the format used by PCP - a parallel Car-Parrinello
22 * molecular dynamics implementation.
23 *
24 * \section install Installation
25 *
26 * Installation should without problems succeed as follows:
27 * -# ./configure (or: mkdir build;mkdir run;cd build; ../configure --bindir=../run)
28 * -# make
29 * -# make install
30 *
31 * Further useful commands are
32 * -# make clean uninstall: deletes .o-files and removes executable from the given binary directory\n
33 * -# make doxygen-doc: Creates these html pages out of the documented source
34 *
35 * \section run Running
36 *
37 * The program can be executed by running: ./molecuilder
38 *
39 * Note, that it uses a database, called "elements.db", in the executable's directory. If the file is not found,
40 * it is created and any given data on elements of the periodic table will be stored therein and re-used on
41 * later re-execution.
42 *
43 * \section ref References
44 *
45 * For the special configuration file format, see the documentation of pcp.
46 *
47 */
48
49
50using namespace std;
51
52#include "boundary.hpp"
53#include "ellipsoid.hpp"
54#include "helpers.hpp"
55#include "molecules.hpp"
56/********************************************* Subsubmenu routine ************************************/
57
58/** Submenu for adding atoms to the molecule.
59 * \param *periode periodentafel
60 * \param *molecule molecules with atoms
61 */
62static void AddAtoms(periodentafel *periode, molecule *mol)
63{
64 atom *first, *second, *third, *fourth;
65 Vector **atoms;
66 Vector x,y,z,n; // coordinates for absolute point in cell volume
67 double a,b,c;
68 char choice; // menu choice char
69 bool valid;
70
71 cout << Verbose(0) << "===========ADD ATOM============================" << endl;
72 cout << Verbose(0) << " a - state absolute coordinates of atom" << endl;
73 cout << Verbose(0) << " b - state relative coordinates of atom wrt to reference point" << endl;
74 cout << Verbose(0) << " c - state relative coordinates of atom wrt to already placed atom" << endl;
75 cout << Verbose(0) << " d - state two atoms, two angles and a distance" << endl;
76 cout << Verbose(0) << " e - least square distance position to a set of atoms" << endl;
77 cout << Verbose(0) << "all else - go back" << endl;
78 cout << Verbose(0) << "===============================================" << endl;
79 cout << Verbose(0) << "Note: Specifiy angles in degrees not multiples of Pi!" << endl;
80 cout << Verbose(0) << "INPUT: ";
81 cin >> choice;
82
83 switch (choice) {
84 default:
85 cout << Verbose(0) << "Not a valid choice." << endl;
86 break;
87 case 'a': // absolute coordinates of atom
88 cout << Verbose(0) << "Enter absolute coordinates." << endl;
89 first = new atom;
90 first->x.AskPosition(mol->cell_size, false);
91 first->type = periode->AskElement(); // give type
92 mol->AddAtom(first); // add to molecule
93 break;
94
95 case 'b': // relative coordinates of atom wrt to reference point
96 first = new atom;
97 valid = true;
98 do {
99 if (!valid) cout << Verbose(0) << "Resulting position out of cell." << endl;
100 cout << Verbose(0) << "Enter reference coordinates." << endl;
101 x.AskPosition(mol->cell_size, true);
102 cout << Verbose(0) << "Enter relative coordinates." << endl;
103 first->x.AskPosition(mol->cell_size, false);
104 first->x.AddVector((const Vector *)&x);
105 cout << Verbose(0) << "\n";
106 } while (!(valid = mol->CheckBounds((const Vector *)&first->x)));
107 first->type = periode->AskElement(); // give type
108 mol->AddAtom(first); // add to molecule
109 break;
110
111 case 'c': // relative coordinates of atom wrt to already placed atom
112 first = new atom;
113 valid = true;
114 do {
115 if (!valid) cout << Verbose(0) << "Resulting position out of cell." << endl;
116 second = mol->AskAtom("Enter atom number: ");
117 cout << Verbose(0) << "Enter relative coordinates." << endl;
118 first->x.AskPosition(mol->cell_size, false);
119 for (int i=NDIM;i--;) {
120 first->x.x[i] += second->x.x[i];
121 }
122 } while (!(valid = mol->CheckBounds((const Vector *)&first->x)));
123 first->type = periode->AskElement(); // give type
124 mol->AddAtom(first); // add to molecule
125 break;
126
127 case 'd': // two atoms, two angles and a distance
128 first = new atom;
129 valid = true;
130 do {
131 if (!valid) {
132 cout << Verbose(0) << "Resulting coordinates out of cell - ";
133 first->x.Output((ofstream *)&cout);
134 cout << Verbose(0) << endl;
135 }
136 cout << Verbose(0) << "First, we need two atoms, the first atom is the central, while the second is the outer one." << endl;
137 second = mol->AskAtom("Enter central atom: ");
138 third = mol->AskAtom("Enter second atom (specifying the axis for first angle): ");
139 fourth = mol->AskAtom("Enter third atom (specifying a plane for second angle): ");
140 a = ask_value("Enter distance between central (first) and new atom: ");
141 b = ask_value("Enter angle between new, first and second atom (degrees): ");
142 b *= M_PI/180.;
143 bound(&b, 0., 2.*M_PI);
144 c = ask_value("Enter second angle between new and normal vector of plane defined by first, second and third atom (degrees): ");
145 c *= M_PI/180.;
146 bound(&c, -M_PI, M_PI);
147 cout << Verbose(0) << "radius: " << a << "\t phi: " << b*180./M_PI << "\t theta: " << c*180./M_PI << endl;
148/*
149 second->Output(1,1,(ofstream *)&cout);
150 third->Output(1,2,(ofstream *)&cout);
151 fourth->Output(1,3,(ofstream *)&cout);
152 n.MakeNormalvector((const vector *)&second->x, (const vector *)&third->x, (const vector *)&fourth->x);
153 x.Copyvector(&second->x);
154 x.SubtractVector(&third->x);
155 x.Copyvector(&fourth->x);
156 x.SubtractVector(&third->x);
157
158 if (!z.SolveSystem(&x,&y,&n, b, c, a)) {
159 cout << Verbose(0) << "Failure solving self-dependent linear system!" << endl;
160 continue;
161 }
162 cout << Verbose(0) << "resulting relative coordinates: ";
163 z.Output((ofstream *)&cout);
164 cout << Verbose(0) << endl;
165 */
166 // calc axis vector
167 x.CopyVector(&second->x);
168 x.SubtractVector(&third->x);
169 x.Normalize();
170 cout << "x: ",
171 x.Output((ofstream *)&cout);
172 cout << endl;
173 z.MakeNormalVector(&second->x,&third->x,&fourth->x);
174 cout << "z: ",
175 z.Output((ofstream *)&cout);
176 cout << endl;
177 y.MakeNormalVector(&x,&z);
178 cout << "y: ",
179 y.Output((ofstream *)&cout);
180 cout << endl;
181
182 // rotate vector around first angle
183 first->x.CopyVector(&x);
184 first->x.RotateVector(&z,b - M_PI);
185 cout << "Rotated vector: ",
186 first->x.Output((ofstream *)&cout);
187 cout << endl;
188 // remove the projection onto the rotation plane of the second angle
189 n.CopyVector(&y);
190 n.Scale(first->x.Projection(&y));
191 cout << "N1: ",
192 n.Output((ofstream *)&cout);
193 cout << endl;
194 first->x.SubtractVector(&n);
195 cout << "Subtracted vector: ",
196 first->x.Output((ofstream *)&cout);
197 cout << endl;
198 n.CopyVector(&z);
199 n.Scale(first->x.Projection(&z));
200 cout << "N2: ",
201 n.Output((ofstream *)&cout);
202 cout << endl;
203 first->x.SubtractVector(&n);
204 cout << "2nd subtracted vector: ",
205 first->x.Output((ofstream *)&cout);
206 cout << endl;
207
208 // rotate another vector around second angle
209 n.CopyVector(&y);
210 n.RotateVector(&x,c - M_PI);
211 cout << "2nd Rotated vector: ",
212 n.Output((ofstream *)&cout);
213 cout << endl;
214
215 // add the two linear independent vectors
216 first->x.AddVector(&n);
217 first->x.Normalize();
218 first->x.Scale(a);
219 first->x.AddVector(&second->x);
220
221 cout << Verbose(0) << "resulting coordinates: ";
222 first->x.Output((ofstream *)&cout);
223 cout << Verbose(0) << endl;
224 } while (!(valid = mol->CheckBounds((const Vector *)&first->x)));
225 first->type = periode->AskElement(); // give type
226 mol->AddAtom(first); // add to molecule
227 break;
228
229 case 'e': // least square distance position to a set of atoms
230 first = new atom;
231 atoms = new (Vector*[128]);
232 valid = true;
233 for(int i=128;i--;)
234 atoms[i] = NULL;
235 int i=0, j=0;
236 cout << Verbose(0) << "Now we need at least three molecules.\n";
237 do {
238 cout << Verbose(0) << "Enter " << i+1 << "th atom: ";
239 cin >> j;
240 if (j != -1) {
241 second = mol->FindAtom(j);
242 atoms[i++] = &(second->x);
243 }
244 } while ((j != -1) && (i<128));
245 if (i >= 2) {
246 first->x.LSQdistance(atoms, i);
247
248 first->x.Output((ofstream *)&cout);
249 first->type = periode->AskElement(); // give type
250 mol->AddAtom(first); // add to molecule
251 } else {
252 delete first;
253 cout << Verbose(0) << "Please enter at least two vectors!\n";
254 }
255 break;
256 };
257};
258
259/** Submenu for centering the atoms in the molecule.
260 * \param *mol molecule with all the atoms
261 */
262static void CenterAtoms(molecule *mol)
263{
264 Vector x, y, helper;
265 char choice; // menu choice char
266
267 cout << Verbose(0) << "===========CENTER ATOMS=========================" << endl;
268 cout << Verbose(0) << " a - on origin" << endl;
269 cout << Verbose(0) << " b - on center of gravity" << endl;
270 cout << Verbose(0) << " c - within box with additional boundary" << endl;
271 cout << Verbose(0) << " d - within given simulation box" << endl;
272 cout << Verbose(0) << "all else - go back" << endl;
273 cout << Verbose(0) << "===============================================" << endl;
274 cout << Verbose(0) << "INPUT: ";
275 cin >> choice;
276
277 switch (choice) {
278 default:
279 cout << Verbose(0) << "Not a valid choice." << endl;
280 break;
281 case 'a':
282 cout << Verbose(0) << "Centering atoms in config file on origin." << endl;
283 mol->CenterOrigin((ofstream *)&cout);
284 break;
285 case 'b':
286 cout << Verbose(0) << "Centering atoms in config file on center of gravity." << endl;
287 mol->CenterPeriodic((ofstream *)&cout);
288 break;
289 case 'c':
290 cout << Verbose(0) << "Centering atoms in config file within given additional boundary." << endl;
291 for (int i=0;i<NDIM;i++) {
292 cout << Verbose(0) << "Enter axis " << i << " boundary: ";
293 cin >> y.x[i];
294 }
295 mol->CenterEdge((ofstream *)&cout, &x); // make every coordinate positive
296 mol->Center.AddVector(&y); // translate by boundary
297 helper.CopyVector(&y);
298 helper.Scale(2.);
299 helper.AddVector(&x);
300 mol->SetBoxDimension(&helper); // update Box of atoms by boundary
301 break;
302 case 'd':
303 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl;
304 for (int i=0;i<NDIM;i++) {
305 cout << Verbose(0) << "Enter axis " << i << " boundary: ";
306 cin >> x.x[i];
307 }
308 // update Box of atoms by boundary
309 mol->SetBoxDimension(&x);
310 // center
311 mol->CenterInBox((ofstream *)&cout);
312 break;
313 }
314};
315
316/** Submenu for aligning the atoms in the molecule.
317 * \param *periode periodentafel
318 * \param *mol molecule with all the atoms
319 */
320static void AlignAtoms(periodentafel *periode, molecule *mol)
321{
322 atom *first, *second, *third;
323 Vector x,n;
324 char choice; // menu choice char
325
326 cout << Verbose(0) << "===========ALIGN ATOMS=========================" << endl;
327 cout << Verbose(0) << " a - state three atoms defining align plane" << endl;
328 cout << Verbose(0) << " b - state alignment vector" << endl;
329 cout << Verbose(0) << " c - state two atoms in alignment direction" << endl;
330 cout << Verbose(0) << " d - align automatically by least square fit" << endl;
331 cout << Verbose(0) << "all else - go back" << endl;
332 cout << Verbose(0) << "===============================================" << endl;
333 cout << Verbose(0) << "INPUT: ";
334 cin >> choice;
335
336 switch (choice) {
337 default:
338 case 'a': // three atoms defining mirror plane
339 first = mol->AskAtom("Enter first atom: ");
340 second = mol->AskAtom("Enter second atom: ");
341 third = mol->AskAtom("Enter third atom: ");
342
343 n.MakeNormalVector((const Vector *)&first->x,(const Vector *)&second->x,(const Vector *)&third->x);
344 break;
345 case 'b': // normal vector of mirror plane
346 cout << Verbose(0) << "Enter normal vector of mirror plane." << endl;
347 n.AskPosition(mol->cell_size,0);
348 n.Normalize();
349 break;
350 case 'c': // three atoms defining mirror plane
351 first = mol->AskAtom("Enter first atom: ");
352 second = mol->AskAtom("Enter second atom: ");
353
354 n.CopyVector((const Vector *)&first->x);
355 n.SubtractVector((const Vector *)&second->x);
356 n.Normalize();
357 break;
358 case 'd':
359 char shorthand[4];
360 Vector a;
361 struct lsq_params param;
362 do {
363 fprintf(stdout, "Enter the element of atoms to be chosen: ");
364 fscanf(stdin, "%3s", shorthand);
365 } while ((param.type = periode->FindElement(shorthand)) == NULL);
366 cout << Verbose(0) << "Element is " << param.type->name << endl;
367 mol->GetAlignvector(&param);
368 for (int i=NDIM;i--;) {
369 x.x[i] = gsl_vector_get(param.x,i);
370 n.x[i] = gsl_vector_get(param.x,i+NDIM);
371 }
372 gsl_vector_free(param.x);
373 cout << Verbose(0) << "Offset vector: ";
374 x.Output((ofstream *)&cout);
375 cout << Verbose(0) << endl;
376 n.Normalize();
377 break;
378 };
379 cout << Verbose(0) << "Alignment vector: ";
380 n.Output((ofstream *)&cout);
381 cout << Verbose(0) << endl;
382 mol->Align(&n);
383};
384
385/** Submenu for mirroring the atoms in the molecule.
386 * \param *mol molecule with all the atoms
387 */
388static void MirrorAtoms(molecule *mol)
389{
390 atom *first, *second, *third;
391 Vector n;
392 char choice; // menu choice char
393
394 cout << Verbose(0) << "===========MIRROR ATOMS=========================" << endl;
395 cout << Verbose(0) << " a - state three atoms defining mirror plane" << endl;
396 cout << Verbose(0) << " b - state normal vector of mirror plane" << endl;
397 cout << Verbose(0) << " c - state two atoms in normal direction" << endl;
398 cout << Verbose(0) << "all else - go back" << endl;
399 cout << Verbose(0) << "===============================================" << endl;
400 cout << Verbose(0) << "INPUT: ";
401 cin >> choice;
402
403 switch (choice) {
404 default:
405 case 'a': // three atoms defining mirror plane
406 first = mol->AskAtom("Enter first atom: ");
407 second = mol->AskAtom("Enter second atom: ");
408 third = mol->AskAtom("Enter third atom: ");
409
410 n.MakeNormalVector((const Vector *)&first->x,(const Vector *)&second->x,(const Vector *)&third->x);
411 break;
412 case 'b': // normal vector of mirror plane
413 cout << Verbose(0) << "Enter normal vector of mirror plane." << endl;
414 n.AskPosition(mol->cell_size,0);
415 n.Normalize();
416 break;
417 case 'c': // three atoms defining mirror plane
418 first = mol->AskAtom("Enter first atom: ");
419 second = mol->AskAtom("Enter second atom: ");
420
421 n.CopyVector((const Vector *)&first->x);
422 n.SubtractVector((const Vector *)&second->x);
423 n.Normalize();
424 break;
425 };
426 cout << Verbose(0) << "Normal vector: ";
427 n.Output((ofstream *)&cout);
428 cout << Verbose(0) << endl;
429 mol->Mirror((const Vector *)&n);
430};
431
432/** Submenu for removing the atoms from the molecule.
433 * \param *mol molecule with all the atoms
434 */
435static void RemoveAtoms(molecule *mol)
436{
437 atom *first, *second;
438 int axis;
439 double tmp1, tmp2;
440 char choice; // menu choice char
441
442 cout << Verbose(0) << "===========REMOVE ATOMS=========================" << endl;
443 cout << Verbose(0) << " a - state atom for removal by number" << endl;
444 cout << Verbose(0) << " b - keep only in radius around atom" << endl;
445 cout << Verbose(0) << " c - remove this with one axis greater value" << endl;
446 cout << Verbose(0) << "all else - go back" << endl;
447 cout << Verbose(0) << "===============================================" << endl;
448 cout << Verbose(0) << "INPUT: ";
449 cin >> choice;
450
451 switch (choice) {
452 default:
453 case 'a':
454 if (mol->RemoveAtom(mol->AskAtom("Enter number of atom within molecule: ")))
455 cout << Verbose(1) << "Atom removed." << endl;
456 else
457 cout << Verbose(1) << "Atom not found." << endl;
458 break;
459 case 'b':
460 second = mol->AskAtom("Enter number of atom as reference point: ");
461 cout << Verbose(0) << "Enter radius: ";
462 cin >> tmp1;
463 first = mol->start;
464 second = first->next;
465 while(second != mol->end) {
466 first = second;
467 second = first->next;
468 if (first->x.DistanceSquared((const Vector *)&second->x) > tmp1*tmp1) // distance to first above radius ...
469 mol->RemoveAtom(first);
470 }
471 break;
472 case 'c':
473 cout << Verbose(0) << "Which axis is it: ";
474 cin >> axis;
475 cout << Verbose(0) << "Lower boundary: ";
476 cin >> tmp1;
477 cout << Verbose(0) << "Upper boundary: ";
478 cin >> tmp2;
479 first = mol->start;
480 second = first->next;
481 while(second != mol->end) {
482 first = second;
483 second = first->next;
484 if ((first->x.x[axis] < tmp1) || (first->x.x[axis] > tmp2)) {// out of boundary ...
485 //cout << "Atom " << *first << " with " << first->x.x[axis] << " on axis " << axis << " is out of bounds [" << tmp1 << "," << tmp2 << "]." << endl;
486 mol->RemoveAtom(first);
487 }
488 }
489 break;
490 };
491 //mol->Output((ofstream *)&cout);
492 choice = 'r';
493};
494
495/** Submenu for measuring out the atoms in the molecule.
496 * \param *periode periodentafel
497 * \param *mol molecule with all the atoms
498 */
499static void MeasureAtoms(periodentafel *periode, molecule *mol, config *configuration)
500{
501 atom *first, *second, *third;
502 Vector x,y;
503 double min[256], tmp1, tmp2, tmp3;
504 int Z;
505 char choice; // menu choice char
506
507 cout << Verbose(0) << "===========MEASURE ATOMS=========================" << endl;
508 cout << Verbose(0) << " a - calculate bond length between one atom and all others" << endl;
509 cout << Verbose(0) << " b - calculate bond length between two atoms" << endl;
510 cout << Verbose(0) << " c - calculate bond angle" << endl;
511 cout << Verbose(0) << " d - calculate principal axis of the system" << endl;
512 cout << Verbose(0) << " e - calculate volume of the convex envelope" << endl;
513 cout << Verbose(0) << " f - calculate temperature from current velocity" << endl;
514 cout << Verbose(0) << " g - output all temperatures per step from velocities" << endl;
515 cout << Verbose(0) << "all else - go back" << endl;
516 cout << Verbose(0) << "===============================================" << endl;
517 cout << Verbose(0) << "INPUT: ";
518 cin >> choice;
519
520 switch(choice) {
521 default:
522 cout << Verbose(1) << "Not a valid choice." << endl;
523 break;
524 case 'a':
525 first = mol->AskAtom("Enter first atom: ");
526 for (int i=MAX_ELEMENTS;i--;)
527 min[i] = 0.;
528
529 second = mol->start;
530 while ((second->next != mol->end)) {
531 second = second->next; // advance
532 Z = second->type->Z;
533 tmp1 = 0.;
534 if (first != second) {
535 x.CopyVector((const Vector *)&first->x);
536 x.SubtractVector((const Vector *)&second->x);
537 tmp1 = x.Norm();
538 }
539 if ((tmp1 != 0.) && ((min[Z] == 0.) || (tmp1 < min[Z]))) min[Z] = tmp1;
540 //cout << Verbose(0) << "Bond length between Atom " << first->nr << " and " << second->nr << ": " << tmp1 << " a.u." << endl;
541 }
542 for (int i=MAX_ELEMENTS;i--;)
543 if (min[i] != 0.) cout << Verbose(0) << "Minimum Bond length between " << first->type->name << " Atom " << first->nr << " and next Ion of type " << (periode->FindElement(i))->name << ": " << min[i] << " a.u." << endl;
544 break;
545
546 case 'b':
547 first = mol->AskAtom("Enter first atom: ");
548 second = mol->AskAtom("Enter second atom: ");
549 for (int i=NDIM;i--;)
550 min[i] = 0.;
551 x.CopyVector((const Vector *)&first->x);
552 x.SubtractVector((const Vector *)&second->x);
553 tmp1 = x.Norm();
554 cout << Verbose(1) << "Distance vector is ";
555 x.Output((ofstream *)&cout);
556 cout << "." << endl << "Norm of distance is " << tmp1 << "." << endl;
557 break;
558
559 case 'c':
560 cout << Verbose(0) << "Evaluating bond angle between three - first, central, last - atoms." << endl;
561 first = mol->AskAtom("Enter first atom: ");
562 second = mol->AskAtom("Enter central atom: ");
563 third = mol->AskAtom("Enter last atom: ");
564 tmp1 = tmp2 = tmp3 = 0.;
565 x.CopyVector((const Vector *)&first->x);
566 x.SubtractVector((const Vector *)&second->x);
567 y.CopyVector((const Vector *)&third->x);
568 y.SubtractVector((const Vector *)&second->x);
569 cout << Verbose(0) << "Bond angle between first atom Nr." << first->nr << ", central atom Nr." << second->nr << " and last atom Nr." << third->nr << ": ";
570 cout << Verbose(0) << (acos(x.ScalarProduct((const Vector *)&y)/(y.Norm()*x.Norm()))/M_PI*180.) << " degrees" << endl;
571 break;
572 case 'd':
573 cout << Verbose(0) << "Evaluating prinicipal axis." << endl;
574 cout << Verbose(0) << "Shall we rotate? [0/1]: ";
575 cin >> Z;
576 if ((Z >=0) && (Z <=1))
577 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)Z);
578 else
579 mol->PrincipalAxisSystem((ofstream *)&cout, false);
580 break;
581 case 'e':
582 {
583 cout << Verbose(0) << "Evaluating volume of the convex envelope.";
584 LinkedCell LCList(mol, 10.);
585 class Tesselation *TesselStruct = NULL;
586 Find_convex_border((ofstream *)&cout, mol, &LCList, NULL);
587 double clustervolume = VolumeOfConvexEnvelope((ofstream *)&cout, TesselStruct, configuration);
588 cout << Verbose(0) << "The tesselated surface area is " << clustervolume << "." << endl;
589 delete(TesselStruct);
590 }
591 break;
592 case 'f':
593 mol->OutputTemperatureFromTrajectories((ofstream *)&cout, mol->MDSteps-1, mol->MDSteps, (ofstream *)&cout);
594 break;
595 case 'g':
596 {
597 char filename[255];
598 cout << "Please enter filename: " << endl;
599 cin >> filename;
600 cout << Verbose(1) << "Storing temperatures in " << filename << "." << endl;
601 ofstream *output = new ofstream(filename, ios::trunc);
602 if (!mol->OutputTemperatureFromTrajectories((ofstream *)&cout, 0, mol->MDSteps, output))
603 cout << Verbose(2) << "File could not be written." << endl;
604 else
605 cout << Verbose(2) << "File stored." << endl;
606 output->close();
607 delete(output);
608 }
609 break;
610 }
611};
612
613/** Submenu for measuring out the atoms in the molecule.
614 * \param *mol molecule with all the atoms
615 * \param *configuration configuration structure for the to be written config files of all fragments
616 */
617static void FragmentAtoms(molecule *mol, config *configuration)
618{
619 int Order1;
620 clock_t start, end;
621
622 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl;
623 cout << Verbose(0) << "What's the desired bond order: ";
624 cin >> Order1;
625 if (mol->first->next != mol->last) { // there are bonds
626 start = clock();
627 mol->FragmentMolecule((ofstream *)&cout, Order1, configuration);
628 end = clock();
629 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
630 } else
631 cout << Verbose(0) << "Connection matrix has not yet been generated!" << endl;
632};
633
634/********************************************** Submenu routine **************************************/
635
636/** Submenu for manipulating atoms.
637 * \param *periode periodentafel
638 * \param *molecules list of molecules whose atoms are to be manipulated
639 */
640static void ManipulateAtoms(periodentafel *periode, MoleculeListClass *molecules, config *configuration)
641{
642 atom *first, *second;
643 molecule *mol = NULL;
644 Vector x,y,z,n; // coordinates for absolute point in cell volume
645 double *factor; // unit factor if desired
646 double bond, min_bond;
647 char choice; // menu choice char
648 bool valid;
649
650 cout << Verbose(0) << "=========MANIPULATE ATOMS======================" << endl;
651 cout << Verbose(0) << "a - add an atom" << endl;
652 cout << Verbose(0) << "r - remove an atom" << endl;
653 cout << Verbose(0) << "b - scale a bond between atoms" << endl;
654 cout << Verbose(0) << "u - change an atoms element" << endl;
655 cout << Verbose(0) << "l - measure lengths, angles, ... for an atom" << endl;
656 cout << Verbose(0) << "all else - go back" << endl;
657 cout << Verbose(0) << "===============================================" << endl;
658 if (molecules->NumberOfActiveMolecules() > 1)
659 cout << Verbose(0) << "WARNING: There is more than one molecule active! Atoms will be added to each." << endl;
660 cout << Verbose(0) << "INPUT: ";
661 cin >> choice;
662
663 switch (choice) {
664 default:
665 cout << Verbose(0) << "Not a valid choice." << endl;
666 break;
667
668 case 'a': // add atom
669 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
670 if ((*ListRunner)->ActiveFlag) {
671 mol = *ListRunner;
672 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
673 AddAtoms(periode, mol);
674 }
675 break;
676
677 case 'b': // scale a bond
678 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
679 if ((*ListRunner)->ActiveFlag) {
680 mol = *ListRunner;
681 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
682 cout << Verbose(0) << "Scaling bond length between two atoms." << endl;
683 first = mol->AskAtom("Enter first (fixed) atom: ");
684 second = mol->AskAtom("Enter second (shifting) atom: ");
685 min_bond = 0.;
686 for (int i=NDIM;i--;)
687 min_bond += (first->x.x[i]-second->x.x[i])*(first->x.x[i] - second->x.x[i]);
688 min_bond = sqrt(min_bond);
689 cout << Verbose(0) << "Current Bond length between " << first->type->name << " Atom " << first->nr << " and " << second->type->name << " Atom " << second->nr << ": " << min_bond << " a.u." << endl;
690 cout << Verbose(0) << "Enter new bond length [a.u.]: ";
691 cin >> bond;
692 for (int i=NDIM;i--;) {
693 second->x.x[i] -= (second->x.x[i]-first->x.x[i])/min_bond*(min_bond-bond);
694 }
695 //cout << Verbose(0) << "New coordinates of Atom " << second->nr << " are: ";
696 //second->Output(second->type->No, 1, (ofstream *)&cout);
697 }
698 break;
699
700 case 'c': // unit scaling of the metric
701 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
702 if ((*ListRunner)->ActiveFlag) {
703 mol = *ListRunner;
704 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
705 cout << Verbose(0) << "Angstroem -> Bohrradius: 1.8897261\t\tBohrradius -> Angstroem: 0.52917721" << endl;
706 cout << Verbose(0) << "Enter three factors: ";
707 factor = new double[NDIM];
708 cin >> factor[0];
709 cin >> factor[1];
710 cin >> factor[2];
711 valid = true;
712 mol->Scale(&factor);
713 delete[](factor);
714 }
715 break;
716
717 case 'l': // measure distances or angles
718 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
719 if ((*ListRunner)->ActiveFlag) {
720 mol = *ListRunner;
721 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
722 MeasureAtoms(periode, mol, configuration);
723 }
724 break;
725
726 case 'r': // remove atom
727 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
728 if ((*ListRunner)->ActiveFlag) {
729 mol = *ListRunner;
730 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
731 RemoveAtoms(mol);
732 }
733 break;
734
735 case 'u': // change an atom's element
736 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
737 if ((*ListRunner)->ActiveFlag) {
738 int Z;
739 mol = *ListRunner;
740 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
741 first = NULL;
742 do {
743 cout << Verbose(0) << "Change the element of which atom: ";
744 cin >> Z;
745 } while ((first = mol->FindAtom(Z)) == NULL);
746 cout << Verbose(0) << "New element by atomic number Z: ";
747 cin >> Z;
748 first->type = periode->FindElement(Z);
749 cout << Verbose(0) << "Atom " << first->nr << "'s element is " << first->type->name << "." << endl;
750 }
751 break;
752 }
753};
754
755/** Submenu for manipulating molecules.
756 * \param *periode periodentafel
757 * \param *molecules list of molecule to manipulate
758 */
759static void ManipulateMolecules(periodentafel *periode, MoleculeListClass *molecules, config *configuration)
760{
761 atom *first = NULL;
762 Vector x,y,z,n; // coordinates for absolute point in cell volume
763 int j, axis, count, faktor;
764 char choice; // menu choice char
765 molecule *mol = NULL;
766 element **Elements;
767 Vector **vectors;
768 MoleculeLeafClass *Subgraphs = NULL;
769
770 cout << Verbose(0) << "=========MANIPULATE GLOBALLY===================" << endl;
771 cout << Verbose(0) << "c - scale by unit transformation" << endl;
772 cout << Verbose(0) << "d - duplicate molecule/periodic cell" << endl;
773 cout << Verbose(0) << "f - fragment molecule many-body bond order style" << endl;
774 cout << Verbose(0) << "g - center atoms in box" << endl;
775 cout << Verbose(0) << "i - realign molecule" << endl;
776 cout << Verbose(0) << "m - mirror all molecules" << endl;
777 cout << Verbose(0) << "o - create connection matrix" << endl;
778 cout << Verbose(0) << "t - translate molecule by vector" << endl;
779 cout << Verbose(0) << "all else - go back" << endl;
780 cout << Verbose(0) << "===============================================" << endl;
781 if (molecules->NumberOfActiveMolecules() > 1)
782 cout << Verbose(0) << "WARNING: There is more than one molecule active! Atoms will be added to each." << endl;
783 cout << Verbose(0) << "INPUT: ";
784 cin >> choice;
785
786 switch (choice) {
787 default:
788 cout << Verbose(0) << "Not a valid choice." << endl;
789 break;
790
791 case 'd': // duplicate the periodic cell along a given axis, given times
792 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
793 if ((*ListRunner)->ActiveFlag) {
794 mol = *ListRunner;
795 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
796 cout << Verbose(0) << "State the axis [(+-)123]: ";
797 cin >> axis;
798 cout << Verbose(0) << "State the factor: ";
799 cin >> faktor;
800
801 mol->CountAtoms((ofstream *)&cout); // recount atoms
802 if (mol->AtomCount != 0) { // if there is more than none
803 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand
804 Elements = new element *[count];
805 vectors = new Vector *[count];
806 j = 0;
807 first = mol->start;
808 while (first->next != mol->end) { // make a list of all atoms with coordinates and element
809 first = first->next;
810 Elements[j] = first->type;
811 vectors[j] = &first->x;
812 j++;
813 }
814 if (count != j)
815 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl;
816 x.Zero();
817 y.Zero();
818 y.x[abs(axis)-1] = mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] * abs(axis)/axis; // last term is for sign, first is for magnitude
819 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times
820 x.AddVector(&y); // per factor one cell width further
821 for (int k=count;k--;) { // go through every atom of the original cell
822 first = new atom(); // create a new body
823 first->x.CopyVector(vectors[k]); // use coordinate of original atom
824 first->x.AddVector(&x); // translate the coordinates
825 first->type = Elements[k]; // insert original element
826 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)
827 }
828 }
829 if (mol->first->next != mol->last) // if connect matrix is present already, redo it
830 mol->CreateAdjacencyList((ofstream *)&cout, mol->BondDistance, configuration->GetIsAngstroem());
831 // free memory
832 delete[](Elements);
833 delete[](vectors);
834 // correct cell size
835 if (axis < 0) { // if sign was negative, we have to translate everything
836 x.Zero();
837 x.AddVector(&y);
838 x.Scale(-(faktor-1));
839 mol->Translate(&x);
840 }
841 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor;
842 }
843 }
844 break;
845
846 case 'f':
847 FragmentAtoms(mol, configuration);
848 break;
849
850 case 'g': // center the atoms
851 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
852 if ((*ListRunner)->ActiveFlag) {
853 mol = *ListRunner;
854 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
855 CenterAtoms(mol);
856 }
857 break;
858
859 case 'i': // align all atoms
860 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
861 if ((*ListRunner)->ActiveFlag) {
862 mol = *ListRunner;
863 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
864 AlignAtoms(periode, mol);
865 }
866 break;
867
868 case 'm': // mirror atoms along a given axis
869 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
870 if ((*ListRunner)->ActiveFlag) {
871 mol = *ListRunner;
872 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
873 MirrorAtoms(mol);
874 }
875 break;
876
877 case 'o': // create the connection matrix
878 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
879 if ((*ListRunner)->ActiveFlag) {
880 mol = *ListRunner;
881 double bonddistance;
882 clock_t start,end;
883 cout << Verbose(0) << "What's the maximum bond distance: ";
884 cin >> bonddistance;
885 start = clock();
886 mol->CreateAdjacencyList((ofstream *)&cout, bonddistance, configuration->GetIsAngstroem());
887 mol->CreateListOfBondsPerAtom((ofstream *)&cout);
888 end = clock();
889 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
890 }
891 break;
892
893 case 't': // translate all atoms
894 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
895 if ((*ListRunner)->ActiveFlag) {
896 mol = *ListRunner;
897 cout << Verbose(0) << "Current molecule is: " << mol->IndexNr << "\t" << mol->name << endl;
898 cout << Verbose(0) << "Enter translation vector." << endl;
899 x.AskPosition(mol->cell_size,0);
900 mol->Center.AddVector((const Vector *)&x);
901 }
902 break;
903 }
904 // Free all
905 if (Subgraphs != NULL) { // free disconnected subgraph list of DFS analysis was performed
906 while (Subgraphs->next != NULL) {
907 Subgraphs = Subgraphs->next;
908 delete(Subgraphs->previous);
909 }
910 delete(Subgraphs);
911 }
912};
913
914
915/** Submenu for creating new molecules.
916 * \param *periode periodentafel
917 * \param *molecules list of molecules to add to
918 */
919static void EditMolecules(periodentafel *periode, MoleculeListClass *molecules)
920{
921 char choice; // menu choice char
922 Vector center;
923 int nr, count;
924 molecule *mol = NULL;
925
926 cout << Verbose(0) << "==========EDIT MOLECULES=====================" << endl;
927 cout << Verbose(0) << "c - create new molecule" << endl;
928 cout << Verbose(0) << "l - load molecule from xyz file" << endl;
929 cout << Verbose(0) << "n - change molecule's name" << endl;
930 cout << Verbose(0) << "N - give molecules filename" << endl;
931 cout << Verbose(0) << "p - parse atoms in xyz file into molecule" << endl;
932 cout << Verbose(0) << "r - remove a molecule" << endl;
933 cout << Verbose(0) << "all else - go back" << endl;
934 cout << Verbose(0) << "===============================================" << endl;
935 cout << Verbose(0) << "INPUT: ";
936 cin >> choice;
937
938 switch (choice) {
939 default:
940 cout << Verbose(0) << "Not a valid choice." << endl;
941 break;
942 case 'c':
943 mol = new molecule(periode);
944 molecules->insert(mol);
945 break;
946
947 case 'l': // load from XYZ file
948 {
949 char filename[MAXSTRINGSIZE];
950 cout << Verbose(0) << "Format should be XYZ with: ShorthandOfElement\tX\tY\tZ" << endl;
951 mol = new molecule(periode);
952 do {
953 cout << Verbose(0) << "Enter file name: ";
954 cin >> filename;
955 } while (!mol->AddXYZFile(filename));
956 mol->SetNameFromFilename(filename);
957 // center at set box dimensions
958 mol->CenterEdge((ofstream *)&cout, &center);
959 mol->cell_size[0] = center.x[0];
960 mol->cell_size[1] = 0;
961 mol->cell_size[2] = center.x[1];
962 mol->cell_size[3] = 0;
963 mol->cell_size[4] = 0;
964 mol->cell_size[5] = center.x[2];
965 molecules->insert(mol);
966 }
967 break;
968
969 case 'n':
970 {
971 char filename[MAXSTRINGSIZE];
972 do {
973 cout << Verbose(0) << "Enter index of molecule: ";
974 cin >> nr;
975 mol = molecules->ReturnIndex(nr);
976 } while (mol == NULL);
977 cout << Verbose(0) << "Enter name: ";
978 cin >> filename;
979 strcpy(mol->name, filename);
980 }
981 break;
982
983 case 'N':
984 {
985 char filename[MAXSTRINGSIZE];
986 do {
987 cout << Verbose(0) << "Enter index of molecule: ";
988 cin >> nr;
989 mol = molecules->ReturnIndex(nr);
990 } while (mol == NULL);
991 cout << Verbose(0) << "Enter name: ";
992 cin >> filename;
993 mol->SetNameFromFilename(filename);
994 }
995 break;
996
997 case 'p': // parse XYZ file
998 {
999 char filename[MAXSTRINGSIZE];
1000 mol = NULL;
1001 do {
1002 cout << Verbose(0) << "Enter index of molecule: ";
1003 cin >> nr;
1004 mol = molecules->ReturnIndex(nr);
1005 } while (mol == NULL);
1006 cout << Verbose(0) << "Format should be XYZ with: ShorthandOfElement\tX\tY\tZ" << endl;
1007 do {
1008 cout << Verbose(0) << "Enter file name: ";
1009 cin >> filename;
1010 } while (!mol->AddXYZFile(filename));
1011 mol->SetNameFromFilename(filename);
1012 }
1013 break;
1014
1015 case 'r':
1016 cout << Verbose(0) << "Enter index of molecule: ";
1017 cin >> nr;
1018 count = 1;
1019 for( MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
1020 if (nr == (*ListRunner)->IndexNr) {
1021 mol = *ListRunner;
1022 molecules->ListOfMolecules.erase(ListRunner);
1023 delete(mol);
1024 }
1025 break;
1026 }
1027};
1028
1029
1030/** Submenu for merging molecules.
1031 * \param *periode periodentafel
1032 * \param *molecules list of molecules to add to
1033 */
1034static void MergeMolecules(periodentafel *periode, MoleculeListClass *molecules)
1035{
1036 char choice; // menu choice char
1037
1038 cout << Verbose(0) << "===========MERGE MOLECULES=====================" << endl;
1039 cout << Verbose(0) << "a - simple add of one molecule to another" << endl;
1040 cout << Verbose(0) << "e - embedding merge of two molecules" << endl;
1041 cout << Verbose(0) << "m - multi-merge of all molecules" << endl;
1042 cout << Verbose(0) << "s - scatter merge of two molecules" << endl;
1043 cout << Verbose(0) << "t - simple merge of two molecules" << endl;
1044 cout << Verbose(0) << "all else - go back" << endl;
1045 cout << Verbose(0) << "===============================================" << endl;
1046 cout << Verbose(0) << "INPUT: ";
1047 cin >> choice;
1048
1049 switch (choice) {
1050 default:
1051 cout << Verbose(0) << "Not a valid choice." << endl;
1052 break;
1053
1054 case 'a':
1055 {
1056 int src, dest;
1057 molecule *srcmol = NULL, *destmol = NULL;
1058 {
1059 do {
1060 cout << Verbose(0) << "Enter index of destination molecule: ";
1061 cin >> dest;
1062 destmol = molecules->ReturnIndex(dest);
1063 } while ((destmol == NULL) && (dest != -1));
1064 do {
1065 cout << Verbose(0) << "Enter index of source molecule to add from: ";
1066 cin >> src;
1067 srcmol = molecules->ReturnIndex(src);
1068 } while ((srcmol == NULL) && (src != -1));
1069 if ((src != -1) && (dest != -1))
1070 molecules->SimpleAdd(srcmol, destmol);
1071 }
1072 }
1073 break;
1074
1075 case 'e':
1076 cout << Verbose(0) << "Not implemented yet." << endl;
1077 break;
1078
1079 case 'm':
1080 {
1081 int nr;
1082 molecule *mol = NULL;
1083 do {
1084 cout << Verbose(0) << "Enter index of molecule to merge into: ";
1085 cin >> nr;
1086 mol = molecules->ReturnIndex(nr);
1087 } while ((mol == NULL) && (nr != -1));
1088 if (nr != -1) {
1089 int N = molecules->ListOfMolecules.size()-1;
1090 int *src = new int(N);
1091 for(MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
1092 if ((*ListRunner)->IndexNr != nr)
1093 src[N++] = (*ListRunner)->IndexNr;
1094 molecules->SimpleMultiMerge(mol, src, N);
1095 delete[](src);
1096 }
1097 }
1098 break;
1099
1100 case 's':
1101 cout << Verbose(0) << "Not implemented yet." << endl;
1102 break;
1103
1104 case 't':
1105 {
1106 int src, dest;
1107 molecule *srcmol = NULL, *destmol = NULL;
1108 {
1109 do {
1110 cout << Verbose(0) << "Enter index of destination molecule: ";
1111 cin >> dest;
1112 destmol = molecules->ReturnIndex(dest);
1113 } while ((destmol == NULL) && (dest != -1));
1114 do {
1115 cout << Verbose(0) << "Enter index of source molecule to merge into: ";
1116 cin >> src;
1117 srcmol = molecules->ReturnIndex(src);
1118 } while ((srcmol == NULL) && (src != -1));
1119 if ((src != -1) && (dest != -1))
1120 molecules->SimpleMerge(srcmol, destmol);
1121 }
1122 }
1123 break;
1124 }
1125};
1126
1127
1128/********************************************** Test routine **************************************/
1129
1130/** Is called always as option 'T' in the menu.
1131 * \param *molecules list of molecules
1132 */
1133static void testroutine(MoleculeListClass *molecules)
1134{
1135 // the current test routine checks the functionality of the KeySet&Graph concept:
1136 // We want to have a multiindex (the KeySet) describing a unique subgraph
1137 int i, comp, counter=0;
1138
1139 // create a clone
1140 molecule *mol = NULL;
1141 if (molecules->ListOfMolecules.size() != 0) // clone
1142 mol = (molecules->ListOfMolecules.front())->CopyMolecule();
1143 else {
1144 cerr << "I don't have anything to test on ... ";
1145 return;
1146 }
1147 atom *Walker = mol->start;
1148
1149 // generate some KeySets
1150 cout << "Generating KeySets." << endl;
1151 KeySet TestSets[mol->AtomCount+1];
1152 i=1;
1153 while (Walker->next != mol->end) {
1154 Walker = Walker->next;
1155 for (int j=0;j<i;j++) {
1156 TestSets[j].insert(Walker->nr);
1157 }
1158 i++;
1159 }
1160 cout << "Testing insertion of already present item in KeySets." << endl;
1161 KeySetTestPair test;
1162 test = TestSets[mol->AtomCount-1].insert(Walker->nr);
1163 if (test.second) {
1164 cout << Verbose(1) << "Insertion worked?!" << endl;
1165 } else {
1166 cout << Verbose(1) << "Insertion rejected: Present object is " << (*test.first) << "." << endl;
1167 }
1168 TestSets[mol->AtomCount].insert(mol->end->previous->nr);
1169 TestSets[mol->AtomCount].insert(mol->end->previous->previous->previous->nr);
1170
1171 // constructing Graph structure
1172 cout << "Generating Subgraph class." << endl;
1173 Graph Subgraphs;
1174
1175 // insert KeySets into Subgraphs
1176 cout << "Inserting KeySets into Subgraph class." << endl;
1177 for (int j=0;j<mol->AtomCount;j++) {
1178 Subgraphs.insert(GraphPair (TestSets[j],pair<int, double>(counter++, 1.)));
1179 }
1180 cout << "Testing insertion of already present item in Subgraph." << endl;
1181 GraphTestPair test2;
1182 test2 = Subgraphs.insert(GraphPair (TestSets[mol->AtomCount],pair<int, double>(counter++, 1.)));
1183 if (test2.second) {
1184 cout << Verbose(1) << "Insertion worked?!" << endl;
1185 } else {
1186 cout << Verbose(1) << "Insertion rejected: Present object is " << (*(test2.first)).second.first << "." << endl;
1187 }
1188
1189 // show graphs
1190 cout << "Showing Subgraph's contents, checking that it's sorted." << endl;
1191 Graph::iterator A = Subgraphs.begin();
1192 while (A != Subgraphs.end()) {
1193 cout << (*A).second.first << ": ";
1194 KeySet::iterator key = (*A).first.begin();
1195 comp = -1;
1196 while (key != (*A).first.end()) {
1197 if ((*key) > comp)
1198 cout << (*key) << " ";
1199 else
1200 cout << (*key) << "! ";
1201 comp = (*key);
1202 key++;
1203 }
1204 cout << endl;
1205 A++;
1206 }
1207 delete(mol);
1208};
1209
1210/** Tries given filename or standard on saving the config file.
1211 * \param *ConfigFileName name of file
1212 * \param *configuration pointer to configuration structure with all the values
1213 * \param *periode pointer to periodentafel structure with all the elements
1214 * \param *molecules list of molecules structure with all the atoms and coordinates
1215 */
1216static void SaveConfig(char *ConfigFileName, config *configuration, periodentafel *periode, MoleculeListClass *molecules)
1217{
1218 char filename[MAXSTRINGSIZE];
1219 ofstream output;
1220 molecule *mol = new molecule(periode);
1221
1222 // translate each to its center and merge all molecules in MoleculeListClass into this molecule
1223 int N = molecules->ListOfMolecules.size();
1224 int *src = new int(N);
1225 N=0;
1226 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++) {
1227 src[N++] = (*ListRunner)->IndexNr;
1228 (*ListRunner)->Translate(&(*ListRunner)->Center);
1229 }
1230 molecules->SimpleMultiAdd(mol, src, N);
1231 delete(src);
1232
1233 // ... and translate back
1234 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++) {
1235 (*ListRunner)->Center.Scale(-1.);
1236 (*ListRunner)->Translate(&(*ListRunner)->Center);
1237 (*ListRunner)->Center.Scale(-1.);
1238 }
1239
1240 cout << Verbose(0) << "Storing configuration ... " << endl;
1241 // get correct valence orbitals
1242 mol->CalculateOrbitals(*configuration);
1243 configuration->InitMaxMinStopStep = configuration->MaxMinStopStep = configuration->MaxPsiDouble;
1244 if (ConfigFileName != NULL) { // test the file name
1245 strcpy(filename, ConfigFileName);
1246 output.open(filename, ios::trunc);
1247 } else if (strlen(configuration->configname) != 0) {
1248 strcpy(filename, configuration->configname);
1249 output.open(configuration->configname, ios::trunc);
1250 } else {
1251 strcpy(filename, DEFAULTCONFIG);
1252 output.open(DEFAULTCONFIG, ios::trunc);
1253 }
1254 output.close();
1255 output.clear();
1256 cout << Verbose(0) << "Saving of config file ";
1257 if (configuration->Save(filename, periode, mol))
1258 cout << "successful." << endl;
1259 else
1260 cout << "failed." << endl;
1261
1262 // and save to xyz file
1263 if (ConfigFileName != NULL) {
1264 strcpy(filename, ConfigFileName);
1265 strcat(filename, ".xyz");
1266 output.open(filename, ios::trunc);
1267 }
1268 if (output == NULL) {
1269 strcpy(filename,"main_pcp_linux");
1270 strcat(filename, ".xyz");
1271 output.open(filename, ios::trunc);
1272 }
1273 cout << Verbose(0) << "Saving of XYZ file ";
1274 if (mol->MDSteps <= 1) {
1275 if (mol->OutputXYZ(&output))
1276 cout << "successful." << endl;
1277 else
1278 cout << "failed." << endl;
1279 } else {
1280 if (mol->OutputTrajectoriesXYZ(&output))
1281 cout << "successful." << endl;
1282 else
1283 cout << "failed." << endl;
1284 }
1285 output.close();
1286 output.clear();
1287
1288 // and save as MPQC configuration
1289 if (ConfigFileName != NULL)
1290 strcpy(filename, ConfigFileName);
1291 if (output == NULL)
1292 strcpy(filename,"main_pcp_linux");
1293 cout << Verbose(0) << "Saving as mpqc input ";
1294 if (configuration->SaveMPQC(filename, mol))
1295 cout << "done." << endl;
1296 else
1297 cout << "failed." << endl;
1298
1299 if (!strcmp(configuration->configpath, configuration->GetDefaultPath())) {
1300 cerr << "WARNING: config is found under different path then stated in config file::defaultpath!" << endl;
1301 }
1302 delete(mol);
1303};
1304
1305/** Parses the command line options.
1306 * \param argc argument count
1307 * \param **argv arguments array
1308 * \param *molecules list of molecules structure
1309 * \param *periode elements structure
1310 * \param configuration config file structure
1311 * \param *ConfigFileName pointer to config file name in **argv
1312 * \param *PathToDatabases pointer to db's path in **argv
1313 * \return exit code (0 - successful, all else - something's wrong)
1314 */
1315static int ParseCommandLineOptions(int argc, char **argv, MoleculeListClass *&molecules, periodentafel *&periode, config& configuration, char *&ConfigFileName)
1316{
1317 Vector x,y,z,n; // coordinates for absolute point in cell volume
1318 double *factor; // unit factor if desired
1319 ifstream test;
1320 ofstream output;
1321 string line;
1322 atom *first;
1323 bool SaveFlag = false;
1324 int ExitFlag = 0;
1325 int j;
1326 double volume = 0.;
1327 enum ConfigStatus config_present = absent;
1328 clock_t start,end;
1329 int argptr;
1330 molecule *mol = NULL;
1331 strncpy(configuration.databasepath, LocalPath, MAXSTRINGSIZE-1);
1332
1333 if (argc > 1) { // config file specified as option
1334 // 1. : Parse options that just set variables or print help
1335 argptr = 1;
1336 do {
1337 if (argv[argptr][0] == '-') {
1338 cout << Verbose(0) << "Recognized command line argument: " << argv[argptr][1] << ".\n";
1339 argptr++;
1340 switch(argv[argptr-1][1]) {
1341 case 'h':
1342 case 'H':
1343 case '?':
1344 cout << "MoleCuilder suite" << endl << "==================" << endl << endl;
1345 cout << "Usage: " << argv[0] << "[config file] [-{acefpsthH?vfrp}] [further arguments]" << endl;
1346 cout << "or simply " << argv[0] << " without arguments for interactive session." << endl;
1347 cout << "\t-a Z x1 x2 x3\tAdd new atom of element Z at coordinates (x1,x2,x3)." << endl;
1348 cout << "\t-A <source>\tCreate adjacency list from bonds parsed from 'dbond'-style file." <<endl;
1349 cout << "\t-b xx xy xz yy yz zz\tCenter atoms in domain with given symmetric matrix of (xx,xy,xz,yy,yz,zz)." << endl;
1350 cout << "\t-B xx xy xz yy yz zz\tBound atoms by domain with given symmetric matrix of (xx,xy,xz,yy,yz,zz)." << endl;
1351 cout << "\t-c x1 x2 x3\tCenter atoms in domain with a minimum distance to boundary of (x1,x2,x3)." << endl;
1352 cout << "\t-D <bond distance>\tDepth-First-Search Analysis of the molecule, giving cycles and tree/back edges." << endl;
1353 cout << "\t-O\tCenter atoms in origin." << endl;
1354 cout << "\t-d x1 x2 x3\tDuplicate cell along each axis by given factor." << endl;
1355 cout << "\t-e <file>\tSets the databases path to be parsed (default: ./)." << endl;
1356 cout << "\t-E <id> <Z>\tChange atom <id>'s element to <Z>, <id> begins at 0." << endl;
1357 cout << "\t-f/F <dist> <order>\tFragments the molecule in BOSSANOVA manner (with/out rings compressed) and stores config files in same dir as config (return code 0 - fragmented, 2 - no fragmentation necessary)." << endl;
1358 cout << "\t-h/-H/-?\tGive this help screen." << endl;
1359 cout << "\t-m <0/1>\tCalculate (0)/ Align in(1) PAS with greatest EV along z axis." << endl;
1360 cout << "\t-M <basis>\tSetting basis to store to MPQC config files." << endl;
1361 cout << "\t-n\tFast parsing (i.e. no trajectories are looked for)." << endl;
1362 cout << "\t-N <radius> <file>\tGet non-convex-envelope." << endl;
1363 cout << "\t-o <out>\tGet volume of the convex envelope (and store to tecplot file)." << endl;
1364 cout << "\t-p <file>\tParse given xyz file and create raw config file from it." << endl;
1365 cout << "\t-P <file>\tParse given forces file and append as an MD step to config file via Verlet." << endl;
1366 cout << "\t-L <step0> <step1> <prefix>\tStore a linear interpolation between two configurations <step0> and <step1> into single config files with prefix <prefix> and as Trajectories into the current config file." << endl;
1367 cout << "\t-r\t\tConvert file from an old pcp syntax." << endl;
1368 cout << "\t-R\t\tRemove all atoms out of sphere around a given one." << endl;
1369 cout << "\t-t x1 x2 x3\tTranslate all atoms by this vector (x1,x2,x3)." << endl;
1370 cout << "\t-T x1 x2 x3\tTranslate periodically all atoms by this vector (x1,x2,x3)." << endl;
1371 cout << "\t-S <file> Store temperatures from the config file in <file>." << endl;
1372 cout << "\t-s x1 x2 x3\tScale all atom coordinates by this vector (x1,x2,x3)." << endl;
1373 cout << "\t-u rho\tsuspend in water solution and output necessary cell lengths, average density rho and repetition." << endl;
1374 cout << "\t-v/-V\t\tGives version information." << endl;
1375 cout << "Note: config files must not begin with '-' !" << endl;
1376 return (1);
1377 break;
1378 case 'v':
1379 case 'V':
1380 cout << argv[0] << " " << VERSIONSTRING << endl;
1381 cout << "Build your own molecule position set." << endl;
1382 return (1);
1383 break;
1384 case 'e':
1385 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1386 cerr << "Not enough or invalid arguments for specifying element db: -e <db file>" << endl;
1387 } else {
1388 cout << "Using " << argv[argptr] << " as elements database." << endl;
1389 strncpy (configuration.databasepath, argv[argptr], MAXSTRINGSIZE-1);
1390 argptr+=1;
1391 }
1392 break;
1393 case 'n':
1394 cout << "I won't parse trajectories." << endl;
1395 configuration.FastParsing = true;
1396 break;
1397 default: // no match? Step on
1398 argptr++;
1399 break;
1400 }
1401 } else
1402 argptr++;
1403 } while (argptr < argc);
1404
1405 // 2. Parse the element database
1406 if (periode->LoadPeriodentafel(configuration.databasepath)) {
1407 cout << Verbose(0) << "Element list loaded successfully." << endl;
1408 //periode->Output((ofstream *)&cout);
1409 } else {
1410 cout << Verbose(0) << "Element list loading failed." << endl;
1411 return 1;
1412 }
1413 // 3. Find config file name and parse if possible
1414 if (argv[1][0] != '-') {
1415 // simply create a new molecule, wherein the config file is loaded and the manipulation takes place
1416 mol = new molecule(periode);
1417 mol->ActiveFlag = true;
1418 molecules->insert(mol);
1419
1420 cout << Verbose(0) << "Config file given." << endl;
1421 test.open(argv[1], ios::in);
1422 if (test == NULL) {
1423 //return (1);
1424 output.open(argv[1], ios::out);
1425 if (output == NULL) {
1426 cout << Verbose(1) << "Specified config file " << argv[1] << " not found." << endl;
1427 config_present = absent;
1428 } else {
1429 cout << "Empty configuration file." << endl;
1430 ConfigFileName = argv[1];
1431 config_present = empty;
1432 output.close();
1433 }
1434 } else {
1435 test.close();
1436 ConfigFileName = argv[1];
1437 cout << Verbose(1) << "Specified config file found, parsing ... ";
1438 switch (configuration.TestSyntax(ConfigFileName, periode, mol)) {
1439 case 1:
1440 cout << "new syntax." << endl;
1441 configuration.Load(ConfigFileName, periode, mol);
1442 config_present = present;
1443 break;
1444 case 0:
1445 cout << "old syntax." << endl;
1446 configuration.LoadOld(ConfigFileName, periode, mol);
1447 config_present = present;
1448 break;
1449 default:
1450 cout << "Unknown syntax or empty, yet present file." << endl;
1451 config_present = empty;
1452 }
1453 }
1454 } else
1455 config_present = absent;
1456 // 4. parse again through options, now for those depending on elements db and config presence
1457 argptr = 1;
1458 do {
1459 cout << "Current Command line argument: " << argv[argptr] << "." << endl;
1460 if (argv[argptr][0] == '-') {
1461 argptr++;
1462 if ((config_present == present) || (config_present == empty)) {
1463 switch(argv[argptr-1][1]) {
1464 case 'p':
1465 ExitFlag = 1;
1466 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1467 ExitFlag = 255;
1468 cerr << "Not enough arguments for parsing: -p <xyz file>" << endl;
1469 } else {
1470 SaveFlag = true;
1471 cout << Verbose(1) << "Parsing xyz file for new atoms." << endl;
1472 if (!mol->AddXYZFile(argv[argptr]))
1473 cout << Verbose(2) << "File not found." << endl;
1474 else {
1475 cout << Verbose(2) << "File found and parsed." << endl;
1476 config_present = present;
1477 }
1478 }
1479 break;
1480 case 'a':
1481 ExitFlag = 1;
1482 if ((argptr >= argc) || (argv[argptr][0] == '-') || (!IsValidNumber(argv[argptr+1]))) {
1483 ExitFlag = 255;
1484 cerr << "Not enough or invalid arguments for adding atom: -a <element> <x> <y> <z>" << endl;
1485 } else {
1486 SaveFlag = true;
1487 cout << Verbose(1) << "Adding new atom with element " << argv[argptr] << " at (" << argv[argptr+1] << "," << argv[argptr+2] << "," << argv[argptr+3] << "), ";
1488 first = new atom;
1489 first->type = periode->FindElement(atoi(argv[argptr]));
1490 if (first->type != NULL)
1491 cout << Verbose(2) << "found element " << first->type->name << endl;
1492 for (int i=NDIM;i--;)
1493 first->x.x[i] = atof(argv[argptr+1+i]);
1494 if (first->type != NULL) {
1495 mol->AddAtom(first); // add to molecule
1496 if ((config_present == empty) && (mol->AtomCount != 0))
1497 config_present = present;
1498 } else
1499 cerr << Verbose(1) << "Could not find the specified element." << endl;
1500 argptr+=4;
1501 }
1502 break;
1503 default: // no match? Don't step on (this is done in next switch's default)
1504 break;
1505 }
1506 }
1507 if (config_present == present) {
1508 switch(argv[argptr-1][1]) {
1509 case 'M':
1510 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1511 ExitFlag = 255;
1512 cerr << "Not enough or invalid arguments given for setting MPQC basis: -B <basis name>" << endl;
1513 } else {
1514 configuration.basis = argv[argptr];
1515 cout << Verbose(1) << "Setting MPQC basis to " << configuration.basis << "." << endl;
1516 argptr+=1;
1517 }
1518 break;
1519 case 'D':
1520 ExitFlag = 1;
1521 {
1522 cout << Verbose(1) << "Depth-First-Search Analysis." << endl;
1523 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
1524 int *MinimumRingSize = new int[mol->AtomCount];
1525 atom ***ListOfLocalAtoms = NULL;
1526 int FragmentCounter = 0;
1527 class StackClass<bond *> *BackEdgeStack = NULL;
1528 class StackClass<bond *> *LocalBackEdgeStack = NULL;
1529 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr]), configuration.GetIsAngstroem());
1530 mol->CreateListOfBondsPerAtom((ofstream *)&cout);
1531 Subgraphs = mol->DepthFirstSearchAnalysis((ofstream *)&cout, BackEdgeStack);
1532 if (Subgraphs != NULL) {
1533 Subgraphs->next->FillBondStructureFromReference((ofstream *)&cout, mol, (FragmentCounter = 0), ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms
1534 while (Subgraphs->next != NULL) {
1535 Subgraphs = Subgraphs->next;
1536 LocalBackEdgeStack = new StackClass<bond *> (Subgraphs->Leaf->BondCount);
1537 Subgraphs->Leaf->PickLocalBackEdges((ofstream *)&cout, ListOfLocalAtoms[FragmentCounter++], BackEdgeStack, LocalBackEdgeStack);
1538 Subgraphs->Leaf->CyclicStructureAnalysis((ofstream *)&cout, BackEdgeStack, MinimumRingSize);
1539 delete(LocalBackEdgeStack);
1540 delete(Subgraphs->previous);
1541 }
1542 delete(Subgraphs);
1543 for (int i=0;i<FragmentCounter;i++)
1544 Free((void **)&ListOfLocalAtoms[FragmentCounter], "ParseCommandLineOptions: **ListOfLocalAtoms[]");
1545 Free((void **)&ListOfLocalAtoms, "ParseCommandLineOptions: ***ListOfLocalAtoms");
1546 }
1547 delete(BackEdgeStack);
1548 delete[](MinimumRingSize);
1549 }
1550 //argptr+=1;
1551 break;
1552 case 'E':
1553 ExitFlag = 1;
1554 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (argv[argptr+1][0] == '-')) {
1555 ExitFlag = 255;
1556 cerr << "Not enough or invalid arguments given for changing element: -E <atom nr.> <element>" << endl;
1557 } else {
1558 SaveFlag = true;
1559 cout << Verbose(1) << "Changing atom " << argv[argptr] << " to element " << argv[argptr+1] << "." << endl;
1560 first = mol->FindAtom(atoi(argv[argptr]));
1561 first->type = periode->FindElement(atoi(argv[argptr+1]));
1562 argptr+=2;
1563 }
1564 break;
1565 case 'F':
1566 ExitFlag = 1;
1567 if (argptr+5 >=argc) {
1568 ExitFlag = 255;
1569 cerr << "Not enough or invalid arguments given for filling box with water: -F <dist_x> <dist_y> <dist_z> <randatom> <randmol> <DoRotate>" << endl;
1570 } else {
1571 SaveFlag = true;
1572 cout << Verbose(1) << "Filling Box with water molecules." << endl;
1573 // construct water molecule
1574 molecule *filler = new molecule(periode);;
1575 molecule *Filling = NULL;
1576 atom *second = NULL, *third = NULL;
1577 first = new atom();
1578 first->type = periode->FindElement(1);
1579 first->x.Init(0.441, -0.143, 0.);
1580 filler->AddAtom(first);
1581 second = new atom();
1582 second->type = periode->FindElement(1);
1583 second->x.Init(-0.464, 1.137, 0.0);
1584 filler->AddAtom(second);
1585 third = new atom();
1586 third->type = periode->FindElement(8);
1587 third->x.Init(-0.464, 0.177, 0.);
1588 filler->AddAtom(third);
1589 filler->AddBond(first, third, 1);
1590 filler->AddBond(second, third, 1);
1591 // call routine
1592 double distance[NDIM];
1593 for (int i=0;i<NDIM;i++)
1594 distance[i] = atof(argv[argptr+i]);
1595 Filling = FillBoxWithMolecule((ofstream *)&cout, molecules, filler, configuration, distance, atof(argv[argptr+3]), atof(argv[argptr+4]), atoi(argv[argptr+5]));
1596 if (Filling != NULL) {
1597 molecules->insert(Filling);
1598 }
1599 delete(filler);
1600 argptr+=6;
1601 }
1602 break;
1603 case 'A':
1604 ExitFlag = 1;
1605 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1606 ExitFlag =255;
1607 cerr << "Missing source file for bonds in molecule: -A <bond sourcefile>" << endl;
1608 } else {
1609 cout << "Parsing bonds from " << argv[argptr] << "." << endl;
1610 ifstream *input = new ifstream(argv[argptr]);
1611 mol->CreateAdjacencyList2((ofstream *)&cout, input);
1612 input->close();
1613 argptr+=1;
1614 }
1615 break;
1616 case 'N':
1617 ExitFlag = 1;
1618 if ((argptr+1 >= argc) || (argv[argptr+1][0] == '-')){
1619 ExitFlag = 255;
1620 cerr << "Not enough or invalid arguments given for non-convex envelope: -o <radius> <tecplot output file>" << endl;
1621 } else {
1622 class Tesselation T;
1623 string filename(argv[argptr+1]);
1624 filename.append(".csv");
1625 cout << Verbose(0) << "Evaluating non-convex envelope.";
1626 cout << Verbose(1) << "Using rolling ball of radius " << atof(argv[argptr]) << " and storing tecplot data in " << argv[argptr+1] << "." << endl;
1627 start = clock();
1628 LinkedCell LCList(mol, atof(argv[argptr])*2.);
1629 Find_non_convex_border((ofstream *)&cout, mol, &LCList, argv[argptr+1], atof(argv[argptr]));
1630 //FindDistributionOfEllipsoids((ofstream *)&cout, &T, &LCList, N, number, filename.c_str());
1631 end = clock();
1632 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
1633 argptr+=2;
1634 }
1635 break;
1636 case 'S':
1637 ExitFlag = 1;
1638 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1639 ExitFlag = 255;
1640 cerr << "Not enough or invalid arguments given for storing tempature: -S <temperature file>" << endl;
1641 } else {
1642 cout << Verbose(1) << "Storing temperatures in " << argv[argptr] << "." << endl;
1643 ofstream *output = new ofstream(argv[argptr], ios::trunc);
1644 if (!mol->OutputTemperatureFromTrajectories((ofstream *)&cout, 0, mol->MDSteps, output))
1645 cout << Verbose(2) << "File could not be written." << endl;
1646 else
1647 cout << Verbose(2) << "File stored." << endl;
1648 output->close();
1649 delete(output);
1650 argptr+=1;
1651 }
1652 break;
1653 case 'L':
1654 ExitFlag = 1;
1655 SaveFlag = true;
1656 cout << Verbose(1) << "Linear interpolation between configuration " << argv[argptr] << " and " << argv[argptr+1] << "." << endl;
1657 if (!mol->LinearInterpolationBetweenConfiguration((ofstream *)&cout, atoi(argv[argptr]), atoi(argv[argptr+1]), argv[argptr+2], configuration))
1658 cout << Verbose(2) << "Could not store " << argv[argptr+2] << " files." << endl;
1659 else
1660 cout << Verbose(2) << "Steps created and " << argv[argptr+2] << " files stored." << endl;
1661 argptr+=3;
1662 break;
1663 case 'P':
1664 ExitFlag = 1;
1665 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1666 ExitFlag = 255;
1667 cerr << "Not enough or invalid arguments given for parsing and integrating forces: -P <forces file>" << endl;
1668 } else {
1669 SaveFlag = true;
1670 cout << Verbose(1) << "Parsing forces file and Verlet integrating." << endl;
1671 if (!mol->VerletForceIntegration((ofstream *)&cout, argv[argptr], configuration))
1672 cout << Verbose(2) << "File not found." << endl;
1673 else
1674 cout << Verbose(2) << "File found and parsed." << endl;
1675 argptr+=1;
1676 }
1677 break;
1678 case 'R':
1679 ExitFlag = 1;
1680 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1]))) {
1681 ExitFlag = 255;
1682 cerr << "Not enough or invalid arguments given for removing atoms: -R <id> <distance>" << endl;
1683 } else {
1684 SaveFlag = true;
1685 cout << Verbose(1) << "Removing atoms around " << argv[argptr] << " with radius " << argv[argptr+1] << "." << endl;
1686 double tmp1 = atof(argv[argptr+1]);
1687 atom *third = mol->FindAtom(atoi(argv[argptr]));
1688 atom *first = mol->start;
1689 if ((third != NULL) && (first != mol->end)) {
1690 atom *second = first->next;
1691 while(second != mol->end) {
1692 first = second;
1693 second = first->next;
1694 if (first->x.DistanceSquared((const Vector *)&third->x) > tmp1*tmp1) // distance to first above radius ...
1695 mol->RemoveAtom(first);
1696 }
1697 } else {
1698 cerr << "Removal failed due to missing atoms on molecule or wrong id." << endl;
1699 }
1700 argptr+=2;
1701 }
1702 break;
1703 case 't':
1704 ExitFlag = 1;
1705 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) {
1706 ExitFlag = 255;
1707 cerr << "Not enough or invalid arguments given for translation: -t <x> <y> <z>" << endl;
1708 } else {
1709 ExitFlag = 1;
1710 SaveFlag = true;
1711 cout << Verbose(1) << "Translating all ions to new origin." << endl;
1712 for (int i=NDIM;i--;)
1713 x.x[i] = atof(argv[argptr+i]);
1714 mol->Translate((const Vector *)&x);
1715 argptr+=3;
1716 }
1717 case 'T':
1718 ExitFlag = 1;
1719 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) {
1720 ExitFlag = 255;
1721 cerr << "Not enough or invalid arguments given for periodic translation: -T <x> <y> <z>" << endl;
1722 } else {
1723 ExitFlag = 1;
1724 SaveFlag = true;
1725 cout << Verbose(1) << "Translating all ions periodically to new origin." << endl;
1726 for (int i=NDIM;i--;)
1727 x.x[i] = atof(argv[argptr+i]);
1728 mol->TranslatePeriodically((const Vector *)&x);
1729 argptr+=3;
1730 }
1731 break;
1732 case 's':
1733 ExitFlag = 1;
1734 if ((argptr >= argc) || (!IsValidNumber(argv[argptr])) ) {
1735 ExitFlag = 255;
1736 cerr << "Not enough or invalid arguments given for scaling: -s <factor/[factor_x]> [factor_y] [factor_z]" << endl;
1737 } else {
1738 SaveFlag = true;
1739 j = -1;
1740 cout << Verbose(1) << "Scaling all ion positions by factor." << endl;
1741 factor = new double[NDIM];
1742 factor[0] = atof(argv[argptr]);
1743 if ((argptr < argc) && (IsValidNumber(argv[argptr])))
1744 argptr++;
1745 factor[1] = atof(argv[argptr]);
1746 if ((argptr < argc) && (IsValidNumber(argv[argptr])))
1747 argptr++;
1748 factor[2] = atof(argv[argptr]);
1749 mol->Scale(&factor);
1750 for (int i=0;i<NDIM;i++) {
1751 j += i+1;
1752 x.x[i] = atof(argv[NDIM+i]);
1753 mol->cell_size[j]*=factor[i];
1754 }
1755 delete[](factor);
1756 argptr+=1;
1757 }
1758 break;
1759 case 'b':
1760 ExitFlag = 1;
1761 if ((argptr+5 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) || (!IsValidNumber(argv[argptr+3])) || (!IsValidNumber(argv[argptr+4])) || (!IsValidNumber(argv[argptr+5])) ) {
1762 ExitFlag = 255;
1763 cerr << "Not enough or invalid arguments given for centering in box: -b <xx> <xy> <xz> <yy> <yz> <zz>" << endl;
1764 } else {
1765 SaveFlag = true;
1766 j = -1;
1767 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl;
1768 for (int i=0;i<6;i++) {
1769 mol->cell_size[i] = atof(argv[argptr+i]);
1770 }
1771 // center
1772 mol->CenterInBox((ofstream *)&cout);
1773 argptr+=6;
1774 }
1775 break;
1776 case 'B':
1777 ExitFlag = 1;
1778 if ((argptr+5 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) || (!IsValidNumber(argv[argptr+3])) || (!IsValidNumber(argv[argptr+4])) || (!IsValidNumber(argv[argptr+5])) ) {
1779 ExitFlag = 255;
1780 cerr << "Not enough or invalid arguments given for bounding in box: -B <xx> <xy> <xz> <yy> <yz> <zz>" << endl;
1781 } else {
1782 SaveFlag = true;
1783 j = -1;
1784 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl;
1785 for (int i=0;i<6;i++) {
1786 mol->cell_size[i] = atof(argv[argptr+i]);
1787 }
1788 // center
1789 mol->BoundInBox((ofstream *)&cout);
1790 argptr+=6;
1791 }
1792 break;
1793 case 'c':
1794 ExitFlag = 1;
1795 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) {
1796 ExitFlag = 255;
1797 cerr << "Not enough or invalid arguments given for centering with boundary: -c <boundary_x> <boundary_y> <boundary_z>" << endl;
1798 } else {
1799 SaveFlag = true;
1800 j = -1;
1801 cout << Verbose(1) << "Centering atoms in config file within given additional boundary." << endl;
1802 // make every coordinate positive
1803 mol->CenterEdge((ofstream *)&cout, &x);
1804 // update Box of atoms by boundary
1805 mol->SetBoxDimension(&x);
1806 // translate each coordinate by boundary
1807 j=-1;
1808 for (int i=0;i<NDIM;i++) {
1809 j += i+1;
1810 x.x[i] = atof(argv[argptr+i]);
1811 mol->cell_size[j] += x.x[i]*2.;
1812 }
1813 mol->Translate((const Vector *)&x);
1814 argptr+=3;
1815 }
1816 break;
1817 case 'O':
1818 ExitFlag = 1;
1819 SaveFlag = true;
1820 cout << Verbose(1) << "Centering atoms on edge and setting box dimensions." << endl;
1821 x.Zero();
1822 mol->CenterEdge((ofstream *)&cout, &x);
1823 mol->SetBoxDimension(&x);
1824 argptr+=0;
1825 break;
1826 case 'r':
1827 ExitFlag = 1;
1828 SaveFlag = true;
1829 cout << Verbose(1) << "Converting config file from supposed old to new syntax." << endl;
1830 break;
1831 case 'f':
1832 ExitFlag = 1;
1833 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1]))) {
1834 ExitFlag = 255;
1835 cerr << "Not enough or invalid arguments for fragmentation: -f <max. bond distance> <bond order>" << endl;
1836 } else {
1837 cout << "Fragmenting molecule with bond distance " << argv[argptr] << " angstroem, order of " << argv[argptr+1] << "." << endl;
1838 cout << Verbose(0) << "Creating connection matrix..." << endl;
1839 start = clock();
1840 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr++]), configuration.GetIsAngstroem());
1841 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl;
1842 if (mol->first->next != mol->last) {
1843 ExitFlag = mol->FragmentMolecule((ofstream *)&cout, atoi(argv[argptr]), &configuration);
1844 }
1845 end = clock();
1846 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
1847 argptr+=2;
1848 }
1849 break;
1850 case 'm':
1851 ExitFlag = 1;
1852 j = atoi(argv[argptr++]);
1853 if ((j<0) || (j>1)) {
1854 cerr << Verbose(1) << "ERROR: Argument of '-m' should be either 0 for no-rotate or 1 for rotate." << endl;
1855 j = 0;
1856 }
1857 if (j) {
1858 SaveFlag = true;
1859 cout << Verbose(0) << "Converting to prinicipal axis system." << endl;
1860 } else
1861 cout << Verbose(0) << "Evaluating prinicipal axis." << endl;
1862 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)j);
1863 break;
1864 case 'o':
1865 ExitFlag = 1;
1866 if ((argptr >= argc) || (argv[argptr][0] == '-')){
1867 ExitFlag = 255;
1868 cerr << "Not enough or invalid arguments given for convex envelope: -o <tecplot output file>" << endl;
1869 } else {
1870 cout << Verbose(0) << "Evaluating volume of the convex envelope.";
1871 cout << Verbose(1) << "Storing tecplot data in " << argv[argptr] << "." << endl;
1872 LinkedCell LCList(mol, 10.);
1873 //Find_convex_border((ofstream *)&cout, mol, &LCList, argv[argptr]);
1874 Find_non_convex_border((ofstream *)&cout, mol, &LCList, argv[argptr], 10.);
1875
1876 double volumedifference = ConvexizeNonconvexEnvelope((ofstream *)&cout, mol->TesselStruct);
1877 double clustervolume = VolumeOfConvexEnvelope((ofstream *)&cout, mol->TesselStruct, &configuration);
1878 cout << Verbose(0) << "The tesselated surface area is " << clustervolume << " " << (configuration.GetIsAngstroem() ? "angstrom" : "atomiclength") << "^3." << endl;
1879 cout << Verbose(0) << "The non-convex tesselated surface area is " << clustervolume-volumedifference << " " << (configuration.GetIsAngstroem() ? "angstrom" : "atomiclength") << "^3." << endl;
1880 argptr+=1;
1881 }
1882 break;
1883 case 'U':
1884 ExitFlag = 1;
1885 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) ) {
1886 ExitFlag = 255;
1887 cerr << "Not enough or invalid arguments given for suspension with specified volume: -U <volume> <density>" << endl;
1888 volume = -1; // for case 'u': don't print error again
1889 } else {
1890 volume = atof(argv[argptr++]);
1891 cout << Verbose(0) << "Using " << volume << " angstrom^3 as the volume instead of convex envelope one's." << endl;
1892 }
1893 case 'u':
1894 ExitFlag = 1;
1895 if ((argptr >= argc) || (!IsValidNumber(argv[argptr])) ) {
1896 if (volume != -1)
1897 ExitFlag = 255;
1898 cerr << "Not enough arguments given for suspension: -u <density>" << endl;
1899 } else {
1900 double density;
1901 SaveFlag = true;
1902 cout << Verbose(0) << "Evaluating necessary cell volume for a cluster suspended in water.";
1903 density = atof(argv[argptr++]);
1904 if (density < 1.0) {
1905 cerr << Verbose(0) << "Density must be greater than 1.0g/cm^3 !" << endl;
1906 density = 1.3;
1907 }
1908// for(int i=0;i<NDIM;i++) {
1909// repetition[i] = atoi(argv[argptr++]);
1910// if (repetition[i] < 1)
1911// cerr << Verbose(0) << "ERROR: repetition value must be greater 1!" << endl;
1912// repetition[i] = 1;
1913// }
1914 PrepareClustersinWater((ofstream *)&cout, &configuration, mol, volume, density); // if volume == 0, will calculate from ConvexEnvelope
1915 }
1916 break;
1917 case 'd':
1918 ExitFlag = 1;
1919 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) {
1920 ExitFlag = 255;
1921 cerr << "Not enough or invalid arguments given for repeating cells: -d <repeat_x> <repeat_y> <repeat_z>" << endl;
1922 } else {
1923 SaveFlag = true;
1924 for (int axis = 1; axis <= NDIM; axis++) {
1925 int faktor = atoi(argv[argptr++]);
1926 int count;
1927 element ** Elements;
1928 Vector ** vectors;
1929 if (faktor < 1) {
1930 cerr << Verbose(0) << "ERROR: Repetition faktor mus be greater than 1!" << endl;
1931 faktor = 1;
1932 }
1933 mol->CountAtoms((ofstream *)&cout); // recount atoms
1934 if (mol->AtomCount != 0) { // if there is more than none
1935 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand
1936 Elements = new element *[count];
1937 vectors = new Vector *[count];
1938 j = 0;
1939 first = mol->start;
1940 while (first->next != mol->end) { // make a list of all atoms with coordinates and element
1941 first = first->next;
1942 Elements[j] = first->type;
1943 vectors[j] = &first->x;
1944 j++;
1945 }
1946 if (count != j)
1947 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl;
1948 x.Zero();
1949 y.Zero();
1950 y.x[abs(axis)-1] = mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] * abs(axis)/axis; // last term is for sign, first is for magnitude
1951 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times
1952 x.AddVector(&y); // per factor one cell width further
1953 for (int k=count;k--;) { // go through every atom of the original cell
1954 first = new atom(); // create a new body
1955 first->x.CopyVector(vectors[k]); // use coordinate of original atom
1956 first->x.AddVector(&x); // translate the coordinates
1957 first->type = Elements[k]; // insert original element
1958 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)
1959 }
1960 }
1961 // free memory
1962 delete[](Elements);
1963 delete[](vectors);
1964 // correct cell size
1965 if (axis < 0) { // if sign was negative, we have to translate everything
1966 x.Zero();
1967 x.AddVector(&y);
1968 x.Scale(-(faktor-1));
1969 mol->Translate(&x);
1970 }
1971 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor;
1972 }
1973 }
1974 }
1975 break;
1976 default: // no match? Step on
1977 if ((argptr < argc) && (argv[argptr][0] != '-')) // if it started with a '-' we've already made a step!
1978 argptr++;
1979 break;
1980 }
1981 }
1982 } else argptr++;
1983 } while (argptr < argc);
1984 if (SaveFlag)
1985 SaveConfig(ConfigFileName, &configuration, periode, molecules);
1986 } else { // no arguments, hence scan the elements db
1987 if (periode->LoadPeriodentafel(configuration.databasepath))
1988 cout << Verbose(0) << "Element list loaded successfully." << endl;
1989 else
1990 cout << Verbose(0) << "Element list loading failed." << endl;
1991 configuration.RetrieveConfigPathAndName("main_pcp_linux");
1992 }
1993 return(ExitFlag);
1994};
1995
1996/********************************************** Main routine **************************************/
1997
1998int main(int argc, char **argv)
1999{
2000 periodentafel *periode = new periodentafel; // and a period table of all elements
2001 MoleculeListClass *molecules = new MoleculeListClass; // list of all molecules
2002 molecule *mol = NULL;
2003 config configuration;
2004 char choice; // menu choice char
2005 Vector x,y,z,n; // coordinates for absolute point in cell volume
2006 ifstream test;
2007 ofstream output;
2008 string line;
2009 char *ConfigFileName = NULL;
2010 int j;
2011
2012 // =========================== PARSE COMMAND LINE OPTIONS ====================================
2013 j = ParseCommandLineOptions(argc, argv, molecules, periode, configuration, ConfigFileName);
2014 switch(j) {
2015 case 255: // something went wrong
2016 delete(molecules); // also free's all molecules contained
2017 delete(periode);
2018 return j;
2019 break;
2020 case 1: // just for -v and -h options
2021 delete(molecules); // also free's all molecules contained
2022 delete(periode);
2023 return 0;
2024 break;
2025 default:
2026 break;
2027 }
2028
2029 // General stuff
2030 if (molecules->ListOfMolecules.size() == 0) {
2031 mol = new molecule(periode);
2032 if (mol->cell_size[0] == 0.) {
2033 cout << Verbose(0) << "enter lower tridiagonal form of basis matrix" << endl << endl;
2034 for (int i=0;i<6;i++) {
2035 cout << Verbose(1) << "Cell size" << i << ": ";
2036 cin >> mol->cell_size[i];
2037 }
2038 }
2039 molecules->insert(mol);
2040 }
2041
2042 // =========================== START INTERACTIVE SESSION ====================================
2043
2044 // now the main construction loop
2045 cout << Verbose(0) << endl << "Now comes the real construction..." << endl;
2046 do {
2047 cout << Verbose(0) << endl << endl;
2048 cout << Verbose(0) << "============Molecule list=======================" << endl;
2049 molecules->Enumerate((ofstream *)&cout);
2050 cout << Verbose(0) << "============Menu===============================" << endl;
2051 cout << Verbose(0) << "a - set molecule (in)active" << endl;
2052 cout << Verbose(0) << "e - edit molecules (load, parse, save)" << endl;
2053 cout << Verbose(0) << "g - globally manipulate atoms in molecule" << endl;
2054 cout << Verbose(0) << "M - Merge molecules" << endl;
2055 cout << Verbose(0) << "m - manipulate atoms" << endl;
2056 cout << Verbose(0) << "-----------------------------------------------" << endl;
2057 cout << Verbose(0) << "c - edit the current configuration" << endl;
2058 cout << Verbose(0) << "-----------------------------------------------" << endl;
2059 cout << Verbose(0) << "s - save current setup to config file" << endl;
2060 cout << Verbose(0) << "T - call the current test routine" << endl;
2061 cout << Verbose(0) << "q - quit" << endl;
2062 cout << Verbose(0) << "===============================================" << endl;
2063 cout << Verbose(0) << "Input: ";
2064 cin >> choice;
2065
2066 switch (choice) {
2067 case 'a': // (in)activate molecule
2068 {
2069 cout << "Enter index of molecule: ";
2070 cin >> j;
2071 for(MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
2072 if ((*ListRunner)->IndexNr == j)
2073 (*ListRunner)->ActiveFlag = !(*ListRunner)->ActiveFlag;
2074 }
2075 break;
2076
2077 case 'c': // edit each field of the configuration
2078 configuration.Edit();
2079 break;
2080
2081 case 'e': // create molecule
2082 EditMolecules(periode, molecules);
2083 break;
2084
2085 case 'g': // manipulate molecules
2086 ManipulateMolecules(periode, molecules, &configuration);
2087 break;
2088
2089 case 'M': // merge molecules
2090 MergeMolecules(periode, molecules);
2091 break;
2092
2093 case 'm': // manipulate atoms
2094 ManipulateAtoms(periode, molecules, &configuration);
2095 break;
2096
2097 case 'q': // quit
2098 break;
2099
2100 case 's': // save to config file
2101 SaveConfig(ConfigFileName, &configuration, periode, molecules);
2102 break;
2103
2104 case 'T':
2105 testroutine(molecules);
2106 break;
2107
2108 default:
2109 break;
2110 };
2111 } while (choice != 'q');
2112
2113 // save element data base
2114 if (periode->StorePeriodentafel(configuration.databasepath)) //ElementsFileName
2115 cout << Verbose(0) << "Saving of elements.db successful." << endl;
2116 else
2117 cout << Verbose(0) << "Saving of elements.db failed." << endl;
2118
2119 delete(molecules); // also free's all molecules contained
2120 delete(periode);
2121 return (0);
2122}
2123
2124/********************************************** E N D **************************************************/
Note: See TracBrowser for help on using the repository browser.