source: molecuilder/src/builder.cpp@ 55e916

Last change on this file since 55e916 was 55e916, checked in by Frederik Heber <heber@…>, 17 years ago

FIX: ExitFlag not defaults to 0, and set specifically to 1 in the subcases

In ParseCommandLineOptions() the ExitFlag was always set to 1, even if only the elements databases were given on the command line. This lead to exit of program, when none was desired.

  • Property mode set to 100644
File size: 57.2 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 "helpers.hpp"
53#include "molecules.hpp"
54#include "boundary.hpp"
55
56/********************************************** Submenu routine **************************************/
57
58/** Submenu for adding atoms to the molecule.
59 * \param *periode periodentafel
60 * \param *mol the molecule to add to
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 case 'a': // absolute coordinates of atom
85 cout << Verbose(0) << "Enter absolute coordinates." << endl;
86 first = new atom;
87 first->x.AskPosition(mol->cell_size, false);
88 first->type = periode->AskElement(); // give type
89 mol->AddAtom(first); // add to molecule
90 break;
91
92 case 'b': // relative coordinates of atom wrt to reference point
93 first = new atom;
94 valid = true;
95 do {
96 if (!valid) cout << Verbose(0) << "Resulting position out of cell." << endl;
97 cout << Verbose(0) << "Enter reference coordinates." << endl;
98 x.AskPosition(mol->cell_size, true);
99 cout << Verbose(0) << "Enter relative coordinates." << endl;
100 first->x.AskPosition(mol->cell_size, false);
101 first->x.AddVector((const Vector *)&x);
102 cout << Verbose(0) << "\n";
103 } while (!(valid = mol->CheckBounds((const Vector *)&first->x)));
104 first->type = periode->AskElement(); // give type
105 mol->AddAtom(first); // add to molecule
106 break;
107
108 case 'c': // relative coordinates of atom wrt to already placed atom
109 first = new atom;
110 valid = true;
111 do {
112 if (!valid) cout << Verbose(0) << "Resulting position out of cell." << endl;
113 second = mol->AskAtom("Enter atom number: ");
114 cout << Verbose(0) << "Enter relative coordinates." << endl;
115 first->x.AskPosition(mol->cell_size, false);
116 for (int i=NDIM;i--;) {
117 first->x.x[i] += second->x.x[i];
118 }
119 } while (!(valid = mol->CheckBounds((const Vector *)&first->x)));
120 first->type = periode->AskElement(); // give type
121 mol->AddAtom(first); // add to molecule
122 break;
123
124 case 'd': // two atoms, two angles and a distance
125 first = new atom;
126 valid = true;
127 do {
128 if (!valid) {
129 cout << Verbose(0) << "Resulting coordinates out of cell - ";
130 first->x.Output((ofstream *)&cout);
131 cout << Verbose(0) << endl;
132 }
133 cout << Verbose(0) << "First, we need two atoms, the first atom is the central, while the second is the outer one." << endl;
134 second = mol->AskAtom("Enter central atom: ");
135 third = mol->AskAtom("Enter second atom (specifying the axis for first angle): ");
136 fourth = mol->AskAtom("Enter third atom (specifying a plane for second angle): ");
137 a = ask_value("Enter distance between central (first) and new atom: ");
138 b = ask_value("Enter angle between new, first and second atom (degrees): ");
139 b *= M_PI/180.;
140 bound(&b, 0., 2.*M_PI);
141 c = ask_value("Enter second angle between new and normal vector of plane defined by first, second and third atom (degrees): ");
142 c *= M_PI/180.;
143 bound(&c, -M_PI, M_PI);
144 cout << Verbose(0) << "radius: " << a << "\t phi: " << b*180./M_PI << "\t theta: " << c*180./M_PI << endl;
145/*
146 second->Output(1,1,(ofstream *)&cout);
147 third->Output(1,2,(ofstream *)&cout);
148 fourth->Output(1,3,(ofstream *)&cout);
149 n.MakeNormalvector((const vector *)&second->x, (const vector *)&third->x, (const vector *)&fourth->x);
150 x.Copyvector(&second->x);
151 x.SubtractVector(&third->x);
152 x.Copyvector(&fourth->x);
153 x.SubtractVector(&third->x);
154
155 if (!z.SolveSystem(&x,&y,&n, b, c, a)) {
156 cout << Verbose(0) << "Failure solving self-dependent linear system!" << endl;
157 continue;
158 }
159 cout << Verbose(0) << "resulting relative coordinates: ";
160 z.Output((ofstream *)&cout);
161 cout << Verbose(0) << endl;
162 */
163 // calc axis vector
164 x.CopyVector(&second->x);
165 x.SubtractVector(&third->x);
166 x.Normalize();
167 cout << "x: ",
168 x.Output((ofstream *)&cout);
169 cout << endl;
170 z.MakeNormalVector(&second->x,&third->x,&fourth->x);
171 cout << "z: ",
172 z.Output((ofstream *)&cout);
173 cout << endl;
174 y.MakeNormalVector(&x,&z);
175 cout << "y: ",
176 y.Output((ofstream *)&cout);
177 cout << endl;
178
179 // rotate vector around first angle
180 first->x.CopyVector(&x);
181 first->x.RotateVector(&z,b - M_PI);
182 cout << "Rotated vector: ",
183 first->x.Output((ofstream *)&cout);
184 cout << endl;
185 // remove the projection onto the rotation plane of the second angle
186 n.CopyVector(&y);
187 n.Scale(first->x.Projection(&y));
188 cout << "N1: ",
189 n.Output((ofstream *)&cout);
190 cout << endl;
191 first->x.SubtractVector(&n);
192 cout << "Subtracted vector: ",
193 first->x.Output((ofstream *)&cout);
194 cout << endl;
195 n.CopyVector(&z);
196 n.Scale(first->x.Projection(&z));
197 cout << "N2: ",
198 n.Output((ofstream *)&cout);
199 cout << endl;
200 first->x.SubtractVector(&n);
201 cout << "2nd subtracted vector: ",
202 first->x.Output((ofstream *)&cout);
203 cout << endl;
204
205 // rotate another vector around second angle
206 n.CopyVector(&y);
207 n.RotateVector(&x,c - M_PI);
208 cout << "2nd Rotated vector: ",
209 n.Output((ofstream *)&cout);
210 cout << endl;
211
212 // add the two linear independent vectors
213 first->x.AddVector(&n);
214 first->x.Normalize();
215 first->x.Scale(a);
216 first->x.AddVector(&second->x);
217
218 cout << Verbose(0) << "resulting coordinates: ";
219 first->x.Output((ofstream *)&cout);
220 cout << Verbose(0) << endl;
221 } while (!(valid = mol->CheckBounds((const Vector *)&first->x)));
222 first->type = periode->AskElement(); // give type
223 mol->AddAtom(first); // add to molecule
224 break;
225
226 case 'e': // least square distance position to a set of atoms
227 first = new atom;
228 atoms = new (Vector*[128]);
229 valid = true;
230 for(int i=128;i--;)
231 atoms[i] = NULL;
232 int i=0, j=0;
233 cout << Verbose(0) << "Now we need at least three molecules.\n";
234 do {
235 cout << Verbose(0) << "Enter " << i+1 << "th atom: ";
236 cin >> j;
237 if (j != -1) {
238 second = mol->FindAtom(j);
239 atoms[i++] = &(second->x);
240 }
241 } while ((j != -1) && (i<128));
242 if (i >= 2) {
243 first->x.LSQdistance(atoms, i);
244
245 first->x.Output((ofstream *)&cout);
246 first->type = periode->AskElement(); // give type
247 mol->AddAtom(first); // add to molecule
248 } else {
249 delete first;
250 cout << Verbose(0) << "Please enter at least two vectors!\n";
251 }
252 break;
253 };
254};
255
256/** Submenu for centering the atoms in the molecule.
257 * \param *mol the molecule with all the atoms
258 */
259static void CenterAtoms(molecule *mol)
260{
261 Vector x, y;
262 char choice; // menu choice char
263
264 cout << Verbose(0) << "===========CENTER ATOMS=========================" << endl;
265 cout << Verbose(0) << " a - on origin" << endl;
266 cout << Verbose(0) << " b - on center of gravity" << endl;
267 cout << Verbose(0) << " c - within box with additional boundary" << endl;
268 cout << Verbose(0) << " d - within given simulation box" << endl;
269 cout << Verbose(0) << "all else - go back" << endl;
270 cout << Verbose(0) << "===============================================" << endl;
271 cout << Verbose(0) << "INPUT: ";
272 cin >> choice;
273
274 switch (choice) {
275 default:
276 cout << Verbose(0) << "Not a valid choice." << endl;
277 break;
278 case 'a':
279 cout << Verbose(0) << "Centering atoms in config file on origin." << endl;
280 mol->CenterOrigin((ofstream *)&cout, &x);
281 break;
282 case 'b':
283 cout << Verbose(0) << "Centering atoms in config file on center of gravity." << endl;
284 mol->CenterGravity((ofstream *)&cout, &x);
285 break;
286 case 'c':
287 cout << Verbose(0) << "Centering atoms in config file within given additional boundary." << endl;
288 for (int i=0;i<NDIM;i++) {
289 cout << Verbose(0) << "Enter axis " << i << " boundary: ";
290 cin >> y.x[i];
291 }
292 mol->CenterEdge((ofstream *)&cout, &x); // make every coordinate positive
293 mol->Translate(&y); // translate by boundary
294 mol->SetBoxDimension(&(x+y*2)); // update Box of atoms by boundary
295 break;
296 case 'd':
297 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl;
298 for (int i=0;i<NDIM;i++) {
299 cout << Verbose(0) << "Enter axis " << i << " boundary: ";
300 cin >> x.x[i];
301 }
302 // center
303 mol->CenterInBox((ofstream *)&cout, &x);
304 // update Box of atoms by boundary
305 mol->SetBoxDimension(&x);
306 break;
307 }
308};
309
310/** Submenu for aligning the atoms in the molecule.
311 * \param *periode periodentafel
312 * \param *mol the molecule with all the atoms
313 */
314static void AlignAtoms(periodentafel *periode, molecule *mol)
315{
316 atom *first, *second, *third;
317 Vector x,n;
318 char choice; // menu choice char
319
320 cout << Verbose(0) << "===========ALIGN ATOMS=========================" << endl;
321 cout << Verbose(0) << " a - state three atoms defining align plane" << endl;
322 cout << Verbose(0) << " b - state alignment vector" << endl;
323 cout << Verbose(0) << " c - state two atoms in alignment direction" << endl;
324 cout << Verbose(0) << " d - align automatically by least square fit" << endl;
325 cout << Verbose(0) << "all else - go back" << endl;
326 cout << Verbose(0) << "===============================================" << endl;
327 cout << Verbose(0) << "INPUT: ";
328 cin >> choice;
329
330 switch (choice) {
331 default:
332 case 'a': // three atoms defining mirror plane
333 first = mol->AskAtom("Enter first atom: ");
334 second = mol->AskAtom("Enter second atom: ");
335 third = mol->AskAtom("Enter third atom: ");
336
337 n.MakeNormalVector((const Vector *)&first->x,(const Vector *)&second->x,(const Vector *)&third->x);
338 break;
339 case 'b': // normal vector of mirror plane
340 cout << Verbose(0) << "Enter normal vector of mirror plane." << endl;
341 n.AskPosition(mol->cell_size,0);
342 n.Normalize();
343 break;
344 case 'c': // three atoms defining mirror plane
345 first = mol->AskAtom("Enter first atom: ");
346 second = mol->AskAtom("Enter second atom: ");
347
348 n.CopyVector((const Vector *)&first->x);
349 n.SubtractVector((const Vector *)&second->x);
350 n.Normalize();
351 break;
352 case 'd':
353 char shorthand[4];
354 Vector a;
355 struct lsq_params param;
356 do {
357 fprintf(stdout, "Enter the element of atoms to be chosen: ");
358 fscanf(stdin, "%3s", shorthand);
359 } while ((param.type = periode->FindElement(shorthand)) == NULL);
360 cout << Verbose(0) << "Element is " << param.type->name << endl;
361 mol->GetAlignvector(&param);
362 for (int i=NDIM;i--;) {
363 x.x[i] = gsl_vector_get(param.x,i);
364 n.x[i] = gsl_vector_get(param.x,i+NDIM);
365 }
366 gsl_vector_free(param.x);
367 cout << Verbose(0) << "Offset vector: ";
368 x.Output((ofstream *)&cout);
369 cout << Verbose(0) << endl;
370 n.Normalize();
371 break;
372 };
373 cout << Verbose(0) << "Alignment vector: ";
374 n.Output((ofstream *)&cout);
375 cout << Verbose(0) << endl;
376 mol->Align(&n);
377};
378
379/** Submenu for mirroring the atoms in the molecule.
380 * \param *mol the molecule with all the atoms
381 */
382static void MirrorAtoms(molecule *mol)
383{
384 atom *first, *second, *third;
385 Vector n;
386 char choice; // menu choice char
387
388 cout << Verbose(0) << "===========MIRROR ATOMS=========================" << endl;
389 cout << Verbose(0) << " a - state three atoms defining mirror plane" << endl;
390 cout << Verbose(0) << " b - state normal vector of mirror plane" << endl;
391 cout << Verbose(0) << " c - state two atoms in normal direction" << endl;
392 cout << Verbose(0) << "all else - go back" << endl;
393 cout << Verbose(0) << "===============================================" << endl;
394 cout << Verbose(0) << "INPUT: ";
395 cin >> choice;
396
397 switch (choice) {
398 default:
399 case 'a': // three atoms defining mirror plane
400 first = mol->AskAtom("Enter first atom: ");
401 second = mol->AskAtom("Enter second atom: ");
402 third = mol->AskAtom("Enter third atom: ");
403
404 n.MakeNormalVector((const Vector *)&first->x,(const Vector *)&second->x,(const Vector *)&third->x);
405 break;
406 case 'b': // normal vector of mirror plane
407 cout << Verbose(0) << "Enter normal vector of mirror plane." << endl;
408 n.AskPosition(mol->cell_size,0);
409 n.Normalize();
410 break;
411 case 'c': // three atoms defining mirror plane
412 first = mol->AskAtom("Enter first atom: ");
413 second = mol->AskAtom("Enter second atom: ");
414
415 n.CopyVector((const Vector *)&first->x);
416 n.SubtractVector((const Vector *)&second->x);
417 n.Normalize();
418 break;
419 };
420 cout << Verbose(0) << "Normal vector: ";
421 n.Output((ofstream *)&cout);
422 cout << Verbose(0) << endl;
423 mol->Mirror((const Vector *)&n);
424};
425
426/** Submenu for removing the atoms from the molecule.
427 * \param *mol the molecule with all the atoms
428 */
429static void RemoveAtoms(molecule *mol)
430{
431 atom *first, *second;
432 int axis;
433 double tmp1, tmp2;
434 char choice; // menu choice char
435
436 cout << Verbose(0) << "===========REMOVE ATOMS=========================" << endl;
437 cout << Verbose(0) << " a - state atom for removal by number" << endl;
438 cout << Verbose(0) << " b - keep only in radius around atom" << endl;
439 cout << Verbose(0) << " c - remove this with one axis greater value" << endl;
440 cout << Verbose(0) << "all else - go back" << endl;
441 cout << Verbose(0) << "===============================================" << endl;
442 cout << Verbose(0) << "INPUT: ";
443 cin >> choice;
444
445 switch (choice) {
446 default:
447 case 'a':
448 if (mol->RemoveAtom(mol->AskAtom("Enter number of atom within molecule: ")))
449 cout << Verbose(1) << "Atom removed." << endl;
450 else
451 cout << Verbose(1) << "Atom not found." << endl;
452 break;
453 case 'b':
454 second = mol->AskAtom("Enter number of atom as reference point: ");
455 cout << Verbose(0) << "Enter radius: ";
456 cin >> tmp1;
457 first = mol->start;
458 while(first->next != mol->end) {
459 first = first->next;
460 if (first->x.Distance((const Vector *)&second->x) > tmp1*tmp1) // distance to first above radius ...
461 mol->RemoveAtom(first);
462 }
463 break;
464 case 'c':
465 cout << Verbose(0) << "Which axis is it: ";
466 cin >> axis;
467 cout << Verbose(0) << "Left inward boundary: ";
468 cin >> tmp1;
469 cout << Verbose(0) << "Right inward boundary: ";
470 cin >> tmp2;
471 first = mol->start;
472 while(first->next != mol->end) {
473 first = first->next;
474 if ((first->x.x[axis] > tmp2) || (first->x.x[axis] < tmp1)) // out of boundary ...
475 mol->RemoveAtom(first);
476 }
477 break;
478 };
479 //mol->Output((ofstream *)&cout);
480 choice = 'r';
481};
482
483/** Submenu for measuring out the atoms in the molecule.
484 * \param *periode periodentafel
485 * \param *mol the molecule with all the atoms
486 */
487static void MeasureAtoms(periodentafel *periode, molecule *mol, config *configuration)
488{
489 atom *first, *second, *third;
490 Vector x,y;
491 double min[256], tmp1, tmp2, tmp3;
492 int Z;
493 char choice; // menu choice char
494
495 cout << Verbose(0) << "===========MEASURE ATOMS=========================" << endl;
496 cout << Verbose(0) << " a - calculate bond length between one atom and all others" << endl;
497 cout << Verbose(0) << " b - calculate bond length between two atoms" << endl;
498 cout << Verbose(0) << " c - calculate bond angle" << endl;
499 cout << Verbose(0) << " d - calculate principal axis of the system" << endl;
500 cout << Verbose(0) << " e - calculate volume of the convex envelope" << endl;
501 cout << Verbose(0) << "all else - go back" << endl;
502 cout << Verbose(0) << "===============================================" << endl;
503 cout << Verbose(0) << "INPUT: ";
504 cin >> choice;
505
506 switch(choice) {
507 default:
508 cout << Verbose(1) << "Not a valid choice." << endl;
509 break;
510 case 'a':
511 first = mol->AskAtom("Enter first atom: ");
512 for (int i=MAX_ELEMENTS;i--;)
513 min[i] = 0.;
514
515 second = mol->start;
516 while ((second->next != mol->end)) {
517 second = second->next; // advance
518 Z = second->type->Z;
519 tmp1 = 0.;
520 if (first != second) {
521 x.CopyVector((const Vector *)&first->x);
522 x.SubtractVector((const Vector *)&second->x);
523 tmp1 = x.Norm();
524 }
525 if ((tmp1 != 0.) && ((min[Z] == 0.) || (tmp1 < min[Z]))) min[Z] = tmp1;
526 //cout << Verbose(0) << "Bond length between Atom " << first->nr << " and " << second->nr << ": " << tmp1 << " a.u." << endl;
527 }
528 for (int i=MAX_ELEMENTS;i--;)
529 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;
530 break;
531
532 case 'b':
533 first = mol->AskAtom("Enter first atom: ");
534 second = mol->AskAtom("Enter second atom: ");
535 for (int i=NDIM;i--;)
536 min[i] = 0.;
537 x.CopyVector((const Vector *)&first->x);
538 x.SubtractVector((const Vector *)&second->x);
539 tmp1 = x.Norm();
540 cout << Verbose(1) << "Distance vector is ";
541 x.Output((ofstream *)&cout);
542 cout << "." << endl << "Norm of distance is " << tmp1 << "." << endl;
543 break;
544
545 case 'c':
546 cout << Verbose(0) << "Evaluating bond angle between three - first, central, last - atoms." << endl;
547 first = mol->AskAtom("Enter first atom: ");
548 second = mol->AskAtom("Enter central atom: ");
549 third = mol->AskAtom("Enter last atom: ");
550 tmp1 = tmp2 = tmp3 = 0.;
551 x.CopyVector((const Vector *)&first->x);
552 x.SubtractVector((const Vector *)&second->x);
553 y.CopyVector((const Vector *)&third->x);
554 y.SubtractVector((const Vector *)&second->x);
555 cout << Verbose(0) << "Bond angle between first atom Nr." << first->nr << ", central atom Nr." << second->nr << " and last atom Nr." << third->nr << ": ";
556 cout << Verbose(0) << (acos(x.ScalarProduct((const Vector *)&y)/(y.Norm()*x.Norm()))/M_PI*180.) << " degrees" << endl;
557 break;
558 case 'd':
559 cout << Verbose(0) << "Evaluating prinicipal axis." << endl;
560 cout << Verbose(0) << "Shall we rotate? [0/1]: ";
561 cin >> Z;
562 if ((Z >=0) && (Z <=1))
563 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)Z);
564 else
565 mol->PrincipalAxisSystem((ofstream *)&cout, false);
566 break;
567 case 'e':
568 cout << Verbose(0) << "Evaluating volume of the convex envelope.";
569 VolumeOfConvexEnvelope((ofstream *)&cout, configuration, NULL, mol);
570 break;
571 }
572};
573
574/** Submenu for measuring out the atoms in the molecule.
575 * \param *mol the molecule with all the atoms
576 * \param *configuration configuration structure for the to be written config files of all fragments
577 */
578static void FragmentAtoms(molecule *mol, config *configuration)
579{
580 int Order1;
581 clock_t start, end;
582
583 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl;
584 cout << Verbose(0) << "What's the desired bond order: ";
585 cin >> Order1;
586 if (mol->first->next != mol->last) { // there are bonds
587 start = clock();
588 mol->FragmentMolecule((ofstream *)&cout, Order1, configuration);
589 end = clock();
590 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
591 } else
592 cout << Verbose(0) << "Connection matrix has not yet been generated!" << endl;
593};
594
595/********************************************** Test routine **************************************/
596
597/** Is called always as option 'T' in the menu.
598 */
599static void testroutine(molecule *mol)
600{
601 // the current test routine checks the functionality of the KeySet&Graph concept:
602 // We want to have a multiindex (the KeySet) describing a unique subgraph
603 atom *Walker = mol->start;
604 int i, comp, counter=0;
605
606 // generate some KeySets
607 cout << "Generating KeySets." << endl;
608 KeySet TestSets[mol->AtomCount+1];
609 i=1;
610 while (Walker->next != mol->end) {
611 Walker = Walker->next;
612 for (int j=0;j<i;j++) {
613 TestSets[j].insert(Walker->nr);
614 }
615 i++;
616 }
617 cout << "Testing insertion of already present item in KeySets." << endl;
618 KeySetTestPair test;
619 test = TestSets[mol->AtomCount-1].insert(Walker->nr);
620 if (test.second) {
621 cout << Verbose(1) << "Insertion worked?!" << endl;
622 } else {
623 cout << Verbose(1) << "Insertion rejected: Present object is " << (*test.first) << "." << endl;
624 }
625 TestSets[mol->AtomCount].insert(mol->end->previous->nr);
626 TestSets[mol->AtomCount].insert(mol->end->previous->previous->previous->nr);
627
628 // constructing Graph structure
629 cout << "Generating Subgraph class." << endl;
630 Graph Subgraphs;
631
632 // insert KeySets into Subgraphs
633 cout << "Inserting KeySets into Subgraph class." << endl;
634 for (int j=0;j<mol->AtomCount;j++) {
635 Subgraphs.insert(GraphPair (TestSets[j],pair<int, double>(counter++, 1.)));
636 }
637 cout << "Testing insertion of already present item in Subgraph." << endl;
638 GraphTestPair test2;
639 test2 = Subgraphs.insert(GraphPair (TestSets[mol->AtomCount],pair<int, double>(counter++, 1.)));
640 if (test2.second) {
641 cout << Verbose(1) << "Insertion worked?!" << endl;
642 } else {
643 cout << Verbose(1) << "Insertion rejected: Present object is " << (*(test2.first)).second.first << "." << endl;
644 }
645
646 // show graphs
647 cout << "Showing Subgraph's contents, checking that it's sorted." << endl;
648 Graph::iterator A = Subgraphs.begin();
649 while (A != Subgraphs.end()) {
650 cout << (*A).second.first << ": ";
651 KeySet::iterator key = (*A).first.begin();
652 comp = -1;
653 while (key != (*A).first.end()) {
654 if ((*key) > comp)
655 cout << (*key) << " ";
656 else
657 cout << (*key) << "! ";
658 comp = (*key);
659 key++;
660 }
661 cout << endl;
662 A++;
663 }
664};
665
666/** Tries given filename or standard on saving the config file.
667 * \param *ConfigFileName name of file
668 * \param *configuration pointer to configuration structure with all the values
669 * \param *periode pointer to periodentafel structure with all the elements
670 * \param *mol pointer to molecule structure with all the atoms and coordinates
671 */
672static void SaveConfig(char *ConfigFileName, config *configuration, periodentafel *periode, molecule *mol)
673{
674 char filename[MAXSTRINGSIZE];
675 ofstream output;
676
677 cout << Verbose(0) << "Storing configuration ... " << endl;
678 // get correct valence orbitals
679 mol->CalculateOrbitals(*configuration);
680 configuration->InitMaxMinStopStep = configuration->MaxMinStopStep = configuration->MaxPsiDouble;
681 if (ConfigFileName != NULL) {
682 output.open(ConfigFileName, ios::trunc);
683 } else if (strlen(configuration->configname) != 0) {
684 output.open(configuration->configname, ios::trunc);
685 } else {
686 output.open(DEFAULTCONFIG, ios::trunc);
687 }
688 if (configuration->Save(&output, periode, mol))
689 cout << Verbose(0) << "Saving of config file successful." << endl;
690 else
691 cout << Verbose(0) << "Saving of config file failed." << endl;
692 output.close();
693 output.clear();
694 // and save to xyz file
695 if (ConfigFileName != NULL) {
696 strcpy(filename, ConfigFileName);
697 strcat(filename, ".xyz");
698 output.open(filename, ios::trunc);
699 }
700 if (output == NULL) {
701 strcpy(filename,"main_pcp_linux");
702 strcat(filename, ".xyz");
703 output.open(filename, ios::trunc);
704 }
705 if (mol->MDSteps <= 1) {
706 if (mol->OutputXYZ(&output))
707 cout << Verbose(0) << "Saving of XYZ file successful." << endl;
708 else
709 cout << Verbose(0) << "Saving of XYZ file failed." << endl;
710 } else {
711 if (mol->OutputTrajectoriesXYZ(&output))
712 cout << Verbose(0) << "Saving of XYZ file successful." << endl;
713 else
714 cout << Verbose(0) << "Saving of XYZ file failed." << endl;
715 }
716 output.close();
717 output.clear();
718
719 if (!strcmp(configuration->configpath, configuration->GetDefaultPath())) {
720 cerr << "WARNING: config is found under different path then stated in config file::defaultpath!" << endl;
721 }
722};
723
724/** Parses the command line options.
725 * \param argc argument count
726 * \param **argv arguments array
727 * \param *mol molecule structure
728 * \param *periode elements structure
729 * \param configuration config file structure
730 * \param *ConfigFileName pointer to config file name in **argv
731 * \param *PathToDatabases pointer to db's path in **argv
732 * \return exit code (0 - successful, all else - something's wrong)
733 */
734static int ParseCommandLineOptions(int argc, char **argv, molecule *&mol, periodentafel *&periode, config& configuration, char *&ConfigFileName, char *&PathToDatabases)
735{
736 Vector x,y,z,n; // coordinates for absolute point in cell volume
737 double *factor; // unit factor if desired
738 ifstream test;
739 ofstream output;
740 string line;
741 atom *first;
742 bool SaveFlag = false;
743 int ExitFlag = 0;
744 int j;
745 double volume = 0.;
746 enum ConfigStatus config_present = absent;
747 clock_t start,end;
748 int argptr;
749 PathToDatabases = LocalPath;
750
751 if (argc > 1) { // config file specified as option
752 // 1. : Parse options that just set variables or print help
753 argptr = 1;
754 do {
755 if (argv[argptr][0] == '-') {
756 cout << Verbose(0) << "Recognized command line argument: " << argv[argptr][1] << ".\n";
757 argptr++;
758 switch(argv[argptr-1][1]) {
759 case 'h':
760 case 'H':
761 case '?':
762 cout << "MoleCuilder suite" << endl << "==================" << endl << endl;
763 cout << "Usage: " << argv[0] << "[config file] [-{acefpsthH?vfrp}] [further arguments]" << endl;
764 cout << "or simply " << argv[0] << " without arguments for interactive session." << endl;
765 cout << "\t-a Z x1 x2 x3\tAdd new atom of element Z at coordinates (x1,x2,x3)." << endl;
766 cout << "\t-b x1 x2 x3\tCenter atoms in domain with given edge lengths of (x1,x2,x3)." << endl;
767 cout << "\t-c x1 x2 x3\tCenter atoms in domain with a minimum distance to boundary of (x1,x2,x3)." << endl;
768 cout << "\t-D <bond distance>\tDepth-First-Search Analysis of the molecule, giving cycles and tree/back edges." << endl;
769 cout << "\t-O\tCenter atoms in origin." << endl;
770 cout << "\t-d x1 x2 x3\tDuplicate cell along each axis by given factor." << endl;
771 cout << "\t-e <file>\tSets the databases path to be parsed (default: ./)." << endl;
772 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;
773 cout << "\t-h/-H/-?\tGive this help screen." << endl;
774 cout << "\t-m <0/1>\tCalculate (0)/ Align in(1) PAS with greatest EV along z axis." << endl;
775 cout << "\t-n\tFast parsing (i.e. no trajectories are looked for)." << endl;
776 cout << "\t-o\tGet volume of the convex envelope (and store to tecplot file)." << endl;
777 cout << "\t-p <file>\tParse given xyz file and create raw config file from it." << endl;
778 cout << "\t-P <file>\tParse given forces file and append as an MD step to config file via Verlet." << endl;
779 cout << "\t-r\t\tConvert file from an old pcp syntax." << endl;
780 cout << "\t-t x1 x2 x3\tTranslate all atoms by this vector (x1,x2,x3)." << endl;
781 cout << "\t-s x1 x2 x3\tScale all atom coordinates by this vector (x1,x2,x3)." << endl;
782 cout << "\t-u rho\tsuspend in water solution and output necessary cell lengths, average density rho and repetition." << endl;
783 cout << "\t-v/-V\t\tGives version information." << endl;
784 cout << "Note: config files must not begin with '-' !" << endl;
785 delete(mol);
786 delete(periode);
787 return (1);
788 break;
789 case 'v':
790 case 'V':
791 cout << argv[0] << " " << VERSIONSTRING << endl;
792 cout << "Build your own molecule position set." << endl;
793 delete(mol);
794 delete(periode);
795 return (1);
796 break;
797 case 'e':
798 cout << "Using " << argv[argptr] << " as elements database." << endl;
799 PathToDatabases = argv[argptr];
800 argptr+=1;
801 break;
802 case 'n':
803 cout << "I won't parse trajectories." << endl;
804 configuration.FastParsing = true;
805 break;
806 default: // no match? Step on
807 argptr++;
808 break;
809 }
810 } else
811 argptr++;
812 } while (argptr < argc);
813
814 // 2. Parse the element database
815 if (periode->LoadPeriodentafel(PathToDatabases)) {
816 cout << Verbose(0) << "Element list loaded successfully." << endl;
817 //periode->Output((ofstream *)&cout);
818 } else {
819 cout << Verbose(0) << "Element list loading failed." << endl;
820 return 1;
821 }
822
823 // 3. Find config file name and parse if possible
824 if (argv[1][0] != '-') {
825 cout << Verbose(0) << "Config file given." << endl;
826 test.open(argv[1], ios::in);
827 if (test == NULL) {
828 //return (1);
829 output.open(argv[1], ios::out);
830 if (output == NULL) {
831 cout << Verbose(1) << "Specified config file " << argv[1] << " not found." << endl;
832 config_present = absent;
833 } else {
834 cout << "Empty configuration file." << endl;
835 ConfigFileName = argv[1];
836 config_present = empty;
837 output.close();
838 }
839 } else {
840 test.close();
841 ConfigFileName = argv[1];
842 cout << Verbose(1) << "Specified config file found, parsing ... ";
843 switch (configuration.TestSyntax(ConfigFileName, periode, mol)) {
844 case 1:
845 cout << "new syntax." << endl;
846 configuration.Load(ConfigFileName, periode, mol);
847 config_present = present;
848 break;
849 case 0:
850 cout << "old syntax." << endl;
851 configuration.LoadOld(ConfigFileName, periode, mol);
852 config_present = present;
853 break;
854 default:
855 cout << "Unknown syntax or empty, yet present file." << endl;
856 config_present = empty;
857 }
858 }
859 } else
860 config_present = absent;
861
862 // 4. parse again through options, now for those depending on elements db and config presence
863 argptr = 1;
864 do {
865 cout << "Current Command line argument: " << argv[argptr] << "." << endl;
866 if (argv[argptr][0] == '-') {
867 argptr++;
868 if ((config_present == present) || (config_present == empty)) {
869 switch(argv[argptr-1][1]) {
870 case 'p':
871 ExitFlag = 1;
872 SaveFlag = true;
873 cout << Verbose(1) << "Parsing xyz file for new atoms." << endl;
874 if (!mol->AddXYZFile(argv[argptr]))
875 cout << Verbose(2) << "File not found." << endl;
876 else {
877 cout << Verbose(2) << "File found and parsed." << endl;
878 config_present = present;
879 }
880 break;
881 default: // no match? Don't step on (this is done in next switch's default)
882 break;
883 }
884 }
885 if (config_present == present) {
886 switch(argv[argptr-1][1]) {
887 case 'D':
888 ExitFlag = 1;
889 {
890 cout << Verbose(1) << "Depth-First-Search Analysis." << endl;
891 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
892 int *MinimumRingSize = NULL;
893 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr++]), configuration.GetIsAngstroem());
894 mol->CreateListOfBondsPerAtom((ofstream *)&cout);
895 Subgraphs = mol->DepthFirstSearchAnalysis((ofstream *)&cout, MinimumRingSize);
896 delete[](MinimumRingSize);
897 if (Subgraphs != NULL) {
898 while (Subgraphs->next != NULL) {
899 Subgraphs = Subgraphs->next;
900 delete(Subgraphs->previous);
901 }
902 delete(Subgraphs);
903 }
904 }
905 argptr+=1;
906 break;
907 case 'P':
908 ExitFlag = 1;
909 SaveFlag = true;
910 cout << Verbose(1) << "Parsing forces file and Verlet integrating." << endl;
911 if (!mol->VerletForceIntegration(argv[argptr], configuration.Deltat, configuration.GetIsAngstroem()))
912 cout << Verbose(2) << "File not found." << endl;
913 else
914 cout << Verbose(2) << "File found and parsed." << endl;
915 argptr+=1;
916 break;
917 case 't':
918 ExitFlag = 1;
919 SaveFlag = true;
920 cout << Verbose(1) << "Translating all ions to new origin." << endl;
921 for (int i=NDIM;i--;)
922 x.x[i] = atof(argv[argptr+i]);
923 mol->Translate((const Vector *)&x);
924 argptr+=3;
925 break;
926 case 'a':
927 ExitFlag = 1;
928 SaveFlag = true;
929 cout << Verbose(1) << "Adding new atom with element " << argv[argptr] << " at (" << argv[argptr+1] << "," << argv[argptr+2] << "," << argv[argptr+3] << "), ";
930 first = new atom;
931 first->type = periode->FindElement(atoi(argv[argptr]));
932 if (first->type != NULL)
933 cout << Verbose(2) << "found element " << first->type->name << endl;
934 for (int i=NDIM;i--;)
935 first->x.x[i] = atof(argv[argptr+1+i]);
936 if (first->type != NULL)
937 mol->AddAtom(first); // add to molecule
938 else
939 cerr << Verbose(1) << "Could not find the specified element." << endl;
940 argptr+=4;
941 break;
942 case 's':
943 ExitFlag = 1;
944 SaveFlag = true;
945 j = -1;
946 cout << Verbose(1) << "Scaling all ion positions by factor." << endl;
947 factor = new double[NDIM];
948 factor[0] = atof(argv[argptr]);
949 if (argc > argptr+1)
950 argptr++;
951 factor[1] = atof(argv[argptr]);
952 if (argc > argptr+1)
953 argptr++;
954 factor[2] = atof(argv[argptr]);
955 mol->Scale(&factor);
956 for (int i=0;i<NDIM;i++) {
957 j += i+1;
958 x.x[i] = atof(argv[NDIM+i]);
959 mol->cell_size[j]*=factor[i];
960 }
961 delete[](factor);
962 argptr+=1;
963 break;
964 case 'b':
965 ExitFlag = 1;
966 SaveFlag = true;
967 j = -1;
968 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl;
969 j=-1;
970 for (int i=0;i<NDIM;i++) {
971 j += i+1;
972 x.x[i] = atof(argv[argptr++]);
973 mol->cell_size[j] += x.x[i]*2.;
974 }
975 // center
976 mol->CenterInBox((ofstream *)&cout, &x);
977 // update Box of atoms by boundary
978 mol->SetBoxDimension(&x);
979 break;
980 case 'c':
981 ExitFlag = 1;
982 SaveFlag = true;
983 j = -1;
984 cout << Verbose(1) << "Centering atoms in config file within given additional boundary." << endl;
985 // make every coordinate positive
986 mol->CenterEdge((ofstream *)&cout, &x);
987 // update Box of atoms by boundary
988 mol->SetBoxDimension(&x);
989 // translate each coordinate by boundary
990 j=-1;
991 for (int i=0;i<NDIM;i++) {
992 j += i+1;
993 x.x[i] = atof(argv[argptr++]);
994 mol->cell_size[j] += x.x[i]*2.;
995 }
996 mol->Translate((const Vector *)&x);
997 break;
998 case 'O':
999 ExitFlag = 1;
1000 SaveFlag = true;
1001 cout << Verbose(1) << "Centering atoms in origin." << endl;
1002 mol->CenterOrigin((ofstream *)&cout, &x);
1003 mol->SetBoxDimension(&x);
1004 break;
1005 case 'r':
1006 ExitFlag = 1;
1007 SaveFlag = true;
1008 cout << Verbose(1) << "Converting config file from supposed old to new syntax." << endl;
1009 break;
1010 case 'F':
1011 case 'f':
1012 ExitFlag = 1;
1013 cout << "Fragmenting molecule with bond distance " << argv[argptr] << " angstroem, order of " << argv[argptr+1] << "." << endl;
1014 if (argc >= argptr+2) {
1015 cout << Verbose(0) << "Creating connection matrix..." << endl;
1016 start = clock();
1017 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr++]), configuration.GetIsAngstroem());
1018 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl;
1019 if (mol->first->next != mol->last) {
1020 ExitFlag = mol->FragmentMolecule((ofstream *)&cout, atoi(argv[argptr]), &configuration);
1021 }
1022 end = clock();
1023 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
1024 argptr+=1;
1025 } else {
1026 cerr << "Not enough arguments for fragmentation: -f <max. bond distance> <bond order>" << endl;
1027 }
1028 break;
1029 case 'm':
1030 ExitFlag = 1;
1031 j = atoi(argv[argptr++]);
1032 if ((j<0) || (j>1)) {
1033 cerr << Verbose(1) << "ERROR: Argument of '-m' should be either 0 for no-rotate or 1 for rotate." << endl;
1034 j = 0;
1035 }
1036 if (j) {
1037 SaveFlag = true;
1038 cout << Verbose(0) << "Converting to prinicipal axis system." << endl;
1039 } else
1040 cout << Verbose(0) << "Evaluating prinicipal axis." << endl;
1041 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)j);
1042 break;
1043 case 'o':
1044 ExitFlag = 1;
1045 SaveFlag = true;
1046 cout << Verbose(0) << "Evaluating volume of the convex envelope.";
1047 VolumeOfConvexEnvelope((ofstream *)&cout, &configuration, NULL, mol);
1048 break;
1049 case 'U':
1050 ExitFlag = 1;
1051 volume = atof(argv[argptr++]);
1052 cout << Verbose(0) << "Using " << volume << " angstrom^3 as the volume instead of convex envelope one's." << endl;
1053 case 'u':
1054 ExitFlag = 1;
1055 {
1056 double density;
1057 SaveFlag = true;
1058 cout << Verbose(0) << "Evaluating necessary cell volume for a cluster suspended in water.";
1059 density = atof(argv[argptr++]);
1060 if (density < 1.0) {
1061 cerr << Verbose(0) << "Density must be greater than 1.0g/cm^3 !" << endl;
1062 density = 1.3;
1063 }
1064// for(int i=0;i<NDIM;i++) {
1065// repetition[i] = atoi(argv[argptr++]);
1066// if (repetition[i] < 1)
1067// cerr << Verbose(0) << "ERROR: repetition value must be greater 1!" << endl;
1068// repetition[i] = 1;
1069// }
1070 PrepareClustersinWater((ofstream *)&cout, &configuration, mol, volume, density);
1071 }
1072 break;
1073 case 'd':
1074 ExitFlag = 1;
1075 SaveFlag = true;
1076 for (int axis = 1; axis <= NDIM; axis++) {
1077 int faktor = atoi(argv[argptr++]);
1078 int count;
1079 element ** Elements;
1080 Vector ** vectors;
1081 if (faktor < 1) {
1082 cerr << Verbose(0) << "ERROR: Repetition faktor mus be greater than 1!" << endl;
1083 faktor = 1;
1084 }
1085 mol->CountAtoms((ofstream *)&cout); // recount atoms
1086 if (mol->AtomCount != 0) { // if there is more than none
1087 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand
1088 Elements = new element *[count];
1089 vectors = new Vector *[count];
1090 j = 0;
1091 first = mol->start;
1092 while (first->next != mol->end) { // make a list of all atoms with coordinates and element
1093 first = first->next;
1094 Elements[j] = first->type;
1095 vectors[j] = &first->x;
1096 j++;
1097 }
1098 if (count != j)
1099 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl;
1100 x.Zero();
1101 y.Zero();
1102 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
1103 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times
1104 x.AddVector(&y); // per factor one cell width further
1105 for (int k=count;k--;) { // go through every atom of the original cell
1106 first = new atom(); // create a new body
1107 first->x.CopyVector(vectors[k]); // use coordinate of original atom
1108 first->x.AddVector(&x); // translate the coordinates
1109 first->type = Elements[k]; // insert original element
1110 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)
1111 }
1112 }
1113 // free memory
1114 delete[](Elements);
1115 delete[](vectors);
1116 // correct cell size
1117 if (axis < 0) { // if sign was negative, we have to translate everything
1118 x.Zero();
1119 x.AddVector(&y);
1120 x.Scale(-(faktor-1));
1121 mol->Translate(&x);
1122 }
1123 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor;
1124 }
1125 }
1126 break;
1127 default: // no match? Step on
1128 if (argv[argptr][0] != '-') // if it started with a '-' we've already made a step!
1129 argptr++;
1130 break;
1131 }
1132 }
1133 } else argptr++;
1134 } while (argptr < argc);
1135 if (SaveFlag)
1136 SaveConfig(ConfigFileName, &configuration, periode, mol);
1137 if ((ExitFlag >= 1)) {
1138 delete(mol);
1139 delete(periode);
1140 return (ExitFlag);
1141 }
1142 } else { // no arguments, hence scan the elements db
1143 if (periode->LoadPeriodentafel(PathToDatabases))
1144 cout << Verbose(0) << "Element list loaded successfully." << endl;
1145 else
1146 cout << Verbose(0) << "Element list loading failed." << endl;
1147 configuration.RetrieveConfigPathAndName("main_pcp_linux");
1148 }
1149 return(0);
1150};
1151
1152/********************************************** Main routine **************************************/
1153
1154int main(int argc, char **argv)
1155{
1156 periodentafel *periode = new periodentafel; // and a period table of all elements
1157 molecule *mol = new molecule(periode); // first we need an empty molecule
1158 config configuration;
1159 double tmp1;
1160 double bond, min_bond;
1161 atom *first, *second;
1162 char choice; // menu choice char
1163 Vector x,y,z,n; // coordinates for absolute point in cell volume
1164 double *factor; // unit factor if desired
1165 bool valid; // flag if input was valid or not
1166 ifstream test;
1167 ofstream output;
1168 string line;
1169 char filename[MAXSTRINGSIZE];
1170 char *ConfigFileName = NULL;
1171 char *ElementsFileName = NULL;
1172 int Z;
1173 int j, axis, count, faktor;
1174 int *MinimumRingSize = NULL;
1175 MoleculeLeafClass *Subgraphs = NULL;
1176 clock_t start,end;
1177 element **Elements;
1178 Vector **vectors;
1179
1180 // =========================== PARSE COMMAND LINE OPTIONS ====================================
1181 j = ParseCommandLineOptions(argc, argv, mol, periode, configuration, ConfigFileName, ElementsFileName);
1182 if (j == 1) return 0; // just for -v and -h options
1183 if (j) return j; // something went wrong
1184
1185 // General stuff
1186 if (mol->cell_size[0] == 0.) {
1187 cout << Verbose(0) << "enter lower triadiagonal form of basis matrix" << endl << endl;
1188 for (int i=0;i<6;i++) {
1189 cout << Verbose(1) << "Cell size" << i << ": ";
1190 cin >> mol->cell_size[i];
1191 }
1192 }
1193
1194 // =========================== START INTERACTIVE SESSION ====================================
1195
1196 // now the main construction loop
1197 cout << Verbose(0) << endl << "Now comes the real construction..." << endl;
1198 do {
1199 cout << Verbose(0) << endl << endl;
1200 cout << Verbose(0) << "============Element list=======================" << endl;
1201 mol->Checkout((ofstream *)&cout);
1202 cout << Verbose(0) << "============Atom list==========================" << endl;
1203 mol->Output((ofstream *)&cout);
1204 cout << Verbose(0) << "============Menu===============================" << endl;
1205 cout << Verbose(0) << "a - add an atom" << endl;
1206 cout << Verbose(0) << "r - remove an atom" << endl;
1207 cout << Verbose(0) << "b - scale a bond between atoms" << endl;
1208 cout << Verbose(0) << "u - change an atoms element" << endl;
1209 cout << Verbose(0) << "l - measure lengths, angles, ... for an atom" << endl;
1210 cout << Verbose(0) << "-----------------------------------------------" << endl;
1211 cout << Verbose(0) << "p - Parse xyz file" << endl;
1212 cout << Verbose(0) << "e - edit the current configuration" << endl;
1213 cout << Verbose(0) << "o - create connection matrix" << endl;
1214 cout << Verbose(0) << "f - fragment molecule many-body bond order style" << endl;
1215 cout << Verbose(0) << "-----------------------------------------------" << endl;
1216 cout << Verbose(0) << "d - duplicate molecule/periodic cell" << endl;
1217 cout << Verbose(0) << "i - realign molecule" << endl;
1218 cout << Verbose(0) << "m - mirror all molecules" << endl;
1219 cout << Verbose(0) << "t - translate molecule by vector" << endl;
1220 cout << Verbose(0) << "c - scale by unit transformation" << endl;
1221 cout << Verbose(0) << "g - center atoms in box" << endl;
1222 cout << Verbose(0) << "-----------------------------------------------" << endl;
1223 cout << Verbose(0) << "s - save current setup to config file" << endl;
1224 cout << Verbose(0) << "T - call the current test routine" << endl;
1225 cout << Verbose(0) << "q - quit" << endl;
1226 cout << Verbose(0) << "===============================================" << endl;
1227 cout << Verbose(0) << "Input: ";
1228 cin >> choice;
1229
1230 switch (choice) {
1231 default:
1232 case 'a': // add atom
1233 AddAtoms(periode, mol);
1234 choice = 'a';
1235 break;
1236
1237 case 'b': // scale a bond
1238 cout << Verbose(0) << "Scaling bond length between two atoms." << endl;
1239 first = mol->AskAtom("Enter first (fixed) atom: ");
1240 second = mol->AskAtom("Enter second (shifting) atom: ");
1241 min_bond = 0.;
1242 for (int i=NDIM;i--;)
1243 min_bond += (first->x.x[i]-second->x.x[i])*(first->x.x[i] - second->x.x[i]);
1244 min_bond = sqrt(min_bond);
1245 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;
1246 cout << Verbose(0) << "Enter new bond length [a.u.]: ";
1247 cin >> bond;
1248 for (int i=NDIM;i--;) {
1249 second->x.x[i] -= (second->x.x[i]-first->x.x[i])/min_bond*(min_bond-bond);
1250 }
1251 //cout << Verbose(0) << "New coordinates of Atom " << second->nr << " are: ";
1252 //second->Output(second->type->No, 1, (ofstream *)&cout);
1253 break;
1254
1255 case 'c': // unit scaling of the metric
1256 cout << Verbose(0) << "Angstroem -> Bohrradius: 1.8897261\t\tBohrradius -> Angstroem: 0.52917721" << endl;
1257 cout << Verbose(0) << "Enter three factors: ";
1258 factor = new double[NDIM];
1259 cin >> factor[0];
1260 cin >> factor[1];
1261 cin >> factor[2];
1262 valid = true;
1263 mol->Scale(&factor);
1264 delete[](factor);
1265 break;
1266
1267 case 'd': // duplicate the periodic cell along a given axis, given times
1268 cout << Verbose(0) << "State the axis [(+-)123]: ";
1269 cin >> axis;
1270 cout << Verbose(0) << "State the factor: ";
1271 cin >> faktor;
1272
1273 mol->CountAtoms((ofstream *)&cout); // recount atoms
1274 if (mol->AtomCount != 0) { // if there is more than none
1275 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand
1276 Elements = new element *[count];
1277 vectors = new Vector *[count];
1278 j = 0;
1279 first = mol->start;
1280 while (first->next != mol->end) { // make a list of all atoms with coordinates and element
1281 first = first->next;
1282 Elements[j] = first->type;
1283 vectors[j] = &first->x;
1284 j++;
1285 }
1286 if (count != j)
1287 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl;
1288 x.Zero();
1289 y.Zero();
1290 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
1291 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times
1292 x.AddVector(&y); // per factor one cell width further
1293 for (int k=count;k--;) { // go through every atom of the original cell
1294 first = new atom(); // create a new body
1295 first->x.CopyVector(vectors[k]); // use coordinate of original atom
1296 first->x.AddVector(&x); // translate the coordinates
1297 first->type = Elements[k]; // insert original element
1298 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)
1299 }
1300 }
1301 if (mol->first->next != mol->last) // if connect matrix is present already, redo it
1302 mol->CreateAdjacencyList((ofstream *)&cout, mol->BondDistance, configuration.GetIsAngstroem());
1303 // free memory
1304 delete[](Elements);
1305 delete[](vectors);
1306 // correct cell size
1307 if (axis < 0) { // if sign was negative, we have to translate everything
1308 x.Zero();
1309 x.AddVector(&y);
1310 x.Scale(-(faktor-1));
1311 mol->Translate(&x);
1312 }
1313 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor;
1314 }
1315 break;
1316
1317 case 'e': // edit each field of the configuration
1318 configuration.Edit(mol);
1319 break;
1320
1321 case 'f':
1322 FragmentAtoms(mol, &configuration);
1323 break;
1324
1325 case 'g': // center the atoms
1326 CenterAtoms(mol);
1327 break;
1328
1329 case 'i': // align all atoms
1330 AlignAtoms(periode, mol);
1331 break;
1332
1333 case 'l': // measure distances or angles
1334 MeasureAtoms(periode, mol, &configuration);
1335 break;
1336
1337 case 'm': // mirror atoms along a given axis
1338 MirrorAtoms(mol);
1339 break;
1340
1341 case 'o': // create the connection matrix
1342 cout << Verbose(0) << "What's the maximum bond distance: ";
1343 cin >> tmp1;
1344 start = clock();
1345 mol->CreateAdjacencyList((ofstream *)&cout, tmp1, configuration.GetIsAngstroem());
1346 //mol->CreateListOfBondsPerAtom((ofstream *)&cout);
1347 Subgraphs = mol->DepthFirstSearchAnalysis((ofstream *)&cout, MinimumRingSize);
1348 while (Subgraphs->next != NULL) {
1349 Subgraphs = Subgraphs->next;
1350 delete(Subgraphs->previous);
1351 }
1352 delete(Subgraphs); // we don't need the list here, so free everything
1353 delete[](MinimumRingSize);
1354 Subgraphs = NULL;
1355 end = clock();
1356 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
1357 break;
1358
1359 case 'p': // parse and XYZ file
1360 cout << Verbose(0) << "Format should be XYZ with: ShorthandOfElement\tX\tY\tZ" << endl;
1361 do {
1362 cout << Verbose(0) << "Enter file name: ";
1363 cin >> filename;
1364 } while (!mol->AddXYZFile(filename));
1365 break;
1366
1367 case 'q': // quit
1368 break;
1369
1370 case 'r': // remove atom
1371 RemoveAtoms(mol);
1372 break;
1373
1374 case 's': // save to config file
1375 SaveConfig(ConfigFileName, &configuration, periode, mol);
1376 break;
1377
1378 case 't': // translate all atoms
1379 cout << Verbose(0) << "Enter translation vector." << endl;
1380 x.AskPosition(mol->cell_size,0);
1381 mol->Translate((const Vector *)&x);
1382 break;
1383
1384 case 'T':
1385 testroutine(mol);
1386 break;
1387
1388 case 'u': // change an atom's element
1389 first = NULL;
1390 do {
1391 cout << Verbose(0) << "Change the element of which atom: ";
1392 cin >> Z;
1393 } while ((first = mol->FindAtom(Z)) == NULL);
1394 cout << Verbose(0) << "New element by atomic number Z: ";
1395 cin >> Z;
1396 first->type = periode->FindElement(Z);
1397 cout << Verbose(0) << "Atom " << first->nr << "'s element is " << first->type->name << "." << endl;
1398 break;
1399 };
1400 } while (choice != 'q');
1401
1402 // save element data base
1403 if (periode->StorePeriodentafel(ElementsFileName)) //ElementsFileName
1404 cout << Verbose(0) << "Saving of elements.db successful." << endl;
1405 else
1406 cout << Verbose(0) << "Saving of elements.db failed." << endl;
1407
1408 // Free all
1409 if (Subgraphs != NULL) { // free disconnected subgraph list of DFS analysis was performed
1410 while (Subgraphs->next != NULL) {
1411 Subgraphs = Subgraphs->next;
1412 delete(Subgraphs->previous);
1413 }
1414 delete(Subgraphs);
1415 }
1416 delete(mol);
1417 delete(periode);
1418 return (0);
1419}
1420
1421/********************************************** E N D **************************************************/
Note: See TracBrowser for help on using the repository browser.