source: src/builder.cpp@ 2319ed

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

We are one step further in fixing the convex hull: There are two functions of Saskia Metzler missing, but then we may proceed with testing whether the simple correction scheme of the convex envelope works, but one thing: Right now we cannot associate a Tesselation to its molecule as the snake bites it's one tail. Hence, the next commit will consist of fixing this bad-OOP issue.

  • Makefile.am: Just some alphabetical resorting.
  • atom::atom() new copy constructor
  • builder.cpp: some output for cluster volume, molecule::AddCopyAtom() uses new copy constructor
  • FillBoxWithMolecule() - new function to fill the remainder of the simulation box with some given filler molecules. Makes explicit use of the tesselated surfaces
  • find_convex_border() - InsertStraddlingPoints() and CorrectConcaveBaselines() is called to correct for atoms outside the envelope and caused-by concave points
  • Tesselation::InsertStraddlingPoints() enlarges the envelope for all atoms found outside, Tesselation::CorrectConcaveBaselines() corrects all found baselines if the adjacent triangles are concave by flipping.
  • boundary.cpp: Lots of helper routines for stuff further below:
  • The following routines are needed to check whether point is in- or outside:
  • FIX: Tesselation::AddPoint() - newly created BoundaryPoint is removed if already present.

Problem: We want to associate a Tesselation class with each molecule class. However, so far we have to know about atoms and bond and molecules inside the Tesselation. We have to remove this dependency and create some intermediate class which enables/encapsulates the access to Vectors, e.g. hidden inside the atom class. This is also good OOP! The Tesselation also only needs a set of Vectors, not more!

  • Property mode set to 100755
