source: src/builder.cpp@ 62f793

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

thermostats enumerator, necessary variables included in class config, molecule::Thermostats() and ..::Constrained
Potential()

Thermostat header definitions implemented. Can be parsed from the ESPACK config file into class config
ConstrainedPotential() calculates the transformation between two given configurations my minimsing a penalty func
tional of the distance to travel per atom. This was implemented due to Michael Griebel's talk during the MultiMat

Closing meeting in order to produce some visuals. It basically mimics a "Bain Transformation". But it is not yet
perfectly implemented.

Also, MD was corrected in VerletIntegration(). However, forces are still wrong with mpqc, as the kinetic energy increases dramatically during the MD simulation.

  • Property mode set to 100644
File size: 60.8 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) << " f - calculate temperature from current velocity" << endl;
502 cout << Verbose(0) << " g - output all temperatures per step from velocities" << endl;
503 cout << Verbose(0) << "all else - go back" << endl;
504 cout << Verbose(0) << "===============================================" << endl;
505 cout << Verbose(0) << "INPUT: ";
506 cin >> choice;
507
508 switch(choice) {
509 default:
510 cout << Verbose(1) << "Not a valid choice." << endl;
511 break;
512 case 'a':
513 first = mol->AskAtom("Enter first atom: ");
514 for (int i=MAX_ELEMENTS;i--;)
515 min[i] = 0.;
516
517 second = mol->start;
518 while ((second->next != mol->end)) {
519 second = second->next; // advance
520 Z = second->type->Z;
521 tmp1 = 0.;
522 if (first != second) {
523 x.CopyVector((const Vector *)&first->x);
524 x.SubtractVector((const Vector *)&second->x);
525 tmp1 = x.Norm();
526 }
527 if ((tmp1 != 0.) && ((min[Z] == 0.) || (tmp1 < min[Z]))) min[Z] = tmp1;
528 //cout << Verbose(0) << "Bond length between Atom " << first->nr << " and " << second->nr << ": " << tmp1 << " a.u." << endl;
529 }
530 for (int i=MAX_ELEMENTS;i--;)
531 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;
532 break;
533
534 case 'b':
535 first = mol->AskAtom("Enter first atom: ");
536 second = mol->AskAtom("Enter second atom: ");
537 for (int i=NDIM;i--;)
538 min[i] = 0.;
539 x.CopyVector((const Vector *)&first->x);
540 x.SubtractVector((const Vector *)&second->x);
541 tmp1 = x.Norm();
542 cout << Verbose(1) << "Distance vector is ";
543 x.Output((ofstream *)&cout);
544 cout << "." << endl << "Norm of distance is " << tmp1 << "." << endl;
545 break;
546
547 case 'c':
548 cout << Verbose(0) << "Evaluating bond angle between three - first, central, last - atoms." << endl;
549 first = mol->AskAtom("Enter first atom: ");
550 second = mol->AskAtom("Enter central atom: ");
551 third = mol->AskAtom("Enter last atom: ");
552 tmp1 = tmp2 = tmp3 = 0.;
553 x.CopyVector((const Vector *)&first->x);
554 x.SubtractVector((const Vector *)&second->x);
555 y.CopyVector((const Vector *)&third->x);
556 y.SubtractVector((const Vector *)&second->x);
557 cout << Verbose(0) << "Bond angle between first atom Nr." << first->nr << ", central atom Nr." << second->nr << " and last atom Nr." << third->nr << ": ";
558 cout << Verbose(0) << (acos(x.ScalarProduct((const Vector *)&y)/(y.Norm()*x.Norm()))/M_PI*180.) << " degrees" << endl;
559 break;
560 case 'd':
561 cout << Verbose(0) << "Evaluating prinicipal axis." << endl;
562 cout << Verbose(0) << "Shall we rotate? [0/1]: ";
563 cin >> Z;
564 if ((Z >=0) && (Z <=1))
565 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)Z);
566 else
567 mol->PrincipalAxisSystem((ofstream *)&cout, false);
568 break;
569 case 'e':
570 cout << Verbose(0) << "Evaluating volume of the convex envelope.";
571 VolumeOfConvexEnvelope((ofstream *)&cout, configuration, NULL, mol);
572 break;
573 case 'f':
574 mol->OutputTemperatureFromTrajectories((ofstream *)&cout, mol->MDSteps-1, mol->MDSteps, (ofstream *)&cout);
575 break;
576 case 'g':
577 {
578 char filename[255];
579 cout << "Please enter filename: " << endl;
580 cin >> filename;
581 cout << Verbose(1) << "Storing temperatures in " << filename << "." << endl;
582 ofstream *output = new ofstream(filename, ios::trunc);
583 if (!mol->OutputTemperatureFromTrajectories((ofstream *)&cout, 0, mol->MDSteps, output))
584 cout << Verbose(2) << "File could not be written." << endl;
585 else
586 cout << Verbose(2) << "File stored." << endl;
587 output->close();
588 delete(output);
589 }
590 break;
591 }
592};
593
594/** Submenu for measuring out the atoms in the molecule.
595 * \param *mol the molecule with all the atoms
596 * \param *configuration configuration structure for the to be written config files of all fragments
597 */
598static void FragmentAtoms(molecule *mol, config *configuration)
599{
600 int Order1;
601 clock_t start, end;
602
603 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl;
604 cout << Verbose(0) << "What's the desired bond order: ";
605 cin >> Order1;
606 if (mol->first->next != mol->last) { // there are bonds
607 start = clock();
608 mol->FragmentMolecule((ofstream *)&cout, Order1, configuration);
609 end = clock();
610 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
611 } else
612 cout << Verbose(0) << "Connection matrix has not yet been generated!" << endl;
613};
614
615/********************************************** Test routine **************************************/
616
617/** Is called always as option 'T' in the menu.
618 */
619static void testroutine(molecule *mol)
620{
621 // the current test routine checks the functionality of the KeySet&Graph concept:
622 // We want to have a multiindex (the KeySet) describing a unique subgraph
623 atom *Walker = mol->start;
624 int i, comp, counter=0;
625
626 // generate some KeySets
627 cout << "Generating KeySets." << endl;
628 KeySet TestSets[mol->AtomCount+1];
629 i=1;
630 while (Walker->next != mol->end) {
631 Walker = Walker->next;
632 for (int j=0;j<i;j++) {
633 TestSets[j].insert(Walker->nr);
634 }
635 i++;
636 }
637 cout << "Testing insertion of already present item in KeySets." << endl;
638 KeySetTestPair test;
639 test = TestSets[mol->AtomCount-1].insert(Walker->nr);
640 if (test.second) {
641 cout << Verbose(1) << "Insertion worked?!" << endl;
642 } else {
643 cout << Verbose(1) << "Insertion rejected: Present object is " << (*test.first) << "." << endl;
644 }
645 TestSets[mol->AtomCount].insert(mol->end->previous->nr);
646 TestSets[mol->AtomCount].insert(mol->end->previous->previous->previous->nr);
647
648 // constructing Graph structure
649 cout << "Generating Subgraph class." << endl;
650 Graph Subgraphs;
651
652 // insert KeySets into Subgraphs
653 cout << "Inserting KeySets into Subgraph class." << endl;
654 for (int j=0;j<mol->AtomCount;j++) {
655 Subgraphs.insert(GraphPair (TestSets[j],pair<int, double>(counter++, 1.)));
656 }
657 cout << "Testing insertion of already present item in Subgraph." << endl;
658 GraphTestPair test2;
659 test2 = Subgraphs.insert(GraphPair (TestSets[mol->AtomCount],pair<int, double>(counter++, 1.)));
660 if (test2.second) {
661 cout << Verbose(1) << "Insertion worked?!" << endl;
662 } else {
663 cout << Verbose(1) << "Insertion rejected: Present object is " << (*(test2.first)).second.first << "." << endl;
664 }
665
666 // show graphs
667 cout << "Showing Subgraph's contents, checking that it's sorted." << endl;
668 Graph::iterator A = Subgraphs.begin();
669 while (A != Subgraphs.end()) {
670 cout << (*A).second.first << ": ";
671 KeySet::iterator key = (*A).first.begin();
672 comp = -1;
673 while (key != (*A).first.end()) {
674 if ((*key) > comp)
675 cout << (*key) << " ";
676 else
677 cout << (*key) << "! ";
678 comp = (*key);
679 key++;
680 }
681 cout << endl;
682 A++;
683 }
684};
685
686/** Tries given filename or standard on saving the config file.
687 * \param *ConfigFileName name of file
688 * \param *configuration pointer to configuration structure with all the values
689 * \param *periode pointer to periodentafel structure with all the elements
690 * \param *mol pointer to molecule structure with all the atoms and coordinates
691 */
692static void SaveConfig(char *ConfigFileName, config *configuration, periodentafel *periode, molecule *mol)
693{
694 char filename[MAXSTRINGSIZE];
695 ofstream output;
696
697 cout << Verbose(0) << "Storing configuration ... " << endl;
698 // get correct valence orbitals
699 mol->CalculateOrbitals(*configuration);
700 configuration->InitMaxMinStopStep = configuration->MaxMinStopStep = configuration->MaxPsiDouble;
701 if (ConfigFileName != NULL) {
702 output.open(ConfigFileName, ios::trunc);
703 } else if (strlen(configuration->configname) != 0) {
704 output.open(configuration->configname, ios::trunc);
705 } else {
706 output.open(DEFAULTCONFIG, ios::trunc);
707 }
708 cout << Verbose(0) << "Saving of config file ";
709 if (configuration->Save(&output, periode, mol))
710 cout << "successful." << endl;
711 else
712 cout << "failed." << endl;
713 output.close();
714 output.clear();
715
716 // and save to xyz file
717 if (ConfigFileName != NULL) {
718 strcpy(filename, ConfigFileName);
719 strcat(filename, ".xyz");
720 output.open(filename, ios::trunc);
721 }
722 if (output == NULL) {
723 strcpy(filename,"main_pcp_linux");
724 strcat(filename, ".xyz");
725 output.open(filename, ios::trunc);
726 }
727 cout << Verbose(0) << "Saving of XYZ file ";
728 if (mol->MDSteps <= 1) {
729 if (mol->OutputXYZ(&output))
730 cout << "successful." << endl;
731 else
732 cout << "failed." << endl;
733 } else {
734 if (mol->OutputTrajectoriesXYZ(&output))
735 cout << "successful." << endl;
736 else
737 cout << "failed." << endl;
738 }
739 output.close();
740 output.clear();
741
742 // and save as MPQC configuration
743 if (ConfigFileName != NULL) {
744 strcpy(filename, ConfigFileName);
745 strcat(filename, ".in");
746 output.open(filename, ios::trunc);
747 }
748 if (output == NULL) {
749 strcpy(filename,"main_pcp_linux");
750 strcat(filename, ".in");
751 output.open(filename, ios::trunc);
752 }
753 cout << Verbose(0) << "Saving as mpqc input ";
754 if (configuration->SaveMPQC(&output, mol))
755 cout << "done." << endl;
756 else
757 cout << "failed." << endl;
758 output.close();
759 output.clear();
760
761 if (!strcmp(configuration->configpath, configuration->GetDefaultPath())) {
762 cerr << "WARNING: config is found under different path then stated in config file::defaultpath!" << endl;
763 }
764};
765
766/** Parses the command line options.
767 * \param argc argument count
768 * \param **argv arguments array
769 * \param *mol molecule structure
770 * \param *periode elements structure
771 * \param configuration config file structure
772 * \param *ConfigFileName pointer to config file name in **argv
773 * \param *PathToDatabases pointer to db's path in **argv
774 * \return exit code (0 - successful, all else - something's wrong)
775 */
776static int ParseCommandLineOptions(int argc, char **argv, molecule *&mol, periodentafel *&periode, config& configuration, char *&ConfigFileName, char *&PathToDatabases)
777{
778 Vector x,y,z,n; // coordinates for absolute point in cell volume
779 double *factor; // unit factor if desired
780 ifstream test;
781 ofstream output;
782 string line;
783 atom *first;
784 bool SaveFlag = false;
785 int ExitFlag = 0;
786 int j;
787 double volume = 0.;
788 enum ConfigStatus config_present = absent;
789 clock_t start,end;
790 int argptr;
791 PathToDatabases = LocalPath;
792
793 if (argc > 1) { // config file specified as option
794 // 1. : Parse options that just set variables or print help
795 argptr = 1;
796 do {
797 if (argv[argptr][0] == '-') {
798 cout << Verbose(0) << "Recognized command line argument: " << argv[argptr][1] << ".\n";
799 argptr++;
800 switch(argv[argptr-1][1]) {
801 case 'h':
802 case 'H':
803 case '?':
804 cout << "MoleCuilder suite" << endl << "==================" << endl << endl;
805 cout << "Usage: " << argv[0] << "[config file] [-{acefpsthH?vfrp}] [further arguments]" << endl;
806 cout << "or simply " << argv[0] << " without arguments for interactive session." << endl;
807 cout << "\t-a Z x1 x2 x3\tAdd new atom of element Z at coordinates (x1,x2,x3)." << endl;
808 cout << "\t-b x1 x2 x3\tCenter atoms in domain with given edge lengths of (x1,x2,x3)." << endl;
809 cout << "\t-c x1 x2 x3\tCenter atoms in domain with a minimum distance to boundary of (x1,x2,x3)." << endl;
810 cout << "\t-D <bond distance>\tDepth-First-Search Analysis of the molecule, giving cycles and tree/back edges." << endl;
811 cout << "\t-O\tCenter atoms in origin." << endl;
812 cout << "\t-d x1 x2 x3\tDuplicate cell along each axis by given factor." << endl;
813 cout << "\t-e <file>\tSets the databases path to be parsed (default: ./)." << endl;
814 cout << "\t-E <id> <Z>\tChange atom <id>'s element to <Z>, <id> begins at 0." << endl;
815 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;
816 cout << "\t-h/-H/-?\tGive this help screen." << endl;
817 cout << "\t-m <0/1>\tCalculate (0)/ Align in(1) PAS with greatest EV along z axis." << endl;
818 cout << "\t-n\tFast parsing (i.e. no trajectories are looked for)." << endl;
819 cout << "\t-o\tGet volume of the convex envelope (and store to tecplot file)." << endl;
820 cout << "\t-p <file>\tParse given xyz file and create raw config file from it." << endl;
821 cout << "\t-P <file>\tParse given forces file and append as an MD step to config file via Verlet." << endl;
822 cout << "\t-L <step0> <step1> <prefix>\tStore a linear interpolation between two configurations <step0> and <step1> into single config files with prefix <prefix> and as Trajectories into the current config file." << endl;
823 cout << "\t-r\t\tConvert file from an old pcp syntax." << endl;
824 cout << "\t-t x1 x2 x3\tTranslate all atoms by this vector (x1,x2,x3)." << endl;
825 cout << "\t-T <file> Store temperatures from the config file in <file>." << endl;
826 cout << "\t-s x1 x2 x3\tScale all atom coordinates by this vector (x1,x2,x3)." << endl;
827 cout << "\t-u rho\tsuspend in water solution and output necessary cell lengths, average density rho and repetition." << endl;
828 cout << "\t-v/-V\t\tGives version information." << endl;
829 cout << "Note: config files must not begin with '-' !" << endl;
830 delete(mol);
831 delete(periode);
832 return (1);
833 break;
834 case 'v':
835 case 'V':
836 cout << argv[0] << " " << VERSIONSTRING << endl;
837 cout << "Build your own molecule position set." << endl;
838 delete(mol);
839 delete(periode);
840 return (1);
841 break;
842 case 'e':
843 cout << "Using " << argv[argptr] << " as elements database." << endl;
844 PathToDatabases = argv[argptr];
845 argptr+=1;
846 break;
847 case 'n':
848 cout << "I won't parse trajectories." << endl;
849 configuration.FastParsing = true;
850 break;
851 default: // no match? Step on
852 argptr++;
853 break;
854 }
855 } else
856 argptr++;
857 } while (argptr < argc);
858
859 // 2. Parse the element database
860 if (periode->LoadPeriodentafel(PathToDatabases)) {
861 cout << Verbose(0) << "Element list loaded successfully." << endl;
862 //periode->Output((ofstream *)&cout);
863 } else {
864 cout << Verbose(0) << "Element list loading failed." << endl;
865 return 1;
866 }
867
868 // 3. Find config file name and parse if possible
869 if (argv[1][0] != '-') {
870 cout << Verbose(0) << "Config file given." << endl;
871 test.open(argv[1], ios::in);
872 if (test == NULL) {
873 //return (1);
874 output.open(argv[1], ios::out);
875 if (output == NULL) {
876 cout << Verbose(1) << "Specified config file " << argv[1] << " not found." << endl;
877 config_present = absent;
878 } else {
879 cout << "Empty configuration file." << endl;
880 ConfigFileName = argv[1];
881 config_present = empty;
882 output.close();
883 }
884 } else {
885 test.close();
886 ConfigFileName = argv[1];
887 cout << Verbose(1) << "Specified config file found, parsing ... ";
888 switch (configuration.TestSyntax(ConfigFileName, periode, mol)) {
889 case 1:
890 cout << "new syntax." << endl;
891 configuration.Load(ConfigFileName, periode, mol);
892 config_present = present;
893 break;
894 case 0:
895 cout << "old syntax." << endl;
896 configuration.LoadOld(ConfigFileName, periode, mol);
897 config_present = present;
898 break;
899 default:
900 cout << "Unknown syntax or empty, yet present file." << endl;
901 config_present = empty;
902 }
903 }
904 } else
905 config_present = absent;
906
907 // 4. parse again through options, now for those depending on elements db and config presence
908 argptr = 1;
909 do {
910 cout << "Current Command line argument: " << argv[argptr] << "." << endl;
911 if (argv[argptr][0] == '-') {
912 argptr++;
913 if ((config_present == present) || (config_present == empty)) {
914 switch(argv[argptr-1][1]) {
915 case 'p':
916 ExitFlag = 1;
917 SaveFlag = true;
918 cout << Verbose(1) << "Parsing xyz file for new atoms." << endl;
919 if (!mol->AddXYZFile(argv[argptr]))
920 cout << Verbose(2) << "File not found." << endl;
921 else {
922 cout << Verbose(2) << "File found and parsed." << endl;
923 config_present = present;
924 }
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 if ((config_present == empty) && (mol->AtomCount != 0))
939 config_present = present;
940 } else
941 cerr << Verbose(1) << "Could not find the specified element." << endl;
942 argptr+=4;
943 break;
944 default: // no match? Don't step on (this is done in next switch's default)
945 break;
946 }
947 }
948 if (config_present == present) {
949 switch(argv[argptr-1][1]) {
950 case 'D':
951 ExitFlag = 1;
952 {
953 cout << Verbose(1) << "Depth-First-Search Analysis." << endl;
954 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
955 int *MinimumRingSize = NULL;
956 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr]), configuration.GetIsAngstroem());
957 mol->CreateListOfBondsPerAtom((ofstream *)&cout);
958 Subgraphs = mol->DepthFirstSearchAnalysis((ofstream *)&cout, MinimumRingSize);
959 delete[](MinimumRingSize);
960 if (Subgraphs != NULL) {
961 while (Subgraphs->next != NULL) {
962 Subgraphs = Subgraphs->next;
963 delete(Subgraphs->previous);
964 }
965 delete(Subgraphs);
966 }
967 }
968 argptr+=1;
969 break;
970 case 'E':
971 ExitFlag = 1;
972 SaveFlag = true;
973 cout << Verbose(1) << "Changing atom " << argv[argptr] << " to element " << argv[argptr+1] << "." << endl;
974 first = mol->FindAtom(atoi(argv[argptr]));
975 first->type = periode->FindElement(atoi(argv[argptr+1]));
976 argptr+=2;
977 break;
978 case 'T':
979 ExitFlag = 1;
980 {
981 cout << Verbose(1) << "Storing temperatures in " << argv[argptr] << "." << endl;
982 ofstream *output = new ofstream(argv[argptr], ios::trunc);
983 if (!mol->OutputTemperatureFromTrajectories((ofstream *)&cout, 0, mol->MDSteps, output))
984 cout << Verbose(2) << "File could not be written." << endl;
985 else
986 cout << Verbose(2) << "File stored." << endl;
987 output->close();
988 delete(output);
989 }
990 argptr+=1;
991 break;
992 case 'L':
993 ExitFlag = 1;
994 SaveFlag = true;
995 cout << Verbose(1) << "Linear interpolation between configuration " << argv[argptr] << " and " << argv[argptr+1] << "." << endl;
996 if (!mol->LinearInterpolationBetweenConfiguration((ofstream *)&cout, atoi(argv[argptr]), atoi(argv[argptr+1]), argv[argptr+2], configuration))
997 cout << Verbose(2) << "Could not store " << argv[argptr+2] << " files." << endl;
998 else
999 cout << Verbose(2) << "Steps created and " << argv[argptr+2] << " files stored." << endl;
1000 argptr+=3;
1001 break;
1002 case 'P':
1003 ExitFlag = 1;
1004 SaveFlag = true;
1005 cout << Verbose(1) << "Parsing forces file and Verlet integrating." << endl;
1006 if (!mol->VerletForceIntegration((ofstream *)&cout, argv[argptr], configuration))
1007 cout << Verbose(2) << "File not found." << endl;
1008 else {
1009 cout << Verbose(2) << "File found and parsed." << endl;
1010 if (configuration.DoConstrainedMD)
1011 // increase source step in expectancy of a new step in the config
1012 configuration.DoConstrainedMD++;
1013 }
1014 argptr+=1;
1015 break;
1016 case 't':
1017 ExitFlag = 1;
1018 SaveFlag = true;
1019 cout << Verbose(1) << "Translating all ions to new origin." << endl;
1020 for (int i=NDIM;i--;)
1021 x.x[i] = atof(argv[argptr+i]);
1022 mol->Translate((const Vector *)&x);
1023 argptr+=3;
1024 break;
1025 case 's':
1026 ExitFlag = 1;
1027 SaveFlag = true;
1028 j = -1;
1029 cout << Verbose(1) << "Scaling all ion positions by factor." << endl;
1030 factor = new double[NDIM];
1031 factor[0] = atof(argv[argptr]);
1032 if (argc > argptr+1)
1033 argptr++;
1034 factor[1] = atof(argv[argptr]);
1035 if (argc > argptr+1)
1036 argptr++;
1037 factor[2] = atof(argv[argptr]);
1038 mol->Scale(&factor);
1039 for (int i=0;i<NDIM;i++) {
1040 j += i+1;
1041 x.x[i] = atof(argv[NDIM+i]);
1042 mol->cell_size[j]*=factor[i];
1043 }
1044 delete[](factor);
1045 argptr+=1;
1046 break;
1047 case 'b':
1048 ExitFlag = 1;
1049 SaveFlag = true;
1050 j = -1;
1051 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl;
1052 j=-1;
1053 for (int i=0;i<NDIM;i++) {
1054 j += i+1;
1055 x.x[i] = atof(argv[argptr++]);
1056 mol->cell_size[j] += x.x[i]*2.;
1057 }
1058 // center
1059 mol->CenterInBox((ofstream *)&cout, &x);
1060 // update Box of atoms by boundary
1061 mol->SetBoxDimension(&x);
1062 break;
1063 case 'c':
1064 ExitFlag = 1;
1065 SaveFlag = true;
1066 j = -1;
1067 cout << Verbose(1) << "Centering atoms in config file within given additional boundary." << endl;
1068 // make every coordinate positive
1069 mol->CenterEdge((ofstream *)&cout, &x);
1070 // update Box of atoms by boundary
1071 mol->SetBoxDimension(&x);
1072 // translate each coordinate by boundary
1073 j=-1;
1074 for (int i=0;i<NDIM;i++) {
1075 j += i+1;
1076 x.x[i] = atof(argv[argptr++]);
1077 mol->cell_size[j] += x.x[i]*2.;
1078 }
1079 mol->Translate((const Vector *)&x);
1080 break;
1081 case 'O':
1082 ExitFlag = 1;
1083 SaveFlag = true;
1084 cout << Verbose(1) << "Centering atoms in origin." << endl;
1085 mol->CenterOrigin((ofstream *)&cout, &x);
1086 mol->SetBoxDimension(&x);
1087 break;
1088 case 'r':
1089 ExitFlag = 1;
1090 SaveFlag = true;
1091 cout << Verbose(1) << "Converting config file from supposed old to new syntax." << endl;
1092 break;
1093 case 'F':
1094 case 'f':
1095 ExitFlag = 1;
1096 cout << "Fragmenting molecule with bond distance " << argv[argptr] << " angstroem, order of " << argv[argptr+1] << "." << endl;
1097 if (argc >= argptr+2) {
1098 cout << Verbose(0) << "Creating connection matrix..." << endl;
1099 start = clock();
1100 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr++]), configuration.GetIsAngstroem());
1101 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl;
1102 if (mol->first->next != mol->last) {
1103 ExitFlag = mol->FragmentMolecule((ofstream *)&cout, atoi(argv[argptr]), &configuration);
1104 }
1105 end = clock();
1106 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
1107 argptr+=1;
1108 } else {
1109 cerr << "Not enough arguments for fragmentation: -f <max. bond distance> <bond order>" << endl;
1110 }
1111 break;
1112 case 'm':
1113 ExitFlag = 1;
1114 j = atoi(argv[argptr++]);
1115 if ((j<0) || (j>1)) {
1116 cerr << Verbose(1) << "ERROR: Argument of '-m' should be either 0 for no-rotate or 1 for rotate." << endl;
1117 j = 0;
1118 }
1119 if (j) {
1120 SaveFlag = true;
1121 cout << Verbose(0) << "Converting to prinicipal axis system." << endl;
1122 } else
1123 cout << Verbose(0) << "Evaluating prinicipal axis." << endl;
1124 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)j);
1125 break;
1126 case 'o':
1127 ExitFlag = 1;
1128 SaveFlag = true;
1129 cout << Verbose(0) << "Evaluating volume of the convex envelope.";
1130 VolumeOfConvexEnvelope((ofstream *)&cout, &configuration, NULL, mol);
1131 break;
1132 case 'U':
1133 ExitFlag = 1;
1134 volume = atof(argv[argptr++]);
1135 cout << Verbose(0) << "Using " << volume << " angstrom^3 as the volume instead of convex envelope one's." << endl;
1136 case 'u':
1137 ExitFlag = 1;
1138 {
1139 double density;
1140 SaveFlag = true;
1141 cout << Verbose(0) << "Evaluating necessary cell volume for a cluster suspended in water.";
1142 density = atof(argv[argptr++]);
1143 if (density < 1.0) {
1144 cerr << Verbose(0) << "Density must be greater than 1.0g/cm^3 !" << endl;
1145 density = 1.3;
1146 }
1147// for(int i=0;i<NDIM;i++) {
1148// repetition[i] = atoi(argv[argptr++]);
1149// if (repetition[i] < 1)
1150// cerr << Verbose(0) << "ERROR: repetition value must be greater 1!" << endl;
1151// repetition[i] = 1;
1152// }
1153 PrepareClustersinWater((ofstream *)&cout, &configuration, mol, volume, density);
1154 }
1155 break;
1156 case 'd':
1157 ExitFlag = 1;
1158 SaveFlag = true;
1159 for (int axis = 1; axis <= NDIM; axis++) {
1160 int faktor = atoi(argv[argptr++]);
1161 int count;
1162 element ** Elements;
1163 Vector ** vectors;
1164 if (faktor < 1) {
1165 cerr << Verbose(0) << "ERROR: Repetition faktor mus be greater than 1!" << endl;
1166 faktor = 1;
1167 }
1168 mol->CountAtoms((ofstream *)&cout); // recount atoms
1169 if (mol->AtomCount != 0) { // if there is more than none
1170 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand
1171 Elements = new element *[count];
1172 vectors = new Vector *[count];
1173 j = 0;
1174 first = mol->start;
1175 while (first->next != mol->end) { // make a list of all atoms with coordinates and element
1176 first = first->next;
1177 Elements[j] = first->type;
1178 vectors[j] = &first->x;
1179 j++;
1180 }
1181 if (count != j)
1182 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl;
1183 x.Zero();
1184 y.Zero();
1185 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
1186 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times
1187 x.AddVector(&y); // per factor one cell width further
1188 for (int k=count;k--;) { // go through every atom of the original cell
1189 first = new atom(); // create a new body
1190 first->x.CopyVector(vectors[k]); // use coordinate of original atom
1191 first->x.AddVector(&x); // translate the coordinates
1192 first->type = Elements[k]; // insert original element
1193 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)
1194 }
1195 }
1196 // free memory
1197 delete[](Elements);
1198 delete[](vectors);
1199 // correct cell size
1200 if (axis < 0) { // if sign was negative, we have to translate everything
1201 x.Zero();
1202 x.AddVector(&y);
1203 x.Scale(-(faktor-1));
1204 mol->Translate(&x);
1205 }
1206 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor;
1207 }
1208 }
1209 break;
1210 default: // no match? Step on
1211 if ((argptr < argc) && (argv[argptr][0] != '-')) // if it started with a '-' we've already made a step!
1212 argptr++;
1213 break;
1214 }
1215 }
1216 } else argptr++;
1217 } while (argptr < argc);
1218 if (SaveFlag)
1219 SaveConfig(ConfigFileName, &configuration, periode, mol);
1220 if ((ExitFlag >= 1)) {
1221 delete(mol);
1222 delete(periode);
1223 return (ExitFlag);
1224 }
1225 } else { // no arguments, hence scan the elements db
1226 if (periode->LoadPeriodentafel(PathToDatabases))
1227 cout << Verbose(0) << "Element list loaded successfully." << endl;
1228 else
1229 cout << Verbose(0) << "Element list loading failed." << endl;
1230 configuration.RetrieveConfigPathAndName("main_pcp_linux");
1231 }
1232 return(0);
1233};
1234
1235/********************************************** Main routine **************************************/
1236
1237int main(int argc, char **argv)
1238{
1239 periodentafel *periode = new periodentafel; // and a period table of all elements
1240 molecule *mol = new molecule(periode); // first we need an empty molecule
1241 config configuration;
1242 double tmp1;
1243 double bond, min_bond;
1244 atom *first, *second;
1245 char choice; // menu choice char
1246 Vector x,y,z,n; // coordinates for absolute point in cell volume
1247 double *factor; // unit factor if desired
1248 bool valid; // flag if input was valid or not
1249 ifstream test;
1250 ofstream output;
1251 string line;
1252 char filename[MAXSTRINGSIZE];
1253 char *ConfigFileName = NULL;
1254 char *ElementsFileName = NULL;
1255 int Z;
1256 int j, axis, count, faktor;
1257 int *MinimumRingSize = NULL;
1258 MoleculeLeafClass *Subgraphs = NULL;
1259 clock_t start,end;
1260 element **Elements;
1261 Vector **vectors;
1262
1263 // =========================== PARSE COMMAND LINE OPTIONS ====================================
1264 j = ParseCommandLineOptions(argc, argv, mol, periode, configuration, ConfigFileName, ElementsFileName);
1265 if (j == 1) return 0; // just for -v and -h options
1266 if (j) return j; // something went wrong
1267
1268 // General stuff
1269 if (mol->cell_size[0] == 0.) {
1270 cout << Verbose(0) << "enter lower triadiagonal form of basis matrix" << endl << endl;
1271 for (int i=0;i<6;i++) {
1272 cout << Verbose(1) << "Cell size" << i << ": ";
1273 cin >> mol->cell_size[i];
1274 }
1275 }
1276
1277 // =========================== START INTERACTIVE SESSION ====================================
1278
1279 // now the main construction loop
1280 cout << Verbose(0) << endl << "Now comes the real construction..." << endl;
1281 do {
1282 cout << Verbose(0) << endl << endl;
1283 cout << Verbose(0) << "============Element list=======================" << endl;
1284 mol->Checkout((ofstream *)&cout);
1285 cout << Verbose(0) << "============Atom list==========================" << endl;
1286 mol->Output((ofstream *)&cout);
1287 cout << Verbose(0) << "============Menu===============================" << endl;
1288 cout << Verbose(0) << "a - add an atom" << endl;
1289 cout << Verbose(0) << "r - remove an atom" << endl;
1290 cout << Verbose(0) << "b - scale a bond between atoms" << endl;
1291 cout << Verbose(0) << "u - change an atoms element" << endl;
1292 cout << Verbose(0) << "l - measure lengths, angles, ... for an atom" << endl;
1293 cout << Verbose(0) << "-----------------------------------------------" << endl;
1294 cout << Verbose(0) << "p - Parse xyz file" << endl;
1295 cout << Verbose(0) << "e - edit the current configuration" << endl;
1296 cout << Verbose(0) << "o - create connection matrix" << endl;
1297 cout << Verbose(0) << "f - fragment molecule many-body bond order style" << endl;
1298 cout << Verbose(0) << "-----------------------------------------------" << endl;
1299 cout << Verbose(0) << "d - duplicate molecule/periodic cell" << endl;
1300 cout << Verbose(0) << "i - realign molecule" << endl;
1301 cout << Verbose(0) << "m - mirror all molecules" << endl;
1302 cout << Verbose(0) << "t - translate molecule by vector" << endl;
1303 cout << Verbose(0) << "c - scale by unit transformation" << endl;
1304 cout << Verbose(0) << "g - center atoms in box" << endl;
1305 cout << Verbose(0) << "-----------------------------------------------" << endl;
1306 cout << Verbose(0) << "s - save current setup to config file" << endl;
1307 cout << Verbose(0) << "T - call the current test routine" << endl;
1308 cout << Verbose(0) << "q - quit" << endl;
1309 cout << Verbose(0) << "===============================================" << endl;
1310 cout << Verbose(0) << "Input: ";
1311 cin >> choice;
1312
1313 switch (choice) {
1314 default:
1315 case 'a': // add atom
1316 AddAtoms(periode, mol);
1317 choice = 'a';
1318 break;
1319
1320 case 'b': // scale a bond
1321 cout << Verbose(0) << "Scaling bond length between two atoms." << endl;
1322 first = mol->AskAtom("Enter first (fixed) atom: ");
1323 second = mol->AskAtom("Enter second (shifting) atom: ");
1324 min_bond = 0.;
1325 for (int i=NDIM;i--;)
1326 min_bond += (first->x.x[i]-second->x.x[i])*(first->x.x[i] - second->x.x[i]);
1327 min_bond = sqrt(min_bond);
1328 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;
1329 cout << Verbose(0) << "Enter new bond length [a.u.]: ";
1330 cin >> bond;
1331 for (int i=NDIM;i--;) {
1332 second->x.x[i] -= (second->x.x[i]-first->x.x[i])/min_bond*(min_bond-bond);
1333 }
1334 //cout << Verbose(0) << "New coordinates of Atom " << second->nr << " are: ";
1335 //second->Output(second->type->No, 1, (ofstream *)&cout);
1336 break;
1337
1338 case 'c': // unit scaling of the metric
1339 cout << Verbose(0) << "Angstroem -> Bohrradius: 1.8897261\t\tBohrradius -> Angstroem: 0.52917721" << endl;
1340 cout << Verbose(0) << "Enter three factors: ";
1341 factor = new double[NDIM];
1342 cin >> factor[0];
1343 cin >> factor[1];
1344 cin >> factor[2];
1345 valid = true;
1346 mol->Scale(&factor);
1347 delete[](factor);
1348 break;
1349
1350 case 'd': // duplicate the periodic cell along a given axis, given times
1351 cout << Verbose(0) << "State the axis [(+-)123]: ";
1352 cin >> axis;
1353 cout << Verbose(0) << "State the factor: ";
1354 cin >> faktor;
1355
1356 mol->CountAtoms((ofstream *)&cout); // recount atoms
1357 if (mol->AtomCount != 0) { // if there is more than none
1358 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand
1359 Elements = new element *[count];
1360 vectors = new Vector *[count];
1361 j = 0;
1362 first = mol->start;
1363 while (first->next != mol->end) { // make a list of all atoms with coordinates and element
1364 first = first->next;
1365 Elements[j] = first->type;
1366 vectors[j] = &first->x;
1367 j++;
1368 }
1369 if (count != j)
1370 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl;
1371 x.Zero();
1372 y.Zero();
1373 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
1374 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times
1375 x.AddVector(&y); // per factor one cell width further
1376 for (int k=count;k--;) { // go through every atom of the original cell
1377 first = new atom(); // create a new body
1378 first->x.CopyVector(vectors[k]); // use coordinate of original atom
1379 first->x.AddVector(&x); // translate the coordinates
1380 first->type = Elements[k]; // insert original element
1381 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)
1382 }
1383 }
1384 if (mol->first->next != mol->last) // if connect matrix is present already, redo it
1385 mol->CreateAdjacencyList((ofstream *)&cout, mol->BondDistance, configuration.GetIsAngstroem());
1386 // free memory
1387 delete[](Elements);
1388 delete[](vectors);
1389 // correct cell size
1390 if (axis < 0) { // if sign was negative, we have to translate everything
1391 x.Zero();
1392 x.AddVector(&y);
1393 x.Scale(-(faktor-1));
1394 mol->Translate(&x);
1395 }
1396 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor;
1397 }
1398 break;
1399
1400 case 'e': // edit each field of the configuration
1401 configuration.Edit(mol);
1402 break;
1403
1404 case 'f':
1405 FragmentAtoms(mol, &configuration);
1406 break;
1407
1408 case 'g': // center the atoms
1409 CenterAtoms(mol);
1410 break;
1411
1412 case 'i': // align all atoms
1413 AlignAtoms(periode, mol);
1414 break;
1415
1416 case 'l': // measure distances or angles
1417 MeasureAtoms(periode, mol, &configuration);
1418 break;
1419
1420 case 'm': // mirror atoms along a given axis
1421 MirrorAtoms(mol);
1422 break;
1423
1424 case 'o': // create the connection matrix
1425 cout << Verbose(0) << "What's the maximum bond distance: ";
1426 cin >> tmp1;
1427 start = clock();
1428 mol->CreateAdjacencyList((ofstream *)&cout, tmp1, configuration.GetIsAngstroem());
1429 //mol->CreateListOfBondsPerAtom((ofstream *)&cout);
1430 Subgraphs = mol->DepthFirstSearchAnalysis((ofstream *)&cout, MinimumRingSize);
1431 while (Subgraphs->next != NULL) {
1432 Subgraphs = Subgraphs->next;
1433 delete(Subgraphs->previous);
1434 }
1435 delete(Subgraphs); // we don't need the list here, so free everything
1436 delete[](MinimumRingSize);
1437 Subgraphs = NULL;
1438 end = clock();
1439 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl;
1440 break;
1441
1442 case 'p': // parse and XYZ file
1443 cout << Verbose(0) << "Format should be XYZ with: ShorthandOfElement\tX\tY\tZ" << endl;
1444 do {
1445 cout << Verbose(0) << "Enter file name: ";
1446 cin >> filename;
1447 } while (!mol->AddXYZFile(filename));
1448 break;
1449
1450 case 'q': // quit
1451 break;
1452
1453 case 'r': // remove atom
1454 RemoveAtoms(mol);
1455 break;
1456
1457 case 's': // save to config file
1458 SaveConfig(ConfigFileName, &configuration, periode, mol);
1459 break;
1460
1461 case 't': // translate all atoms
1462 cout << Verbose(0) << "Enter translation vector." << endl;
1463 x.AskPosition(mol->cell_size,0);
1464 mol->Translate((const Vector *)&x);
1465 break;
1466
1467 case 'T':
1468 testroutine(mol);
1469 break;
1470
1471 case 'u': // change an atom's element
1472 first = NULL;
1473 do {
1474 cout << Verbose(0) << "Change the element of which atom: ";
1475 cin >> Z;
1476 } while ((first = mol->FindAtom(Z)) == NULL);
1477 cout << Verbose(0) << "New element by atomic number Z: ";
1478 cin >> Z;
1479 first->type = periode->FindElement(Z);
1480 cout << Verbose(0) << "Atom " << first->nr << "'s element is " << first->type->name << "." << endl;
1481 break;
1482 };
1483 } while (choice != 'q');
1484
1485 // save element data base
1486 if (periode->StorePeriodentafel(ElementsFileName)) //ElementsFileName
1487 cout << Verbose(0) << "Saving of elements.db successful." << endl;
1488 else
1489 cout << Verbose(0) << "Saving of elements.db failed." << endl;
1490
1491 // Free all
1492 if (Subgraphs != NULL) { // free disconnected subgraph list of DFS analysis was performed
1493 while (Subgraphs->next != NULL) {
1494 Subgraphs = Subgraphs->next;
1495 delete(Subgraphs->previous);
1496 }
1497 delete(Subgraphs);
1498 }
1499 delete(mol);
1500 delete(periode);
1501 return (0);
1502}
1503
1504/********************************************** E N D **************************************************/
Note: See TracBrowser for help on using the repository browser.