source: src/builder.cpp@ d427bd

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

BUGFIX: If other databases could not be loaded, no error was produced, resulting in strange behaviour of the fragmentation routine.

Now an error message is produced, though we still continue. The problem was the switch in handling const char * and a huge mess in LoadPeriodenTafel() with strncat and strncpy.

  • Property mode set to 100644
File size: 54.4 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->OutputXYZ(&output))
706 cout << Verbose(0) << "Saving of XYZ file successful." << endl;
707 else
708 cout << Verbose(0) << "Saving of XYZ file failed." << endl;
709 output.close();
710 output.clear();
711
712 if (!strcmp(configuration->configpath, configuration->GetDefaultPath())) {
713 cerr << "WARNING: config is found under different path then stated in config file::defaultpath!" << endl;
714 }
715};
716
717/** Parses the command line options.
718 * \param argc argument count
719 * \param **argv arguments array
720 * \param *mol molecule structure
721 * \param *periode elements structure
722 * \param configuration config file structure
723 * \param *ConfigFileName pointer to config file name in **argv
724 * \param *PathToDatabases pointer to db's path in **argv
725 * \return exit code (0 - successful, all else - something's wrong)
726 */
727static int ParseCommandLineOptions(int argc, char **argv, molecule *&mol, periodentafel *&periode, config& configuration, char *&ConfigFileName, char *&PathToDatabases)
728{
729 element *finder;
730 vector x,y,z,n; // coordinates for absolute point in cell volume
731 double *factor; // unit factor if desired
732 ifstream test;
733 ofstream output;
734 string line;
735 atom *first;
736 int ExitFlag = 0;
737 int j;
738 double volume = 0.;
739 enum ConfigStatus config_present = absent;
740 clock_t start,end;
741 int argptr;
742 PathToDatabases = LocalPath;
743
744 if (argc > 1) { // config file specified as option
745 // 1. : Parse options that just set variables or print help
746 argptr = 1;
747 do {
748 if (argv[argptr][0] == '-') {
749 cout << Verbose(0) << "Recognized command line argument: " << argv[argptr][1] << ".\n";
750 argptr++;
751 switch(argv[argptr-1][1]) {
752 case 'h':
753 case 'H':
754 case '?':
755 cout << "MoleCuilder suite" << endl << "==================" << endl << endl;
756 cout << "Usage: " << argv[0] << "[config file] [-{acefpsthH?vfrp}] [further arguments]" << endl;
757 cout << "or simply " << argv[0] << " without arguments for interactive session." << endl;
758 cout << "\t-a Z x1 x2 x3\tAdd new atom of element Z at coordinates (x1,x2,x3)." << endl;
759 cout << "\t-b x1 x2 x3\tCenter atoms in domain with given edge lengths of (x1,x2,x3)." << endl;
760 cout << "\t-c x1 x2 x3\tCenter atoms in domain with a minimum distance to boundary of (x1,x2,x3)." << endl;
761 cout << "\t-d x1 x2 x3\tDuplicate cell along each axis by given factor." << endl;
762 cout << "\t-e <file>\tSets the databases path to be parsed (default: ./)." << endl;
763 cout << "\t-f <dist> <order>\tFragments the molecule in BOSSANOVA manner and stores config files in same dir as config." << endl;
764 cout << "\t-h/-H/-?\tGive this help screen." << endl;
765 cout << "\t-m\tAlign in PAS with greatest EV along z axis." << endl;
766 cout << "\t-n\tFast parsing (i.e. no trajectories are looked for)." << endl;
767 cout << "\t-o\tGet volume of the convex envelope (and store to tecplot file)." << endl;
768 cout << "\t-p <file>\tParse given xyz file and create raw config file from it." << endl;
769 cout << "\t-r\t\tConvert file from an old pcp syntax." << endl;
770 cout << "\t-t x1 x2 x3\tTranslate all atoms by this vector (x1,x2,x3)." << endl;
771 cout << "\t-s x1 x2 x3\tScale all atom coordinates by this vector (x1,x2,x3)." << endl;
772 cout << "\t-u rho\tsuspend in water solution and output necessary cell lengths, average density rho and repetition." << endl;
773 cout << "\t-v/-V\t\tGives version information." << endl;
774 cout << "Note: config files must not begin with '-' !" << endl;
775 delete(mol);
776 delete(periode);
777 return (1);
778 break;
779 case 'v':
780 case 'V':
781 cout << argv[0] << " " << VERSIONSTRING << endl;
782 cout << "Build your own molecule position set." << endl;
783 delete(mol);
784 delete(periode);
785 return (1);
786 break;
787 case 'e':
788 cout << "Using " << argv[argptr] << " as elements database." << endl;
789 PathToDatabases = argv[argptr];
790 argptr+=1;
791 break;
792 case 'n':
793 cout << "I won't parse trajectories." << endl;
794 configuration.FastParsing = true;
795 default: // no match? Step on
796 argptr++;
797 break;
798 }
799 } else
800 argptr++;
801 } while (argptr < argc);
802
803 // 2. Parse the element database
804 if (periode->LoadPeriodentafel(PathToDatabases)) {
805 cout << Verbose(0) << "Element list loaded successfully." << endl;
806 periode->Output((ofstream *)&cout);
807 } else {
808 cout << Verbose(0) << "Element list loading failed." << endl;
809 return 1;
810 }
811
812 // 3. Find config file name and parse if possible
813 if (argv[1][0] != '-') {
814 cout << Verbose(0) << "Config file given." << endl;
815 test.open(argv[1], ios::in);
816 if (test == NULL) {
817 //return (1);
818 output.open(argv[1], ios::out);
819 if (output == NULL) {
820 cout << Verbose(1) << "Specified config file " << argv[1] << " not found." << endl;
821 config_present = absent;
822 } else {
823 cout << "Empty configuration file." << endl;
824 ConfigFileName = argv[1];
825 config_present = empty;
826 output.close();
827 }
828 } else {
829 test.close();
830 ConfigFileName = argv[1];
831 cout << Verbose(1) << "Specified config file found, parsing ... ";
832 switch (configuration.TestSyntax(ConfigFileName, periode, mol)) {
833 case 1:
834 cout << "new syntax." << endl;
835 configuration.Load(ConfigFileName, periode, mol);
836 config_present = present;
837 break;
838 case 0:
839 cout << "old syntax." << endl;
840 configuration.LoadOld(ConfigFileName, periode, mol);
841 config_present = present;
842 break;
843 default:
844 cout << "Unknown syntax or empty, yet present file." << endl;
845 config_present = empty;
846 }
847 }
848 } else
849 config_present = absent;
850
851 // 4. parse again through options, now for those depending on elements db and config presence
852 argptr = 1;
853 do {
854 cout << "Current Command line argument: " << argv[argptr] << "." << endl;
855 if (argv[argptr][0] == '-') {
856 argptr++;
857 if ((config_present == present) || (config_present == empty)) {
858 switch(argv[argptr-1][1]) {
859 case 'p':
860 ExitFlag = 1;
861 cout << Verbose(1) << "Parsing xyz file for new atoms." << endl;
862 if (!mol->AddXYZFile(argv[argptr]))
863 cout << Verbose(2) << "File not found." << endl;
864 else
865 cout << Verbose(2) << "File found and parsed." << endl;
866 config_present = present;
867 break;
868 default: // no match? Don't step on (this is done in next switch's default)
869 break;
870 }
871 }
872 if (config_present == present) {
873 switch(argv[argptr-1][1]) {
874 case 't':
875 ExitFlag = 1;
876 cout << Verbose(1) << "Translating all ions to new origin." << endl;
877 for (int i=NDIM;i--;)
878 x.x[i] = atof(argv[argptr+i]);
879 mol->Translate((const vector *)&x);
880 argptr+=3;
881 break;
882 case 'a':
883 ExitFlag = 1;
884 cout << Verbose(1) << "Adding new atom." << endl;
885 first = new atom;
886 for (int i=NDIM;i--;)
887 first->x.x[i] = atof(argv[argptr+1+i]);
888 finder = periode->start;
889 while (finder != periode->end) {
890 finder = finder->next;
891 if (strncmp(finder->symbol,argv[argptr+1],3) == 0) {
892 first->type = finder;
893 break;
894 }
895 }
896 mol->AddAtom(first); // add to molecule
897 argptr+=4;
898 break;
899 case 's':
900 ExitFlag = 1;
901 j = -1;
902 cout << Verbose(1) << "Scaling all ion positions by factor." << endl;
903 factor = new double[NDIM];
904 factor[0] = atof(argv[argptr]);
905 if (argc > argptr+1)
906 argptr++;
907 factor[1] = atof(argv[argptr]);
908 if (argc > argptr+1)
909 argptr++;
910 factor[2] = atof(argv[argptr]);
911 mol->Scale(&factor);
912 for (int i=0;i<NDIM;i++) {
913 j += i+1;
914 x.x[i] = atof(argv[NDIM+i]);
915 mol->cell_size[j]*=factor[i];
916 }
917 delete[](factor);
918 argptr+=1;
919 break;
920 case 'b':
921 ExitFlag = 1;
922 j = -1;
923 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl;
924 j=-1;
925 for (int i=0;i<NDIM;i++) {
926 j += i+1;
927 x.x[i] = atof(argv[argptr++]);
928 mol->cell_size[j] += x.x[i]*2.;
929 }
930 // center
931 mol->CenterInBox((ofstream *)&cout, &x);
932 // update Box of atoms by boundary
933 mol->SetBoxDimension(&x);
934 break;
935 case 'c':
936 ExitFlag = 1;
937 j = -1;
938 cout << Verbose(1) << "Centering atoms in config file within given additional boundary." << endl;
939 // make every coordinate positive
940 mol->CenterEdge((ofstream *)&cout, &x);
941 // update Box of atoms by boundary
942 mol->SetBoxDimension(&x);
943 // translate each coordinate by boundary
944 j=-1;
945 for (int i=0;i<NDIM;i++) {
946 j += i+1;
947 x.x[i] = atof(argv[argptr++]);
948 mol->cell_size[j] += x.x[i]*2.;
949 }
950 mol->Translate((const vector *)&x);
951 break;
952 case 'r':
953 ExitFlag = 1;
954 cout << Verbose(1) << "Converting config file from supposed old to new syntax." << endl;
955 break;
956 case 'f':
957 if (ExitFlag ==0) ExitFlag = 2; // only set if not already by other command line switch
958 cout << "Fragmenting molecule with bond distance " << argv[argptr] << " angstroem, order of " << argv[argptr+1] << "." << endl;
959 if (argc >= argptr+2) {
960 cout << Verbose(0) << "Creating connection matrix..." << endl;
961 start = clock();
962 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr++]), configuration.GetIsAngstroem());
963 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl;
964 if (mol->first->next != mol->last) {
965 mol->FragmentMolecule((ofstream *)&cout, atoi(argv[argptr]), &configuration);
966 }
967 end = clock();
968 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
969 argptr+=1;
970 } else {
971 cerr << "Not enough arguments for fragmentation: -f <max. bond distance> <bond order>" << endl;
972 }
973 break;
974 case 'm':
975 ExitFlag = 1;
976 j = atoi(argv[argptr++]);
977 if ((j<0) || (j>1)) {
978 cerr << Verbose(1) << "ERROR: Argument of '-m' should be either 0 for no-rotate or 1 for rotate." << endl;
979 j = 0;
980 }
981 if (j)
982 cout << Verbose(0) << "Converting to prinicipal axis system." << endl;
983 else
984 cout << Verbose(0) << "Evaluating prinicipal axis." << endl;
985 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)j);
986 break;
987 case 'o':
988 ExitFlag = 1;
989 cout << Verbose(0) << "Evaluating volume of the convex envelope.";
990 VolumeOfConvexEnvelope((ofstream *)&cout, &configuration, NULL, mol);
991 break;
992 case 'U':
993 volume = atof(argv[argptr++]);
994 cout << Verbose(0) << "Using " << volume << " angstrom^3 as the volume instead of convex envelope one's." << endl;
995 case 'u':
996 {
997 double density;
998 ExitFlag = 1;
999 cout << Verbose(0) << "Evaluating necessary cell volume for a cluster suspended in water.";
1000 density = atof(argv[argptr++]);
1001 if (density < 1.0) {
1002 cerr << Verbose(0) << "Density must be greater than 1.0g/cm^3 !" << endl;
1003 density = 1.3;
1004 }
1005// for(int i=0;i<NDIM;i++) {
1006// repetition[i] = atoi(argv[argptr++]);
1007// if (repetition[i] < 1)
1008// cerr << Verbose(0) << "ERROR: repetition value must be greater 1!" << endl;
1009// repetition[i] = 1;
1010// }
1011 PrepareClustersinWater((ofstream *)&cout, &configuration, mol, volume, density);
1012 }
1013 break;
1014 case 'd':
1015 for (int axis = 1; axis <= NDIM; axis++) {
1016 int faktor = atoi(argv[argptr++]);
1017 int count;
1018 element ** Elements;
1019 vector ** Vectors;
1020 if (faktor < 1) {
1021 cerr << Verbose(0) << "ERROR: Repetition faktor mus be greater than 1!" << endl;
1022 faktor = 1;
1023 }
1024 mol->CountAtoms((ofstream *)&cout); // recount atoms
1025 if (mol->AtomCount != 0) { // if there is more than none
1026 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand
1027 Elements = new element *[count];
1028 Vectors = new vector *[count];
1029 j = 0;
1030 first = mol->start;
1031 while (first->next != mol->end) { // make a list of all atoms with coordinates and element
1032 first = first->next;
1033 Elements[j] = first->type;
1034 Vectors[j] = &first->x;
1035 j++;
1036 }
1037 if (count != j)
1038 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl;
1039 x.Zero();
1040 y.Zero();
1041 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
1042 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times
1043 x.AddVector(&y); // per factor one cell width further
1044 for (int k=count;k--;) { // go through every atom of the original cell
1045 first = new atom(); // create a new body
1046 first->x.CopyVector(Vectors[k]); // use coordinate of original atom
1047 first->x.AddVector(&x); // translate the coordinates
1048 first->type = Elements[k]; // insert original element
1049 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)
1050 }
1051 }
1052 // free memory
1053 delete[](Elements);
1054 delete[](Vectors);
1055 // correct cell size
1056 if (axis < 0) { // if sign was negative, we have to translate everything
1057 x.Zero();
1058 x.AddVector(&y);
1059 x.Scale(-(faktor-1));
1060 mol->Translate(&x);
1061 }
1062 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor;
1063 }
1064 }
1065 break;
1066 default: // no match? Step on
1067 if (argv[argptr][0] != '-') // if it started with a '-' we've already made a step!
1068 argptr++;
1069 break;
1070 }
1071 }
1072 } else argptr++;
1073 } while (argptr < argc);
1074 if (ExitFlag == 1) // 1 means save and exit
1075 SaveConfig(ConfigFileName, &configuration, periode, mol);
1076 if (ExitFlag >= 1) { // 2 means just exit
1077 delete(mol);
1078 delete(periode);
1079 return (1);
1080 }
1081 } else { // no arguments, hence scan the elements db
1082 if (periode->LoadPeriodentafel(PathToDatabases))
1083 cout << Verbose(0) << "Element list loaded successfully." << endl;
1084 else
1085 cout << Verbose(0) << "Element list loading failed." << endl;
1086 configuration.RetrieveConfigPathAndName("main_pcp_linux");
1087 }
1088 return(0);
1089};
1090
1091/********************************************** Main routine **************************************/
1092
1093int main(int argc, char **argv)
1094{
1095 periodentafel *periode = new periodentafel; // and a period table of all elements
1096 molecule *mol = new molecule(periode); // first we need an empty molecule
1097 config configuration;
1098 double tmp1;
1099 double bond, min_bond;
1100 atom *first, *second;
1101 char choice; // menu choice char
1102 vector x,y,z,n; // coordinates for absolute point in cell volume
1103 double *factor; // unit factor if desired
1104 bool valid; // flag if input was valid or not
1105 ifstream test;
1106 ofstream output;
1107 string line;
1108 char filename[MAXSTRINGSIZE];
1109 char *ConfigFileName = NULL;
1110 char *ElementsFileName = NULL;
1111 int Z;
1112 int j, axis, count, faktor;
1113 int *MinimumRingSize = NULL;
1114 MoleculeLeafClass *Subgraphs = NULL;
1115 clock_t start,end;
1116 element **Elements;
1117 vector **Vectors;
1118
1119 // =========================== PARSE COMMAND LINE OPTIONS ====================================
1120 j = ParseCommandLineOptions(argc, argv, mol, periode, configuration, ConfigFileName, ElementsFileName);
1121 if (j == 1) return 0; // just for -v and -h options
1122 if (j) return j; // something went wrong
1123
1124 // General stuff
1125 if (mol->cell_size[0] == 0.) {
1126 cout << Verbose(0) << "enter lower triadiagonal form of basis matrix" << endl << endl;
1127 for (int i=0;i<6;i++) {
1128 cout << Verbose(1) << "Cell size" << i << ": ";
1129 cin >> mol->cell_size[i];
1130 }
1131 }
1132
1133 // =========================== START INTERACTIVE SESSION ====================================
1134
1135 // now the main construction loop
1136 cout << Verbose(0) << endl << "Now comes the real construction..." << endl;
1137 do {
1138 cout << Verbose(0) << endl << endl;
1139 cout << Verbose(0) << "============Element list=======================" << endl;
1140 mol->Checkout((ofstream *)&cout);
1141 cout << Verbose(0) << "============Atom list==========================" << endl;
1142 mol->Output((ofstream *)&cout);
1143 cout << Verbose(0) << "============Menu===============================" << endl;
1144 cout << Verbose(0) << "a - add an atom" << endl;
1145 cout << Verbose(0) << "r - remove an atom" << endl;
1146 cout << Verbose(0) << "b - scale a bond between atoms" << endl;
1147 cout << Verbose(0) << "u - change an atoms element" << endl;
1148 cout << Verbose(0) << "l - measure lengths, angles, ... for an atom" << endl;
1149 cout << Verbose(0) << "-----------------------------------------------" << endl;
1150 cout << Verbose(0) << "p - Parse xyz file" << endl;
1151 cout << Verbose(0) << "e - edit the current configuration" << endl;
1152 cout << Verbose(0) << "o - create connection matrix" << endl;
1153 cout << Verbose(0) << "f - fragment molecule many-body bond order style" << endl;
1154 cout << Verbose(0) << "-----------------------------------------------" << endl;
1155 cout << Verbose(0) << "d - duplicate molecule/periodic cell" << endl;
1156 cout << Verbose(0) << "i - realign molecule" << endl;
1157 cout << Verbose(0) << "m - mirror all molecules" << endl;
1158 cout << Verbose(0) << "t - translate molecule by vector" << endl;
1159 cout << Verbose(0) << "c - scale by unit transformation" << endl;
1160 cout << Verbose(0) << "g - center atoms in box" << endl;
1161 cout << Verbose(0) << "-----------------------------------------------" << endl;
1162 cout << Verbose(0) << "s - save current setup to config file" << endl;
1163 cout << Verbose(0) << "T - call the current test routine" << endl;
1164 cout << Verbose(0) << "q - quit" << endl;
1165 cout << Verbose(0) << "===============================================" << endl;
1166 cout << Verbose(0) << "Input: ";
1167 cin >> choice;
1168
1169 switch (choice) {
1170 default:
1171 case 'a': // add atom
1172 AddAtoms(periode, mol);
1173 choice = 'a';
1174 break;
1175
1176 case 'b': // scale a bond
1177 cout << Verbose(0) << "Scaling bond length between two atoms." << endl;
1178 first = mol->AskAtom("Enter first (fixed) atom: ");
1179 second = mol->AskAtom("Enter second (shifting) atom: ");
1180 min_bond = 0.;
1181 for (int i=NDIM;i--;)
1182 min_bond += (first->x.x[i]-second->x.x[i])*(first->x.x[i] - second->x.x[i]);
1183 min_bond = sqrt(min_bond);
1184 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;
1185 cout << Verbose(0) << "Enter new bond length [a.u.]: ";
1186 cin >> bond;
1187 for (int i=NDIM;i--;) {
1188 second->x.x[i] -= (second->x.x[i]-first->x.x[i])/min_bond*(min_bond-bond);
1189 }
1190 //cout << Verbose(0) << "New coordinates of Atom " << second->nr << " are: ";
1191 //second->Output(second->type->No, 1, (ofstream *)&cout);
1192 break;
1193
1194 case 'c': // unit scaling of the metric
1195 cout << Verbose(0) << "Angstroem -> Bohrradius: 1.8897261\t\tBohrradius -> Angstroem: 0.52917721" << endl;
1196 cout << Verbose(0) << "Enter three factors: ";
1197 factor = new double[NDIM];
1198 cin >> factor[0];
1199 cin >> factor[1];
1200 cin >> factor[2];
1201 valid = true;
1202 mol->Scale(&factor);
1203 delete[](factor);
1204 break;
1205
1206 case 'd': // duplicate the periodic cell along a given axis, given times
1207 cout << Verbose(0) << "State the axis [(+-)123]: ";
1208 cin >> axis;
1209 cout << Verbose(0) << "State the factor: ";
1210 cin >> faktor;
1211
1212 mol->CountAtoms((ofstream *)&cout); // recount atoms
1213 if (mol->AtomCount != 0) { // if there is more than none
1214 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand
1215 Elements = new element *[count];
1216 Vectors = new vector *[count];
1217 j = 0;
1218 first = mol->start;
1219 while (first->next != mol->end) { // make a list of all atoms with coordinates and element
1220 first = first->next;
1221 Elements[j] = first->type;
1222 Vectors[j] = &first->x;
1223 j++;
1224 }
1225 if (count != j)
1226 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl;
1227 x.Zero();
1228 y.Zero();
1229 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
1230 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times
1231 x.AddVector(&y); // per factor one cell width further
1232 for (int k=count;k--;) { // go through every atom of the original cell
1233 first = new atom(); // create a new body
1234 first->x.CopyVector(Vectors[k]); // use coordinate of original atom
1235 first->x.AddVector(&x); // translate the coordinates
1236 first->type = Elements[k]; // insert original element
1237 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)
1238 }
1239 }
1240 if (mol->first->next != mol->last) // if connect matrix is present already, redo it
1241 mol->CreateAdjacencyList((ofstream *)&cout, mol->BondDistance, configuration.GetIsAngstroem());
1242 // free memory
1243 delete[](Elements);
1244 delete[](Vectors);
1245 // correct cell size
1246 if (axis < 0) { // if sign was negative, we have to translate everything
1247 x.Zero();
1248 x.AddVector(&y);
1249 x.Scale(-(faktor-1));
1250 mol->Translate(&x);
1251 }
1252 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor;
1253 }
1254 break;
1255
1256 case 'e': // edit each field of the configuration
1257 configuration.Edit(mol);
1258 break;
1259
1260 case 'f':
1261 FragmentAtoms(mol, &configuration);
1262 break;
1263
1264 case 'g': // center the atoms
1265 CenterAtoms(mol);
1266 break;
1267
1268 case 'i': // align all atoms
1269 AlignAtoms(periode, mol);
1270 break;
1271
1272 case 'l': // measure distances or angles
1273 MeasureAtoms(periode, mol, &configuration);
1274 break;
1275
1276 case 'm': // mirror atoms along a given axis
1277 MirrorAtoms(mol);
1278 break;
1279
1280 case 'o': // create the connection matrix
1281 cout << Verbose(0) << "What's the maximum bond distance: ";
1282 cin >> tmp1;
1283 start = clock();
1284 mol->CreateAdjacencyList((ofstream *)&cout, tmp1, configuration.GetIsAngstroem());
1285 //mol->CreateListOfBondsPerAtom((ofstream *)&cout);
1286 Subgraphs = mol->DepthFirstSearchAnalysis((ofstream *)&cout, MinimumRingSize);
1287 while (Subgraphs->next != NULL) {
1288 Subgraphs = Subgraphs->next;
1289 delete(Subgraphs->previous);
1290 }
1291 delete(Subgraphs); // we don't need the list here, so free everything
1292 delete[](MinimumRingSize);
1293 Subgraphs = NULL;
1294 end = clock();
1295 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
1296 break;
1297
1298 case 'p': // parse and XYZ file
1299 cout << Verbose(0) << "Format should be XYZ with: ShorthandOfElement\tX\tY\tZ" << endl;
1300 do {
1301 cout << Verbose(0) << "Enter file name: ";
1302 cin >> filename;
1303 } while (!mol->AddXYZFile(filename));
1304 break;
1305
1306 case 'q': // quit
1307 break;
1308
1309 case 'r': // remove atom
1310 RemoveAtoms(mol);
1311 break;
1312
1313 case 's': // save to config file
1314 SaveConfig(ConfigFileName, &configuration, periode, mol);
1315 break;
1316
1317 case 't': // translate all atoms
1318 cout << Verbose(0) << "Enter translation vector." << endl;
1319 x.AskPosition(mol->cell_size,0);
1320 mol->Translate((const vector *)&x);
1321 break;
1322
1323 case 'T':
1324 testroutine(mol);
1325 break;
1326
1327 case 'u': // change an atom's element
1328 first = NULL;
1329 do {
1330 cout << Verbose(0) << "Change the element of which atom: ";
1331 cin >> Z;
1332 } while ((first = mol->FindAtom(Z)) == NULL);
1333 cout << Verbose(0) << "New element by atomic number Z: ";
1334 cin >> Z;
1335 first->type = periode->FindElement(Z);
1336 cout << Verbose(0) << "Atom " << first->nr << "'s element is " << first->type->name << "." << endl;
1337 break;
1338 };
1339 } while (choice != 'q');
1340
1341 // save element data base
1342 if (periode->StorePeriodentafel(ElementsFileName)) //ElementsFileName
1343 cout << Verbose(0) << "Saving of elements.db successful." << endl;
1344 else
1345 cout << Verbose(0) << "Saving of elements.db failed." << endl;
1346
1347 // Free all
1348 if (Subgraphs != NULL) { // free disconnected subgraph list of DFS analysis was performed
1349 while (Subgraphs->next != NULL) {
1350 Subgraphs = Subgraphs->next;
1351 delete(Subgraphs->previous);
1352 }
1353 delete(Subgraphs);
1354 }
1355 delete(mol);
1356 delete(periode);
1357 return (0);
1358}
1359
1360/********************************************** E N D **************************************************/
Note: See TracBrowser for help on using the repository browser.