File size: 85.6 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, TesselStruct, &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 // ... and translate back
1233 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++) {
1234 (*ListRunner)->Center.Scale(-1.);
1235 (*ListRunner)->Translate(&(*ListRunner)->Center);
1236 (*ListRunner)->Center.Scale(-1.);
1237 }
1238
1239 cout << Verbose(0) << "Storing configuration ... " << endl;
1240 // get correct valence orbitals
1241 mol->CalculateOrbitals(*configuration);
1242 configuration->InitMaxMinStopStep = configuration->MaxMinStopStep = configuration->MaxPsiDouble;
1243 if (ConfigFileName != NULL) { // test the file name
1244 strcpy(filename, ConfigFileName);
1245 output.open(filename, ios::trunc);
1246 } else if (strlen(configuration->configname) != 0) {
1247 strcpy(filename, configuration->configname);
1248 output.open(configuration->configname, ios::trunc);
1249 } else {
1250 strcpy(filename, DEFAULTCONFIG);
1251 output.open(DEFAULTCONFIG, ios::trunc);
1252 }
1253 output.close();
1254 output.clear();
1255 cout << Verbose(0) << "Saving of config file ";
1256 if (configuration->Save(filename, periode, mol))
1257 cout << "successful." << endl;
1258 else
1259 cout << "failed." << endl;
1260
1261 // and save to xyz file
1262 if (ConfigFileName != NULL) {
1263 strcpy(filename, ConfigFileName);
1264 strcat(filename, ".xyz");
1265 output.open(filename, ios::trunc);
1266 }
1267 if (output == NULL) {
1268 strcpy(filename,"main_pcp_linux");
1269 strcat(filename, ".xyz");
1270 output.open(filename, ios::trunc);
1271 }
1272 cout << Verbose(0) << "Saving of XYZ file ";
1273 if (mol->MDSteps <= 1) {
1274 if (mol->OutputXYZ(&output))
1275 cout << "successful." << endl;
1276 else
1277 cout << "failed." << endl;
1278 } else {
1279 if (mol->OutputTrajectoriesXYZ(&output))
1280 cout << "successful." << endl;
1281 else
1282 cout << "failed." << endl;
1283 }
1284 output.close();
1285 output.clear();
1286
1287 // and save as MPQC configuration
1288 if (ConfigFileName != NULL)
1289 strcpy(filename, ConfigFileName);
1290 if (output == NULL)
1291 strcpy(filename,"main_pcp_linux");
1292 cout << Verbose(0) << "Saving as mpqc input ";
1293 if (configuration->SaveMPQC(filename, mol))
1294 cout << "done." << endl;
1295 else
1296 cout << "failed." << endl;
1297
1298 if (!strcmp(configuration->configpath, configuration->GetDefaultPath())) {
1299 cerr << "WARNING: config is found under different path then stated in config file::defaultpath!" << endl;
1300 }
1301 delete(mol);
1302};
1303
1304/** Parses the command line options.
1305 * \param argc argument count
1306 * \param **argv arguments array
1307 * \param *molecules list of molecules structure
1308 * \param *periode elements structure
1309 * \param configuration config file structure
1310 * \param *ConfigFileName pointer to config file name in **argv
1311 * \param *PathToDatabases pointer to db's path in **argv
1312 * \return exit code (0 - successful, all else - something's wrong)
1313 */
1314static int ParseCommandLineOptions(int argc, char **argv, MoleculeListClass *&molecules, periodentafel *&periode, config& configuration, char *&ConfigFileName)
1315{
1316 Vector x,y,z,n; // coordinates for absolute point in cell volume
1317 double *factor; // unit factor if desired
1318 ifstream test;
1319 ofstream output;
1320 string line;
1321 atom *first;
1322 bool SaveFlag = false;
1323 int ExitFlag = 0;
1324 int j;
1325 double volume = 0.;
1326 enum ConfigStatus config_present = absent;
1327 clock_t start,end;
1328 int argptr;
1329 molecule *mol = NULL;
1330 strncpy(configuration.databasepath, LocalPath, MAXSTRINGSIZE-1);
1331
1332 if (argc > 1) { // config file specified as option
1333 // 1. : Parse options that just set variables or print help
1334 argptr = 1;
1335 do {
1336 if (argv[argptr][0] == '-') {
1337 cout << Verbose(0) << "Recognized command line argument: " << argv[argptr][1] << ".\n";
1338 argptr++;
1339 switch(argv[argptr-1][1]) {
1340 case 'h':
1341 case 'H':
1342 case '?':
1343 cout << "MoleCuilder suite" << endl << "==================" << endl << endl;
1344 cout << "Usage: " << argv[0] << "[config file] [-{acefpsthH?vfrp}] [further arguments]" << endl;
1345 cout << "or simply " << argv[0] << " without arguments for interactive session." << endl;
1346 cout << "\t-a Z x1 x2 x3\tAdd new atom of element Z at coordinates (x1,x2,x3)." << endl;
1347 cout << "\t-A <source>\tCreate adjacency list from bonds parsed from 'dbond'-style file." <<endl;
1348 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;
1349 cout << "\t-B <basis>\tSetting basis to store to MPQC config files." << endl;
1350 cout << "\t-c x1 x2 x3\tCenter atoms in domain with a minimum distance to boundary of (x1,x2,x3)." << endl;
1351 cout << "\t-D <bond distance>\tDepth-First-Search Analysis of the molecule, giving cycles and tree/back edges." << endl;
1352 cout << "\t-O\tCenter atoms in origin." << endl;
1353 cout << "\t-d x1 x2 x3\tDuplicate cell along each axis by given factor." << endl;
1354 cout << "\t-e <file>\tSets the databases path to be parsed (default: ./)." << endl;
1355 cout << "\t-E <id> <Z>\tChange atom <id>'s element to <Z>, <id> begins at 0." << endl;
1356 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;
1357 cout << "\t-h/-H/-?\tGive this help screen." << endl;
1358 cout << "\t-m <0/1>\tCalculate (0)/ Align in(1) PAS with greatest EV along z axis." << endl;
1359 cout << "\t-n\tFast parsing (i.e. no trajectories are looked for)." << endl;
1360 cout << "\t-N <radius> <file>\tGet non-convex-envelope." << endl;
1361 cout << "\t-o <out>\tGet volume of the convex envelope (and store to tecplot file)." << endl;
1362 cout << "\t-p <file>\tParse given xyz file and create raw config file from it." << endl;
1363 cout << "\t-P <file>\tParse given forces file and append as an MD step to config file via Verlet." << endl;
1364 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;
1365 cout << "\t-r\t\tConvert file from an old pcp syntax." << endl;
1366 cout << "\t-R\t\tRemove all atoms out of sphere around a given one." << endl;
1367 cout << "\t-t x1 x2 x3\tTranslate all atoms by this vector (x1,x2,x3)." << endl;
1368 cout << "\t-T x1 x2 x3\tTranslate periodically all atoms by this vector (x1,x2,x3)." << endl;
1369 cout << "\t-S <file> Store temperatures from the config file in <file>." << endl;
1370 cout << "\t-s x1 x2 x3\tScale all atom coordinates by this vector (x1,x2,x3)." << endl;
1371 cout << "\t-u rho\tsuspend in water solution and output necessary cell lengths, average density rho and repetition." << endl;
1372 cout << "\t-v/-V\t\tGives version information." << endl;
1373 cout << "Note: config files must not begin with '-' !" << endl;
1374 return (1);
1375 break;
1376 case 'v':
1377 case 'V':
1378 cout << argv[0] << " " << VERSIONSTRING << endl;
1379 cout << "Build your own molecule position set." << endl;
1380 return (1);
1381 break;
1382 case 'e':
1383 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1384 cerr << "Not enough or invalid arguments for specifying element db: -e <db file>" << endl;
1385 } else {
1386 cout << "Using " << argv[argptr] << " as elements database." << endl;
1387 strncpy (configuration.databasepath, argv[argptr], MAXSTRINGSIZE-1);
1388 argptr+=1;
1389 }
1390 break;
1391 case 'n':
1392 cout << "I won't parse trajectories." << endl;
1393 configuration.FastParsing = true;
1394 break;
1395 default: // no match? Step on
1396 argptr++;
1397 break;
1398 }
1399 } else
1400 argptr++;
1401 } while (argptr < argc);
1402
1403 // 2. Parse the element database
1404 if (periode->LoadPeriodentafel(configuration.databasepath)) {
1405 cout << Verbose(0) << "Element list loaded successfully." << endl;
1406 //periode->Output((ofstream *)&cout);
1407 } else {
1408 cout << Verbose(0) << "Element list loading failed." << endl;
1409 return 1;
1410 }
1411 // 3. Find config file name and parse if possible
1412 if (argv[1][0] != '-') {
1413 // simply create a new molecule, wherein the config file is loaded and the manipulation takes place
1414 mol = new molecule(periode);
1415 mol->ActiveFlag = true;
1416 molecules->insert(mol);
1417
1418 cout << Verbose(0) << "Config file given." << endl;
1419 test.open(argv[1], ios::in);
1420 if (test == NULL) {
1421 //return (1);
1422 output.open(argv[1], ios::out);
1423 if (output == NULL) {
1424 cout << Verbose(1) << "Specified config file " << argv[1] << " not found." << endl;
1425 config_present = absent;
1426 } else {
1427 cout << "Empty configuration file." << endl;
1428 ConfigFileName = argv[1];
1429 config_present = empty;
1430 output.close();
1431 }
1432 } else {
1433 test.close();
1434 ConfigFileName = argv[1];
1435 cout << Verbose(1) << "Specified config file found, parsing ... ";
1436 switch (configuration.TestSyntax(ConfigFileName, periode, mol)) {
1437 case 1:
1438 cout << "new syntax." << endl;
1439 configuration.Load(ConfigFileName, periode, mol);
1440 config_present = present;
1441 break;
1442 case 0:
1443 cout << "old syntax." << endl;
1444 configuration.LoadOld(ConfigFileName, periode, mol);
1445 config_present = present;
1446 break;
1447 default:
1448 cout << "Unknown syntax or empty, yet present file." << endl;
1449 config_present = empty;
1450 }
1451 }
1452 } else
1453 config_present = absent;
1454 // 4. parse again through options, now for those depending on elements db and config presence
1455 argptr = 1;
1456 do {
1457 cout << "Current Command line argument: " << argv[argptr] << "." << endl;
1458 if (argv[argptr][0] == '-') {
1459 argptr++;
1460 if ((config_present == present) || (config_present == empty)) {
1461 switch(argv[argptr-1][1]) {
1462 case 'p':
1463 ExitFlag = 1;
1464 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1465 ExitFlag = 255;
1466 cerr << "Not enough arguments for parsing: -p <xyz file>" << endl;
1467 } else {
1468 SaveFlag = true;
1469 cout << Verbose(1) << "Parsing xyz file for new atoms." << endl;
1470 if (!mol->AddXYZFile(argv[argptr]))
1471 cout << Verbose(2) << "File not found." << endl;
1472 else {
1473 cout << Verbose(2) << "File found and parsed." << endl;
1474 config_present = present;
1475 }
1476 }
1477 break;
1478 case 'a':
1479 ExitFlag = 1;
1480 if ((argptr >= argc) || (argv[argptr][0] == '-') || (!IsValidNumber(argv[argptr+1]))) {
1481 ExitFlag = 255;
1482 cerr << "Not enough or invalid arguments for adding atom: -a <element> <x> <y> <z>" << endl;
1483 } else {
1484 SaveFlag = true;
1485 cout << Verbose(1) << "Adding new atom with element " << argv[argptr] << " at (" << argv[argptr+1] << "," << argv[argptr+2] << "," << argv[argptr+3] << "), ";
1486 first = new atom;
1487 first->type = periode->FindElement(atoi(argv[argptr]));
1488 if (first->type != NULL)
1489 cout << Verbose(2) << "found element " << first->type->name << endl;
1490 for (int i=NDIM;i--;)
1491 first->x.x[i] = atof(argv[argptr+1+i]);
1492 if (first->type != NULL) {
1493 mol->AddAtom(first); // add to molecule
1494 if ((config_present == empty) && (mol->AtomCount != 0))
1495 config_present = present;
1496 } else
1497 cerr << Verbose(1) << "Could not find the specified element." << endl;
1498 argptr+=4;
1499 }
1500 break;
1501 default: // no match? Don't step on (this is done in next switch's default)
1502 break;
1503 }
1504 }
1505 if (config_present == present) {
1506 switch(argv[argptr-1][1]) {
1507 case 'B':
1508 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1509 ExitFlag = 255;
1510 cerr << "Not enough or invalid arguments given for setting MPQC basis: -B <basis name>" << endl;
1511 } else {
1512 configuration.basis = argv[argptr];
1513 cout << Verbose(1) << "Setting MPQC basis to " << configuration.basis << "." << endl;
1514 argptr+=1;
1515 }
1516 break;
1517 case 'D':
1518 ExitFlag = 1;
1519 {
1520 cout << Verbose(1) << "Depth-First-Search Analysis." << endl;
1521 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
1522 int *MinimumRingSize = new int[mol->AtomCount];
1523 atom ***ListOfLocalAtoms = NULL;
1524 int FragmentCounter = 0;
1525 class StackClass<bond *> *BackEdgeStack = NULL;
1526 class StackClass<bond *> *LocalBackEdgeStack = NULL;
1527 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr]), configuration.GetIsAngstroem());
1528 mol->CreateListOfBondsPerAtom((ofstream *)&cout);
1529 Subgraphs = mol->DepthFirstSearchAnalysis((ofstream *)&cout, BackEdgeStack);
1530 if (Subgraphs != NULL) {
1531 Subgraphs->next->FillBondStructureFromReference((ofstream *)&cout, mol, (FragmentCounter = 0), ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms
1532 while (Subgraphs->next != NULL) {
1533 Subgraphs = Subgraphs->next;
1534 LocalBackEdgeStack = new StackClass<bond *> (Subgraphs->Leaf->BondCount);
1535 Subgraphs->Leaf->PickLocalBackEdges((ofstream *)&cout, ListOfLocalAtoms[FragmentCounter++], BackEdgeStack, LocalBackEdgeStack);
1536 Subgraphs->Leaf->CyclicStructureAnalysis((ofstream *)&cout, BackEdgeStack, MinimumRingSize);
1537 delete(LocalBackEdgeStack);
1538 delete(Subgraphs->previous);
1539 }
1540 delete(Subgraphs);
1541 for (int i=0;i<FragmentCounter;i++)
1542 Free((void **)&ListOfLocalAtoms[FragmentCounter], "ParseCommandLineOptions: **ListOfLocalAtoms[]");
1543 Free((void **)&ListOfLocalAtoms, "ParseCommandLineOptions: ***ListOfLocalAtoms");
1544 }
1545 delete(BackEdgeStack);
1546 delete[](MinimumRingSize);
1547 }
1548 //argptr+=1;
1549 break;
1550 case 'E':
1551 ExitFlag = 1;
1552 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (argv[argptr+1][0] == '-')) {
1553 ExitFlag = 255;
1554 cerr << "Not enough or invalid arguments given for changing element: -E <atom nr.> <element>" << endl;
1555 } else {
1556 SaveFlag = true;
1557 cout << Verbose(1) << "Changing atom " << argv[argptr] << " to element " << argv[argptr+1] << "." << endl;
1558 first = mol->FindAtom(atoi(argv[argptr]));
1559 first->type = periode->FindElement(atoi(argv[argptr+1]));
1560 argptr+=2;
1561 }
1562 break;
1563 case 'A':
1564 ExitFlag = 1;
1565 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1566 ExitFlag =255;
1567 cerr << "Missing source file for bonds in molecule: -A <bond sourcefile>" << endl;
1568 } else {
1569 cout << "Parsing bonds from " << argv[argptr] << "." << endl;
1570 ifstream *input = new ifstream(argv[argptr]);
1571 mol->CreateAdjacencyList2((ofstream *)&cout, input);
1572 input->close();
1573 argptr+=1;
1574 }
1575 break;
1576 case 'N':
1577 ExitFlag = 1;
1578 if ((argptr+1 >= argc) || (argv[argptr+1][0] == '-')){
1579 ExitFlag = 255;
1580 cerr << "Not enough or invalid arguments given for non-convex envelope: -o <radius> <tecplot output file>" << endl;
1581 } else {
1582 class Tesselation T;
1583 string filename(argv[argptr+1]);
1584 filename.append(".csv");
1585 cout << Verbose(0) << "Evaluating non-convex envelope.";
1586 cout << Verbose(1) << "Using rolling ball of radius " << atof(argv[argptr]) << " and storing tecplot data in " << argv[argptr+1] << "." << endl;
1587 LinkedCell LCList(mol, atof(argv[argptr])*2.);
1588 Find_non_convex_border((ofstream *)&cout, mol, &T, &LCList, argv[argptr+1], atof(argv[argptr]));
1589 //FindDistributionOfEllipsoids((ofstream *)&cout, &T, &LCList, N, number, filename.c_str());
1590 argptr+=2;
1591 }
1592 break;
1593 case 'S':
1594 ExitFlag = 1;
1595 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1596 ExitFlag = 255;
1597 cerr << "Not enough or invalid arguments given for storing tempature: -S <temperature file>" << endl;
1598 } else {
1599 cout << Verbose(1) << "Storing temperatures in " << argv[argptr] << "." << endl;
1600 ofstream *output = new ofstream(argv[argptr], ios::trunc);
1601 if (!mol->OutputTemperatureFromTrajectories((ofstream *)&cout, 0, mol->MDSteps, output))
1602 cout << Verbose(2) << "File could not be written." << endl;
1603 else
1604 cout << Verbose(2) << "File stored." << endl;
1605 output->close();
1606 delete(output);
1607 argptr+=1;
1608 }
1609 break;
1610 case 'L':
1611 ExitFlag = 1;
1612 SaveFlag = true;
1613 cout << Verbose(1) << "Linear interpolation between configuration " << argv[argptr] << " and " << argv[argptr+1] << "." << endl;
1614 if (!mol->LinearInterpolationBetweenConfiguration((ofstream *)&cout, atoi(argv[argptr]), atoi(argv[argptr+1]), argv[argptr+2], configuration))
1615 cout << Verbose(2) << "Could not store " << argv[argptr+2] << " files." << endl;
1616 else
1617 cout << Verbose(2) << "Steps created and " << argv[argptr+2] << " files stored." << endl;
1618 argptr+=3;
1619 break;
1620 case 'P':
1621 ExitFlag = 1;
1622 if ((argptr >= argc) || (argv[argptr][0] == '-')) {
1623 ExitFlag = 255;
1624 cerr << "Not enough or invalid arguments given for parsing and integrating forces: -P <forces file>" << endl;
1625 } else {
1626 SaveFlag = true;
1627 cout << Verbose(1) << "Parsing forces file and Verlet integrating." << endl;
1628 if (!mol->VerletForceIntegration((ofstream *)&cout, argv[argptr], configuration))
1629 cout << Verbose(2) << "File not found." << endl;
1630 else
1631 cout << Verbose(2) << "File found and parsed." << endl;
1632 argptr+=1;
1633 }
1634 break;
1635 case 'R':
1636 ExitFlag = 1;
1637 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1]))) {
1638 ExitFlag = 255;
1639 cerr << "Not enough or invalid arguments given for removing atoms: -R <id> <distance>" << endl;
1640 } else {
1641 SaveFlag = true;
1642 cout << Verbose(1) << "Removing atoms around " << argv[argptr] << " with radius " << argv[argptr+1] << "." << endl;
1643 double tmp1 = atof(argv[argptr+1]);
1644 atom *third = mol->FindAtom(atoi(argv[argptr]));
1645 atom *first = mol->start;
1646 if ((third != NULL) && (first != mol->end)) {
1647 atom *second = first->next;
1648 while(second != mol->end) {
1649 first = second;
1650 second = first->next;
1651 if (first->x.DistanceSquared((const Vector *)&third->x) > tmp1*tmp1) // distance to first above radius ...
1652 mol->RemoveAtom(first);
1653 }
1654 } else {
1655 cerr << "Removal failed due to missing atoms on molecule or wrong id." << endl;
1656 }
1657 argptr+=2;
1658 }
1659 break;
1660 case 't':
1661 ExitFlag = 1;
1662 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) {
1663 ExitFlag = 255;
1664 cerr << "Not enough or invalid arguments given for translation: -t <x> <y> <z>" << endl;
1665 } else {
1666 ExitFlag = 1;
1667 SaveFlag = true;
1668 cout << Verbose(1) << "Translating all ions to new origin." << endl;
1669 for (int i=NDIM;i--;)
1670 x.x[i] = atof(argv[argptr+i]);
1671 mol->Translate((const Vector *)&x);
1672 argptr+=3;
1673 }
1674 case 'T':
1675 ExitFlag = 1;
1676 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) {
1677 ExitFlag = 255;
1678 cerr << "Not enough or invalid arguments given for periodic translation: -T <x> <y> <z>" << endl;
1679 } else {
1680 ExitFlag = 1;
1681 SaveFlag = true;
1682 cout << Verbose(1) << "Translating all ions periodically to new origin." << endl;
1683 for (int i=NDIM;i--;)
1684 x.x[i] = atof(argv[argptr+i]);
1685 mol->TranslatePeriodically((const Vector *)&x);
1686 argptr+=3;
1687 }
1688 break;
1689 case 's':
1690 ExitFlag = 1;
1691 if ((argptr >= argc) || (!IsValidNumber(argv[argptr])) ) {
1692 ExitFlag = 255;
1693 cerr << "Not enough or invalid arguments given for scaling: -s <factor/[factor_x]> [factor_y] [factor_z]" << endl;
1694 } else {
1695 SaveFlag = true;
1696 j = -1;
1697 cout << Verbose(1) << "Scaling all ion positions by factor." << endl;
1698 factor = new double[NDIM];
1699 factor[0] = atof(argv[argptr]);
1700 if ((argptr < argc) && (IsValidNumber(argv[argptr])))
1701 argptr++;
1702 factor[1] = atof(argv[argptr]);
1703 if ((argptr < argc) && (IsValidNumber(argv[argptr])))
1704 argptr++;
1705 factor[2] = atof(argv[argptr]);
1706 mol->Scale(&factor);
1707 for (int i=0;i<NDIM;i++) {
1708 j += i+1;
1709 x.x[i] = atof(argv[NDIM+i]);
1710 mol->cell_size[j]*=factor[i];
1711 }
1712 delete[](factor);
1713 argptr+=1;
1714 }
1715 break;
1716 case 'b':
1717 ExitFlag = 1;
1718 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])) ) {
1719 ExitFlag = 255;
1720 cerr << "Not enough or invalid arguments given for centering in box: -b <xx> <xy> <xz> <yy> <yz> <zz>" << endl;
1721 } else {
1722 SaveFlag = true;
1723 j = -1;
1724 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl;
1725 for (int i=0;i<6;i++) {
1726 mol->cell_size[i] = atof(argv[argptr+i]);
1727 }
1728 // center
1729 mol->CenterInBox((ofstream *)&cout);
1730 argptr+=6;
1731 }
1732 break;
1733 case 'c':
1734 ExitFlag = 1;
1735 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) {
1736 ExitFlag = 255;
1737 cerr << "Not enough or invalid arguments given for centering with boundary: -c <boundary_x> <boundary_y> <boundary_z>" << endl;
1738 } else {
1739 SaveFlag = true;
1740 j = -1;
1741 cout << Verbose(1) << "Centering atoms in config file within given additional boundary." << endl;
1742 // make every coordinate positive
1743 mol->CenterEdge((ofstream *)&cout, &x);
1744 // update Box of atoms by boundary
1745 mol->SetBoxDimension(&x);
1746 // translate each coordinate by boundary
1747 j=-1;
1748 for (int i=0;i<NDIM;i++) {
1749 j += i+1;
1750 x.x[i] = atof(argv[argptr+i]);
1751 mol->cell_size[j] += x.x[i]*2.;
1752 }
1753 mol->Translate((const Vector *)&x);
1754 argptr+=3;
1755 }
1756 break;
1757 case 'O':
1758 ExitFlag = 1;
1759 SaveFlag = true;
1760 cout << Verbose(1) << "Centering atoms on edge and setting box dimensions." << endl;
1761 x.Zero();
1762 mol->CenterEdge((ofstream *)&cout, &x);
1763 mol->SetBoxDimension(&x);
1764 argptr+=0;
1765 break;
1766 case 'r':
1767 ExitFlag = 1;
1768 SaveFlag = true;
1769 cout << Verbose(1) << "Converting config file from supposed old to new syntax." << endl;
1770 break;
1771 case 'F':
1772 case 'f':
1773 ExitFlag = 1;
1774 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1]))) {
1775 ExitFlag = 255;
1776 cerr << "Not enough or invalid arguments for fragmentation: -f <max. bond distance> <bond order>" << endl;
1777 } else {
1778 cout << "Fragmenting molecule with bond distance " << argv[argptr] << " angstroem, order of " << argv[argptr+1] << "." << endl;
1779 cout << Verbose(0) << "Creating connection matrix..." << endl;
1780 start = clock();
1781 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr++]), configuration.GetIsAngstroem());
1782 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl;
1783 if (mol->first->next != mol->last) {
1784 ExitFlag = mol->FragmentMolecule((ofstream *)&cout, atoi(argv[argptr]), &configuration);
1785 }
1786 end = clock();
1787 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
1788 argptr+=2;
1789 }
1790 break;
1791 case 'm':
1792 ExitFlag = 1;
1793 j = atoi(argv[argptr++]);
1794 if ((j<0) || (j>1)) {
1795 cerr << Verbose(1) << "ERROR: Argument of '-m' should be either 0 for no-rotate or 1 for rotate." << endl;
1796 j = 0;
1797 }
1798 if (j) {
1799 SaveFlag = true;
1800 cout << Verbose(0) << "Converting to prinicipal axis system." << endl;
1801 } else
1802 cout << Verbose(0) << "Evaluating prinicipal axis." << endl;
1803 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)j);
1804 break;
1805 case 'o':
1806 ExitFlag = 1;
1807 if ((argptr >= argc) || (argv[argptr][0] == '-')){
1808 ExitFlag = 255;
1809 cerr << "Not enough or invalid arguments given for convex envelope: -o <tecplot output file>" << endl;
1810 } else {
1811 cout << Verbose(0) << "Evaluating volume of the convex envelope.";
1812 cout << Verbose(1) << "Storing tecplot data in " << argv[argptr] << "." << endl;
1813 LinkedCell LCList(mol, 10.);
1814 class Tesselation *TesselStruct = NULL;
1815 Find_convex_border((ofstream *)&cout, mol, TesselStruct, &LCList, argv[argptr]);
1816 double clustervolume = VolumeOfConvexEnvelope((ofstream *)&cout, TesselStruct, &configuration);
1817 cout << Verbose(0) << "The tesselated surface area is " << clustervolume << "." << endl;
1818 delete(TesselStruct);
1819 argptr+=1;
1820 }
1821 break;
1822 case 'U':
1823 ExitFlag = 1;
1824 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) ) {
1825 ExitFlag = 255;
1826 cerr << "Not enough or invalid arguments given for suspension with specified volume: -U <volume> <density>" << endl;
1827 volume = -1; // for case 'u': don't print error again
1828 } else {
1829 volume = atof(argv[argptr++]);
1830 cout << Verbose(0) << "Using " << volume << " angstrom^3 as the volume instead of convex envelope one's." << endl;
1831 }
1832 case 'u':
1833 ExitFlag = 1;
1834 if ((argptr >= argc) || (!IsValidNumber(argv[argptr])) ) {
1835 if (volume != -1)
1836 ExitFlag = 255;
1837 cerr << "Not enough arguments given for suspension: -u <density>" << endl;
1838 } else {
1839 double density;
1840 SaveFlag = true;
1841 cout << Verbose(0) << "Evaluating necessary cell volume for a cluster suspended in water.";
1842 density = atof(argv[argptr++]);
1843 if (density < 1.0) {
1844 cerr << Verbose(0) << "Density must be greater than 1.0g/cm^3 !" << endl;
1845 density = 1.3;
1846 }
1847// for(int i=0;i<NDIM;i++) {
1848// repetition[i] = atoi(argv[argptr++]);
1849// if (repetition[i] < 1)
1850// cerr << Verbose(0) << "ERROR: repetition value must be greater 1!" << endl;
1851// repetition[i] = 1;
1852// }
1853 PrepareClustersinWater((ofstream *)&cout, &configuration, mol, volume, density); // if volume == 0, will calculate from ConvexEnvelope
1854 }
1855 break;
1856 case 'd':
1857 ExitFlag = 1;
1858 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) {
1859 ExitFlag = 255;
1860 cerr << "Not enough or invalid arguments given for repeating cells: -d <repeat_x> <repeat_y> <repeat_z>" << endl;
1861 } else {
1862 SaveFlag = true;
1863 for (int axis = 1; axis <= NDIM; axis++) {
1864 int faktor = atoi(argv[argptr++]);
1865 int count;
1866 element ** Elements;
1867 Vector ** vectors;
1868 if (faktor < 1) {
1869 cerr << Verbose(0) << "ERROR: Repetition faktor mus be greater than 1!" << endl;
1870 faktor = 1;
1871 }
1872 mol->CountAtoms((ofstream *)&cout); // recount atoms
1873 if (mol->AtomCount != 0) { // if there is more than none
1874 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand
1875 Elements = new element *[count];
1876 vectors = new Vector *[count];
1877 j = 0;
1878 first = mol->start;
1879 while (first->next != mol->end) { // make a list of all atoms with coordinates and element
1880 first = first->next;
1881 Elements[j] = first->type;
1882 vectors[j] = &first->x;
1883 j++;
1884 }
1885 if (count != j)
1886 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl;
1887 x.Zero();
1888 y.Zero();
1889 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
1890 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times
1891 x.AddVector(&y); // per factor one cell width further
1892 for (int k=count;k--;) { // go through every atom of the original cell
1893 first = new atom(); // create a new body
1894 first->x.CopyVector(vectors[k]); // use coordinate of original atom
1895 first->x.AddVector(&x); // translate the coordinates
1896 first->type = Elements[k]; // insert original element
1897 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)
1898 }
1899 }
1900 // free memory
1901 delete[](Elements);
1902 delete[](vectors);
1903 // correct cell size
1904 if (axis < 0) { // if sign was negative, we have to translate everything
1905 x.Zero();
1906 x.AddVector(&y);
1907 x.Scale(-(faktor-1));
1908 mol->Translate(&x);
1909 }
1910 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor;
1911 }
1912 }
1913 }
1914 break;
1915 default: // no match? Step on
1916 if ((argptr < argc) && (argv[argptr][0] != '-')) // if it started with a '-' we've already made a step!
1917 argptr++;
1918 break;
1919 }
1920 }
1921 } else argptr++;
1922 } while (argptr < argc);
1923 if (SaveFlag)
1924 SaveConfig(ConfigFileName, &configuration, periode, molecules);
1925 } else { // no arguments, hence scan the elements db
1926 if (periode->LoadPeriodentafel(configuration.databasepath))
1927 cout << Verbose(0) << "Element list loaded successfully." << endl;
1928 else
1929 cout << Verbose(0) << "Element list loading failed." << endl;
1930 configuration.RetrieveConfigPathAndName("main_pcp_linux");
1931 }
1932 return(ExitFlag);
1933};
1934
1935/********************************************** Main routine **************************************/
1936
1937int main(int argc, char **argv)
1938{
1939 periodentafel *periode = new periodentafel; // and a period table of all elements
1940 MoleculeListClass *molecules = new MoleculeListClass; // list of all molecules
1941 molecule *mol = NULL;
1942 config configuration;
1943 char choice; // menu choice char
1944 Vector x,y,z,n; // coordinates for absolute point in cell volume
1945 ifstream test;
1946 ofstream output;
1947 string line;
1948 char *ConfigFileName = NULL;
1949 int j;
1950
1951 // =========================== PARSE COMMAND LINE OPTIONS ====================================
1952 j = ParseCommandLineOptions(argc, argv, molecules, periode, configuration, ConfigFileName);
1953 switch(j) {
1954 case 255: // something went wrong
1955 delete(molecules); // also free's all molecules contained
1956 delete(periode);
1957 return j;
1958 break;
1959 case 1: // just for -v and -h options
1960 delete(molecules); // also free's all molecules contained
1961 delete(periode);
1962 return 0;
1963 break;
1964 default:
1965 break;
1966 }
1967
1968 // General stuff
1969 if (molecules->ListOfMolecules.size() == 0) {
1970 mol = new molecule(periode);
1971 if (mol->cell_size[0] == 0.) {
1972 cout << Verbose(0) << "enter lower tridiagonal form of basis matrix" << endl << endl;
1973 for (int i=0;i<6;i++) {
1974 cout << Verbose(1) << "Cell size" << i << ": ";
1975 cin >> mol->cell_size[i];
1976 }
1977 }
1978 molecules->insert(mol);
1979 }
1980
1981 // =========================== START INTERACTIVE SESSION ====================================
1982
1983 // now the main construction loop
1984 cout << Verbose(0) << endl << "Now comes the real construction..." << endl;
1985 do {
1986 cout << Verbose(0) << endl << endl;
1987 cout << Verbose(0) << "============Molecule list=======================" << endl;
1988 molecules->Enumerate((ofstream *)&cout);
1989 cout << Verbose(0) << "============Menu===============================" << endl;
1990 cout << Verbose(0) << "a - set molecule (in)active" << endl;
1991 cout << Verbose(0) << "e - edit molecules (load, parse, save)" << endl;
1992 cout << Verbose(0) << "g - globally manipulate atoms in molecule" << endl;
1993 cout << Verbose(0) << "M - Merge molecules" << endl;
1994 cout << Verbose(0) << "m - manipulate atoms" << endl;
1995 cout << Verbose(0) << "-----------------------------------------------" << endl;
1996 cout << Verbose(0) << "c - edit the current configuration" << endl;
1997 cout << Verbose(0) << "-----------------------------------------------" << endl;
1998 cout << Verbose(0) << "s - save current setup to config file" << endl;
1999 cout << Verbose(0) << "T - call the current test routine" << endl;
2000 cout << Verbose(0) << "q - quit" << endl;
2001 cout << Verbose(0) << "===============================================" << endl;
2002 cout << Verbose(0) << "Input: ";
2003 cin >> choice;
2004
2005 switch (choice) {
2006 case 'a': // (in)activate molecule
2007 {
2008 cout << "Enter index of molecule: ";
2009 cin >> j;
2010 for(MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++)
2011 if ((*ListRunner)->IndexNr == j)
2012 (*ListRunner)->ActiveFlag = !(*ListRunner)->ActiveFlag;
2013 }
2014 break;
2015
2016 case 'c': // edit each field of the configuration
2017 configuration.Edit();
2018 break;
2019
2020 case 'e': // create molecule
2021 EditMolecules(periode, molecules);
2022 break;
2023
2024 case 'g': // manipulate molecules
2025 ManipulateMolecules(periode, molecules, &configuration);
2026 break;
2027
2028 case 'M': // merge molecules
2029 MergeMolecules(periode, molecules);
2030 break;
2031
2032 case 'm': // manipulate atoms
2033 ManipulateAtoms(periode, molecules, &configuration);
2034 break;
2035
2036 case 'q': // quit
2037 break;
2038
2039 case 's': // save to config file
2040 SaveConfig(ConfigFileName, &configuration, periode, molecules);
2041 break;
2042
2043 case 'T':
2044 testroutine(molecules);
2045 break;
2046
2047 default:
2048 break;
2049 };
2050 } while (choice != 'q');
2051
2052 // save element data base
2053 if (periode->StorePeriodentafel(configuration.databasepath)) //ElementsFileName
2054 cout << Verbose(0) << "Saving of elements.db successful." << endl;
2055 else
2056 cout << Verbose(0) << "Saving of elements.db failed." << endl;
2057
2058 delete(molecules); // also free's all molecules contained
2059 delete(periode);
2060 return (0);
2061}
2062
2063/********************************************** E N D **************************************************/
Note: See TracBrowser for help on using the repository browser.