source: src/builder.cpp@ d2a294

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 d2a294 was db942e, checked in by Frederik Heber <heber@…>, 17 years ago

HUGE REWRITE to allow for adaptive increase of the bond order, first working commit

Lots of code was thrown out:
-BottomUp, TopDown and GetAtomicFragments
-TEFactors are now used as "CreationCounters", i.e. the count how often a fragment as been created (ideal would be only once)
-ReduceToUniqueOnes and stuff all thrown out, since they are out-dated since use of hash table
Other changes:
-CreateListofUniqueFragments renamed to PowerSetGenerator
-PowerSetGenerator goes not over all reachable roots, but one given by calling function FragmentBOSSANOVA
-FragmentBOSSANOVA loops over all possible root sites and hands this over to PowerSetGenerator
-by the virtue of the hash table it is not important anymore whether created keysets are unique or not, as this is recognized in log(n). Hence, the label < label is not important anymore (and not applicable in an adaptive scheme with old, parsed keysets and unknown labels) (THIS IS HOWEVER NOT DONE YET!)
The setup is then as follows:

  1. FragmentMolecule
    1. parses adjacency, keysets and orderatsite files
    2. performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
    3. a RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energy contribution", and that's why this consciously not done in the following loop)
    4. in a loop over all subgraphs

d1. calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
d2. creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)

  1. combines the generated molecule lists from all subgraphs
  2. saves to disk: fragment configs, adjacency, orderatsite, keyset files
  1. FragmentBOSSANOVA
    1. constructs a complete keyset of the molecule
    2. In a loop over all possible roots from the given rootstack

b1. increases order of root site
b2. calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
b3. for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset as the restricted one and each site in the set as the root)
b4. these are merged into a fragment list of keysets

  1. All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
  1. PowerSetGenerator
    1. initialises UniqueFragments structure
    2. fills edge list via BFS
    3. creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as root distance, the edge set, its dimension and the current suborder
    4. Free'ing structure
  2. SPFragmentGenerator (nothing much has changed here)
    1. loops over every possible combination (2dimension of edge set)

a1. inserts current set, if there's still space left

a11. yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root distance+1
a12. no: stores fragment into keyset list by calling InsertFragmentIntoGraph

a2. removes all items added into the snake stack (in UniqueFragments structure) added during level (root distance) and current set

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