- Timestamp:
- Jul 23, 2009, 1:53:01 PM (15 years ago)
- Branches:
- 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
- Children:
- 51c910
- Parents:
- a5b2c3a
- Location:
- src
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
src/builder.cpp
ra5b2c3a r375b458 15 15 * \section about About the Program 16 16 * 17 * 18 * 19 * 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 20 * 21 * 22 * 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 23 * 24 24 * \section install Installation 25 25 * 26 * 27 * 28 * 29 * 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 30 * 31 * 32 * 33 * 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 34 * 35 35 * \section run Running 36 36 * 37 * 37 * The program can be executed by running: ./molecuilder 38 38 * 39 * 40 * 41 * 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 42 * 43 43 * \section ref References 44 44 * 45 * 45 * For the special configuration file format, see the documentation of pcp. 46 46 * 47 47 */ … … 63 63 static void AddAtoms(periodentafel *periode, molecule *mol) 64 64 { 65 66 67 Vector x,y,z,n;// coordinates for absolute point in cell volume68 69 char choice;// menu choice char70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 65 atom *first, *second, *third, *fourth; 66 Vector **atoms; 67 Vector x,y,z,n; // coordinates for absolute point in cell volume 68 double a,b,c; 69 char choice; // menu choice char 70 bool valid; 71 72 cout << Verbose(0) << "===========ADD ATOM============================" << endl; 73 cout << Verbose(0) << " a - state absolute coordinates of atom" << endl; 74 cout << Verbose(0) << " b - state relative coordinates of atom wrt to reference point" << endl; 75 cout << Verbose(0) << " c - state relative coordinates of atom wrt to already placed atom" << endl; 76 cout << Verbose(0) << " d - state two atoms, two angles and a distance" << endl; 77 cout << Verbose(0) << " e - least square distance position to a set of atoms" << endl; 78 cout << Verbose(0) << "all else - go back" << endl; 79 cout << Verbose(0) << "===============================================" << endl; 80 cout << Verbose(0) << "Note: Specifiy angles in degrees not multiples of Pi!" << endl; 81 cout << Verbose(0) << "INPUT: "; 82 cin >> choice; 83 84 switch (choice) { 85 85 default: 86 86 cout << Verbose(0) << "Not a valid choice." << endl; 87 87 break; 88 88 case 'a': // absolute coordinates of atom 89 89 cout << Verbose(0) << "Enter absolute coordinates." << endl; 90 90 first = new atom; 91 91 first->x.AskPosition(mol->cell_size, false); 92 first->type = periode->AskElement(); 93 mol->AddAtom(first); 94 95 96 92 first->type = periode->AskElement(); // give type 93 mol->AddAtom(first); // add to molecule 94 break; 95 96 case 'b': // relative coordinates of atom wrt to reference point 97 97 first = new atom; 98 98 valid = true; … … 106 106 cout << Verbose(0) << "\n"; 107 107 } while (!(valid = mol->CheckBounds((const Vector *)&first->x))); 108 first->type = periode->AskElement(); 109 mol->AddAtom(first); 110 111 112 108 first->type = periode->AskElement(); // give type 109 mol->AddAtom(first); // add to molecule 110 break; 111 112 case 'c': // relative coordinates of atom wrt to already placed atom 113 113 first = new atom; 114 114 valid = true; … … 122 122 } 123 123 } while (!(valid = mol->CheckBounds((const Vector *)&first->x))); 124 first->type = periode->AskElement(); 125 mol->AddAtom(first); 124 first->type = periode->AskElement(); // give type 125 mol->AddAtom(first); // add to molecule 126 126 break; 127 127 … … 224 224 cout << Verbose(0) << endl; 225 225 } while (!(valid = mol->CheckBounds((const Vector *)&first->x))); 226 first->type = periode->AskElement(); 227 mol->AddAtom(first); 228 229 230 226 first->type = periode->AskElement(); // give type 227 mol->AddAtom(first); // add to molecule 228 break; 229 230 case 'e': // least square distance position to a set of atoms 231 231 first = new atom; 232 232 atoms = new (Vector*[128]); … … 248 248 249 249 first->x.Output((ofstream *)&cout); 250 first->type = periode->AskElement(); 251 mol->AddAtom(first); 250 first->type = periode->AskElement(); // give type 251 mol->AddAtom(first); // add to molecule 252 252 } else { 253 253 delete first; 254 254 cout << Verbose(0) << "Please enter at least two vectors!\n"; 255 255 } 256 257 256 break; 257 }; 258 258 }; 259 259 … … 263 263 static void CenterAtoms(molecule *mol) 264 264 { 265 266 char choice;// menu choice char267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 mol->CenterEdge((ofstream *)&cout, &x);// make every coordinate positive297 298 299 300 301 mol->SetBoxDimension(&helper);// update Box of atoms by boundary302 303 304 305 306 307 308 309 310 311 312 313 314 265 Vector x, y, helper; 266 char choice; // menu choice char 267 268 cout << Verbose(0) << "===========CENTER ATOMS=========================" << endl; 269 cout << Verbose(0) << " a - on origin" << endl; 270 cout << Verbose(0) << " b - on center of gravity" << endl; 271 cout << Verbose(0) << " c - within box with additional boundary" << endl; 272 cout << Verbose(0) << " d - within given simulation box" << endl; 273 cout << Verbose(0) << "all else - go back" << endl; 274 cout << Verbose(0) << "===============================================" << endl; 275 cout << Verbose(0) << "INPUT: "; 276 cin >> choice; 277 278 switch (choice) { 279 default: 280 cout << Verbose(0) << "Not a valid choice." << endl; 281 break; 282 case 'a': 283 cout << Verbose(0) << "Centering atoms in config file on origin." << endl; 284 mol->CenterOrigin((ofstream *)&cout, &x); 285 break; 286 case 'b': 287 cout << Verbose(0) << "Centering atoms in config file on center of gravity." << endl; 288 mol->CenterGravity((ofstream *)&cout, &x); 289 break; 290 case 'c': 291 cout << Verbose(0) << "Centering atoms in config file within given additional boundary." << endl; 292 for (int i=0;i<NDIM;i++) { 293 cout << Verbose(0) << "Enter axis " << i << " boundary: "; 294 cin >> y.x[i]; 295 } 296 mol->CenterEdge((ofstream *)&cout, &x); // make every coordinate positive 297 mol->Translate(&y); // translate by boundary 298 helper.CopyVector(&y); 299 helper.Scale(2.); 300 helper.AddVector(&x); 301 mol->SetBoxDimension(&helper); // update Box of atoms by boundary 302 break; 303 case 'd': 304 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl; 305 for (int i=0;i<NDIM;i++) { 306 cout << Verbose(0) << "Enter axis " << i << " boundary: "; 307 cin >> x.x[i]; 308 } 309 // center 310 mol->CenterInBox((ofstream *)&cout, &x); 311 // update Box of atoms by boundary 312 mol->SetBoxDimension(&x); 313 break; 314 } 315 315 }; 316 316 … … 321 321 static void AlignAtoms(periodentafel *periode, molecule *mol) 322 322 { 323 324 325 char choice;// menu choice char326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 323 atom *first, *second, *third; 324 Vector x,n; 325 char choice; // menu choice char 326 327 cout << Verbose(0) << "===========ALIGN ATOMS=========================" << endl; 328 cout << Verbose(0) << " a - state three atoms defining align plane" << endl; 329 cout << Verbose(0) << " b - state alignment vector" << endl; 330 cout << Verbose(0) << " c - state two atoms in alignment direction" << endl; 331 cout << Verbose(0) << " d - align automatically by least square fit" << endl; 332 cout << Verbose(0) << "all else - go back" << endl; 333 cout << Verbose(0) << "===============================================" << endl; 334 cout << Verbose(0) << "INPUT: "; 335 cin >> choice; 336 337 switch (choice) { 338 default: 339 case 'a': // three atoms defining mirror plane 340 first = mol->AskAtom("Enter first atom: "); 341 second = mol->AskAtom("Enter second atom: "); 342 third = mol->AskAtom("Enter third atom: "); 343 344 n.MakeNormalVector((const Vector *)&first->x,(const Vector *)&second->x,(const Vector *)&third->x); 345 break; 346 case 'b': // normal vector of mirror plane 347 cout << Verbose(0) << "Enter normal vector of mirror plane." << endl; 348 n.AskPosition(mol->cell_size,0); 349 n.Normalize(); 350 break; 351 case 'c': // three atoms defining mirror plane 352 first = mol->AskAtom("Enter first atom: "); 353 second = mol->AskAtom("Enter second atom: "); 354 355 n.CopyVector((const Vector *)&first->x); 356 n.SubtractVector((const Vector *)&second->x); 357 n.Normalize(); 358 break; 359 case 'd': 360 char shorthand[4]; 361 Vector a; 362 struct lsq_params param; 363 do { 364 fprintf(stdout, "Enter the element of atoms to be chosen: "); 365 fscanf(stdin, "%3s", shorthand); 366 } while ((param.type = periode->FindElement(shorthand)) == NULL); 367 cout << Verbose(0) << "Element is " << param.type->name << endl; 368 mol->GetAlignvector(¶m); 369 for (int i=NDIM;i--;) { 370 x.x[i] = gsl_vector_get(param.x,i); 371 n.x[i] = gsl_vector_get(param.x,i+NDIM); 372 } 373 gsl_vector_free(param.x); 374 cout << Verbose(0) << "Offset vector: "; 375 x.Output((ofstream *)&cout); 376 cout << Verbose(0) << endl; 377 n.Normalize(); 378 break; 379 }; 380 cout << Verbose(0) << "Alignment vector: "; 381 n.Output((ofstream *)&cout); 382 cout << Verbose(0) << endl; 383 mol->Align(&n); 384 384 }; 385 385 … … 389 389 static void MirrorAtoms(molecule *mol) 390 390 { 391 392 393 char choice;// menu choice char394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 391 atom *first, *second, *third; 392 Vector n; 393 char choice; // menu choice char 394 395 cout << Verbose(0) << "===========MIRROR ATOMS=========================" << endl; 396 cout << Verbose(0) << " a - state three atoms defining mirror plane" << endl; 397 cout << Verbose(0) << " b - state normal vector of mirror plane" << endl; 398 cout << Verbose(0) << " c - state two atoms in normal direction" << endl; 399 cout << Verbose(0) << "all else - go back" << endl; 400 cout << Verbose(0) << "===============================================" << endl; 401 cout << Verbose(0) << "INPUT: "; 402 cin >> choice; 403 404 switch (choice) { 405 default: 406 case 'a': // three atoms defining mirror plane 407 first = mol->AskAtom("Enter first atom: "); 408 second = mol->AskAtom("Enter second atom: "); 409 third = mol->AskAtom("Enter third atom: "); 410 411 n.MakeNormalVector((const Vector *)&first->x,(const Vector *)&second->x,(const Vector *)&third->x); 412 break; 413 case 'b': // normal vector of mirror plane 414 cout << Verbose(0) << "Enter normal vector of mirror plane." << endl; 415 n.AskPosition(mol->cell_size,0); 416 n.Normalize(); 417 break; 418 case 'c': // three atoms defining mirror plane 419 first = mol->AskAtom("Enter first atom: "); 420 second = mol->AskAtom("Enter second atom: "); 421 422 n.CopyVector((const Vector *)&first->x); 423 n.SubtractVector((const Vector *)&second->x); 424 n.Normalize(); 425 break; 426 }; 427 cout << Verbose(0) << "Normal vector: "; 428 n.Output((ofstream *)&cout); 429 cout << Verbose(0) << endl; 430 mol->Mirror((const Vector *)&n); 431 431 }; 432 432 … … 436 436 static void RemoveAtoms(molecule *mol) 437 437 { 438 atom *first, *second, *third; 439 int axis; 440 double tmp1, tmp2; 441 char choice; // menu choice char 442 443 cout << Verbose(0) << "===========REMOVE ATOMS=========================" << endl; 444 cout << Verbose(0) << " a - state atom for removal by number" << endl; 445 cout << Verbose(0) << " b - keep only in radius around atom" << endl; 446 cout << Verbose(0) << " c - remove this with one axis greater value" << endl; 447 cout << Verbose(0) << "all else - go back" << endl; 448 cout << Verbose(0) << "===============================================" << endl; 449 cout << Verbose(0) << "INPUT: "; 450 cin >> choice; 451 452 switch (choice) { 453 default: 454 case 'a': 455 if (mol->RemoveAtom(mol->AskAtom("Enter number of atom within molecule: "))) 456 cout << Verbose(1) << "Atom removed." << endl; 457 else 458 cout << Verbose(1) << "Atom not found." << endl; 459 break; 460 case 'b': 461 third = mol->AskAtom("Enter number of atom as reference point: "); 462 cout << Verbose(0) << "Enter radius: "; 463 cin >> tmp1; 464 first = mol->start; 465 second = first->next; 466 while(second != mol->end) { 467 first = second; 468 second = first->next; 469 if (first->x.DistanceSquared((const Vector *)&third->x) > tmp1*tmp1) // distance to first above radius ... 470 mol->RemoveAtom(first); 471 } 472 break; 473 case 'c': 474 cout << Verbose(0) << "Which axis is it: "; 475 cin >> axis; 476 cout << Verbose(0) << "Lower boundary: "; 477 cin >> tmp1; 478 cout << Verbose(0) << "Upper boundary: "; 479 cin >> tmp2; 480 first = mol->start; 438 atom *first, *second, *third; 439 int axis; 440 double tmp1, tmp2; 441 char choice; // menu choice char 442 443 cout << Verbose(0) << "===========REMOVE ATOMS=========================" << endl; 444 cout << Verbose(0) << " a - state atom for removal by number" << endl; 445 cout << Verbose(0) << " b - keep only in radius around atom" << endl; 446 cout << Verbose(0) << " c - remove this with one axis greater value" << endl; 447 cout << Verbose(0) << "all else - go back" << endl; 448 cout << Verbose(0) << "===============================================" << endl; 449 cout << Verbose(0) << "INPUT: "; 450 cin >> choice; 451 452 switch (choice) { 453 default: 454 case 'a': 455 if (mol->RemoveAtom(mol->AskAtom("Enter number of atom within molecule: "))) 456 cout << Verbose(1) << "Atom removed." << endl; 457 else 458 cout << Verbose(1) << "Atom not found." << endl; 459 break; 460 case 'b': 461 third = mol->AskAtom("Enter number of atom as reference point: "); 462 cout << Verbose(0) << "Enter radius: "; 463 cin >> tmp1; 464 first = mol->start; 481 465 second = first->next; 482 466 while(second != mol->end) { 483 467 first = second; 484 468 second = first->next; 485 if ((first->x.x[axis] < tmp1) || (first->x.x[axis] > tmp2)) {// out of boundary ... 486 //cout << "Atom " << *first << " with " << first->x.x[axis] << " on axis " << axis << " is out of bounds [" << tmp1 << "," << tmp2 << "]." << endl; 487 mol->RemoveAtom(first); 488 } 489 } 490 break; 491 }; 492 //mol->Output((ofstream *)&cout); 493 choice = 'r'; 469 if (first->x.DistanceSquared((const Vector *)&third->x) > tmp1*tmp1) // distance to first above radius ... 470 mol->RemoveAtom(first); 471 } 472 break; 473 case 'c': 474 cout << Verbose(0) << "Which axis is it: "; 475 cin >> axis; 476 cout << Verbose(0) << "Lower boundary: "; 477 cin >> tmp1; 478 cout << Verbose(0) << "Upper boundary: "; 479 cin >> tmp2; 480 first = mol->start; 481 second = first->next; 482 while(second != mol->end) { 483 first = second; 484 second = first->next; 485 if ((first->x.x[axis] < tmp1) || (first->x.x[axis] > tmp2)) {// out of boundary ... 486 //cout << "Atom " << *first << " with " << first->x.x[axis] << " on axis " << axis << " is out of bounds [" << tmp1 << "," << tmp2 << "]." << endl; 487 mol->RemoveAtom(first); 488 } 489 } 490 break; 491 }; 492 //mol->Output((ofstream *)&cout); 493 choice = 'r'; 494 494 }; 495 495 … … 500 500 static void MeasureAtoms(periodentafel *periode, molecule *mol, config *configuration) 501 501 { 502 503 504 505 506 char choice;// menu choice char507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 third= mol->AskAtom("Enter last atom: ");565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 502 atom *first, *second, *third; 503 Vector x,y; 504 double min[256], tmp1, tmp2, tmp3; 505 int Z; 506 char choice; // menu choice char 507 508 cout << Verbose(0) << "===========MEASURE ATOMS=========================" << endl; 509 cout << Verbose(0) << " a - calculate bond length between one atom and all others" << endl; 510 cout << Verbose(0) << " b - calculate bond length between two atoms" << endl; 511 cout << Verbose(0) << " c - calculate bond angle" << endl; 512 cout << Verbose(0) << " d - calculate principal axis of the system" << endl; 513 cout << Verbose(0) << " e - calculate volume of the convex envelope" << endl; 514 cout << Verbose(0) << " f - calculate temperature from current velocity" << endl; 515 cout << Verbose(0) << " g - output all temperatures per step from velocities" << endl; 516 cout << Verbose(0) << "all else - go back" << endl; 517 cout << Verbose(0) << "===============================================" << endl; 518 cout << Verbose(0) << "INPUT: "; 519 cin >> choice; 520 521 switch(choice) { 522 default: 523 cout << Verbose(1) << "Not a valid choice." << endl; 524 break; 525 case 'a': 526 first = mol->AskAtom("Enter first atom: "); 527 for (int i=MAX_ELEMENTS;i--;) 528 min[i] = 0.; 529 530 second = mol->start; 531 while ((second->next != mol->end)) { 532 second = second->next; // advance 533 Z = second->type->Z; 534 tmp1 = 0.; 535 if (first != second) { 536 x.CopyVector((const Vector *)&first->x); 537 x.SubtractVector((const Vector *)&second->x); 538 tmp1 = x.Norm(); 539 } 540 if ((tmp1 != 0.) && ((min[Z] == 0.) || (tmp1 < min[Z]))) min[Z] = tmp1; 541 //cout << Verbose(0) << "Bond length between Atom " << first->nr << " and " << second->nr << ": " << tmp1 << " a.u." << endl; 542 } 543 for (int i=MAX_ELEMENTS;i--;) 544 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; 545 break; 546 547 case 'b': 548 first = mol->AskAtom("Enter first atom: "); 549 second = mol->AskAtom("Enter second atom: "); 550 for (int i=NDIM;i--;) 551 min[i] = 0.; 552 x.CopyVector((const Vector *)&first->x); 553 x.SubtractVector((const Vector *)&second->x); 554 tmp1 = x.Norm(); 555 cout << Verbose(1) << "Distance vector is "; 556 x.Output((ofstream *)&cout); 557 cout << "." << endl << "Norm of distance is " << tmp1 << "." << endl; 558 break; 559 560 case 'c': 561 cout << Verbose(0) << "Evaluating bond angle between three - first, central, last - atoms." << endl; 562 first = mol->AskAtom("Enter first atom: "); 563 second = mol->AskAtom("Enter central atom: "); 564 third = mol->AskAtom("Enter last atom: "); 565 tmp1 = tmp2 = tmp3 = 0.; 566 x.CopyVector((const Vector *)&first->x); 567 x.SubtractVector((const Vector *)&second->x); 568 y.CopyVector((const Vector *)&third->x); 569 y.SubtractVector((const Vector *)&second->x); 570 cout << Verbose(0) << "Bond angle between first atom Nr." << first->nr << ", central atom Nr." << second->nr << " and last atom Nr." << third->nr << ": "; 571 cout << Verbose(0) << (acos(x.ScalarProduct((const Vector *)&y)/(y.Norm()*x.Norm()))/M_PI*180.) << " degrees" << endl; 572 break; 573 case 'd': 574 cout << Verbose(0) << "Evaluating prinicipal axis." << endl; 575 cout << Verbose(0) << "Shall we rotate? [0/1]: "; 576 cin >> Z; 577 if ((Z >=0) && (Z <=1)) 578 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)Z); 579 else 580 mol->PrincipalAxisSystem((ofstream *)&cout, false); 581 break; 582 case 'e': 583 cout << Verbose(0) << "Evaluating volume of the convex envelope."; 584 VolumeOfConvexEnvelope((ofstream *)&cout, NULL, configuration, NULL, mol); 585 break; 586 case 'f': 587 mol->OutputTemperatureFromTrajectories((ofstream *)&cout, mol->MDSteps-1, mol->MDSteps, (ofstream *)&cout); 588 break; 589 case 'g': 590 { 591 char filename[255]; 592 cout << "Please enter filename: " << endl; 593 cin >> filename; 594 cout << Verbose(1) << "Storing temperatures in " << filename << "." << endl; 595 ofstream *output = new ofstream(filename, ios::trunc); 596 if (!mol->OutputTemperatureFromTrajectories((ofstream *)&cout, 0, mol->MDSteps, output)) 597 cout << Verbose(2) << "File could not be written." << endl; 598 else 599 cout << Verbose(2) << "File stored." << endl; 600 output->close(); 601 delete(output); 602 } 603 break; 604 } 605 605 }; 606 606 … … 611 611 static void FragmentAtoms(molecule *mol, config *configuration) 612 612 { 613 614 615 616 617 618 619 if (mol->first->next != mol->last) {// there are bonds620 621 622 623 624 625 613 int Order1; 614 clock_t start, end; 615 616 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl; 617 cout << Verbose(0) << "What's the desired bond order: "; 618 cin >> Order1; 619 if (mol->first->next != mol->last) { // there are bonds 620 start = clock(); 621 mol->FragmentMolecule((ofstream *)&cout, Order1, configuration); 622 end = clock(); 623 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl; 624 } else 625 cout << Verbose(0) << "Connection matrix has not yet been generated!" << endl; 626 626 }; 627 627 … … 1053 1053 static void testroutine(MoleculeListClass *molecules) 1054 1054 { 1055 1056 1055 // the current test routine checks the functionality of the KeySet&Graph concept: 1056 // We want to have a multiindex (the KeySet) describing a unique subgraph 1057 1057 int i, comp, counter=0; 1058 1058 … … 1067 1067 atom *Walker = mol->start; 1068 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 while (A !=Subgraphs.end()) {1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1069 // generate some KeySets 1070 cout << "Generating KeySets." << endl; 1071 KeySet TestSets[mol->AtomCount+1]; 1072 i=1; 1073 while (Walker->next != mol->end) { 1074 Walker = Walker->next; 1075 for (int j=0;j<i;j++) { 1076 TestSets[j].insert(Walker->nr); 1077 } 1078 i++; 1079 } 1080 cout << "Testing insertion of already present item in KeySets." << endl; 1081 KeySetTestPair test; 1082 test = TestSets[mol->AtomCount-1].insert(Walker->nr); 1083 if (test.second) { 1084 cout << Verbose(1) << "Insertion worked?!" << endl; 1085 } else { 1086 cout << Verbose(1) << "Insertion rejected: Present object is " << (*test.first) << "." << endl; 1087 } 1088 TestSets[mol->AtomCount].insert(mol->end->previous->nr); 1089 TestSets[mol->AtomCount].insert(mol->end->previous->previous->previous->nr); 1090 1091 // constructing Graph structure 1092 cout << "Generating Subgraph class." << endl; 1093 Graph Subgraphs; 1094 1095 // insert KeySets into Subgraphs 1096 cout << "Inserting KeySets into Subgraph class." << endl; 1097 for (int j=0;j<mol->AtomCount;j++) { 1098 Subgraphs.insert(GraphPair (TestSets[j],pair<int, double>(counter++, 1.))); 1099 } 1100 cout << "Testing insertion of already present item in Subgraph." << endl; 1101 GraphTestPair test2; 1102 test2 = Subgraphs.insert(GraphPair (TestSets[mol->AtomCount],pair<int, double>(counter++, 1.))); 1103 if (test2.second) { 1104 cout << Verbose(1) << "Insertion worked?!" << endl; 1105 } else { 1106 cout << Verbose(1) << "Insertion rejected: Present object is " << (*(test2.first)).second.first << "." << endl; 1107 } 1108 1109 // show graphs 1110 cout << "Showing Subgraph's contents, checking that it's sorted." << endl; 1111 Graph::iterator A = Subgraphs.begin(); 1112 while (A != Subgraphs.end()) { 1113 cout << (*A).second.first << ": "; 1114 KeySet::iterator key = (*A).first.begin(); 1115 comp = -1; 1116 while (key != (*A).first.end()) { 1117 if ((*key) > comp) 1118 cout << (*key) << " "; 1119 else 1120 cout << (*key) << "! "; 1121 comp = (*key); 1122 key++; 1123 } 1124 cout << endl; 1125 A++; 1126 } 1127 delete(mol); 1128 1128 }; 1129 1129 … … 1136 1136 static void SaveConfig(char *ConfigFileName, config *configuration, periodentafel *periode, MoleculeListClass *molecules) 1137 1137 { 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1138 char filename[MAXSTRINGSIZE]; 1139 ofstream output; 1140 molecule *mol = new molecule(periode); 1141 1142 // merge all molecules in MoleculeListClass into this molecule 1143 int N = molecules->ListOfMolecules.size(); 1144 int *src = new int(N); 1145 N=0; 1146 for (MoleculeList::iterator ListRunner = molecules->ListOfMolecules.begin(); ListRunner != molecules->ListOfMolecules.end(); ListRunner++) 1147 src[N++] = (*ListRunner)->IndexNr; 1148 molecules->SimpleMultiAdd(mol, src, N); 1149 1150 cout << Verbose(0) << "Storing configuration ... " << endl; 1151 // get correct valence orbitals 1152 mol->CalculateOrbitals(*configuration); 1153 configuration->InitMaxMinStopStep = configuration->MaxMinStopStep = configuration->MaxPsiDouble; 1154 strcpy(filename, ConfigFileName); 1155 if (ConfigFileName != NULL) { // test the file name 1156 output.open(ConfigFileName, ios::trunc); 1157 } else if (strlen(configuration->configname) != 0) { 1158 strcpy(filename, configuration->configname); 1159 output.open(configuration->configname, ios::trunc); 1160 } else { 1161 strcpy(filename, DEFAULTCONFIG); 1162 output.open(DEFAULTCONFIG, ios::trunc); 1163 } 1164 output.close(); 1165 output.clear(); 1166 cout << Verbose(0) << "Saving of config file "; 1167 if (configuration->Save(filename, periode, mol)) 1168 cout << "successful." << endl; 1169 else 1170 cout << "failed." << endl; 1171 1172 // and save to xyz file 1173 if (ConfigFileName != NULL) { 1174 strcpy(filename, ConfigFileName); 1175 strcat(filename, ".xyz"); 1176 output.open(filename, ios::trunc); 1177 } 1178 if (output == NULL) { 1179 strcpy(filename,"main_pcp_linux"); 1180 strcat(filename, ".xyz"); 1181 output.open(filename, ios::trunc); 1182 } 1183 cout << Verbose(0) << "Saving of XYZ file "; 1184 if (mol->MDSteps <= 1) { 1185 if (mol->OutputXYZ(&output)) 1186 cout << "successful." << endl; 1187 else 1188 cout << "failed." << endl; 1189 } else { 1190 if (mol->OutputTrajectoriesXYZ(&output)) 1191 cout << "successful." << endl; 1192 else 1193 cout << "failed." << endl; 1194 } 1195 output.close(); 1196 output.clear(); 1197 1198 // and save as MPQC configuration 1199 if (ConfigFileName != NULL) 1200 strcpy(filename, ConfigFileName); 1201 if (output == NULL) 1202 strcpy(filename,"main_pcp_linux"); 1203 cout << Verbose(0) << "Saving as mpqc input "; 1204 if (configuration->SaveMPQC(filename, mol)) 1205 cout << "done." << endl; 1206 else 1207 cout << "failed." << endl; 1208 1209 if (!strcmp(configuration->configpath, configuration->GetDefaultPath())) { 1210 cerr << "WARNING: config is found under different path then stated in config file::defaultpath!" << endl; 1211 } 1212 delete(mol); 1213 1213 }; 1214 1214 … … 1225 1225 static int ParseCommandLineOptions(int argc, char **argv, MoleculeListClass *&molecules, periodentafel *&periode, config& configuration, char *&ConfigFileName, char *&PathToDatabases) 1226 1226 { 1227 Vector x,y,z,n;// coordinates for absolute point in cell volume1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 default:// no match? Step on1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 mol->AddAtom(first);// add to molecule1405 1406 1407 1408 1409 1410 1411 1412 default:// no match? Don't step on (this is done in next switch's default)1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 MoleculeLeafClass *Subgraphs = NULL;// list of subgraphs from DFS analysis1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 Subgraphs->next->FillBondStructureFromReference((ofstream *)&cout, mol, (FragmentCounter = 0), ListOfLocalAtoms, false);// we want to keep the created ListOfLocalAtoms1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 LinkedCell LCList(mol, atof(argv[argptr]));// \NOTE not twice the radius??1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1227 Vector x,y,z,n; // coordinates for absolute point in cell volume 1228 double *factor; // unit factor if desired 1229 ifstream test; 1230 ofstream output; 1231 string line; 1232 atom *first; 1233 bool SaveFlag = false; 1234 int ExitFlag = 0; 1235 int j; 1236 double volume = 0.; 1237 enum ConfigStatus config_present = absent; 1238 clock_t start,end; 1239 int argptr; 1240 PathToDatabases = LocalPath; 1241 1242 // simply create a new molecule, wherein the config file is loaded and the manipulation takes place 1243 molecule *mol = new molecule(periode); 1244 molecules->insert(mol); 1245 1246 if (argc > 1) { // config file specified as option 1247 // 1. : Parse options that just set variables or print help 1248 argptr = 1; 1249 do { 1250 if (argv[argptr][0] == '-') { 1251 cout << Verbose(0) << "Recognized command line argument: " << argv[argptr][1] << ".\n"; 1252 argptr++; 1253 switch(argv[argptr-1][1]) { 1254 case 'h': 1255 case 'H': 1256 case '?': 1257 cout << "MoleCuilder suite" << endl << "==================" << endl << endl; 1258 cout << "Usage: " << argv[0] << "[config file] [-{acefpsthH?vfrp}] [further arguments]" << endl; 1259 cout << "or simply " << argv[0] << " without arguments for interactive session." << endl; 1260 cout << "\t-a Z x1 x2 x3\tAdd new atom of element Z at coordinates (x1,x2,x3)." << endl; 1261 cout << "\t-A <source>\tCreate adjacency list from bonds parsed from 'dbond'-style file." <<endl; 1262 cout << "\t-b x1 x2 x3\tCenter atoms in domain with given edge lengths of (x1,x2,x3)." << endl; 1263 cout << "\t-B <basis>\tSetting basis to store to MPQC config files." << endl; 1264 cout << "\t-c x1 x2 x3\tCenter atoms in domain with a minimum distance to boundary of (x1,x2,x3)." << endl; 1265 cout << "\t-D <bond distance>\tDepth-First-Search Analysis of the molecule, giving cycles and tree/back edges." << endl; 1266 cout << "\t-O\tCenter atoms in origin." << endl; 1267 cout << "\t-d x1 x2 x3\tDuplicate cell along each axis by given factor." << endl; 1268 cout << "\t-e <file>\tSets the databases path to be parsed (default: ./)." << endl; 1269 cout << "\t-E <id> <Z>\tChange atom <id>'s element to <Z>, <id> begins at 0." << endl; 1270 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; 1271 cout << "\t-h/-H/-?\tGive this help screen." << endl; 1272 cout << "\t-m <0/1>\tCalculate (0)/ Align in(1) PAS with greatest EV along z axis." << endl; 1273 cout << "\t-n\tFast parsing (i.e. no trajectories are looked for)." << endl; 1274 cout << "\t-N <radius> <file>\tGet non-convex-envelope." << endl; 1275 cout << "\t-o <out>\tGet volume of the convex envelope (and store to tecplot file)." << endl; 1276 cout << "\t-p <file>\tParse given xyz file and create raw config file from it." << endl; 1277 cout << "\t-P <file>\tParse given forces file and append as an MD step to config file via Verlet." << endl; 1278 cout << "\t-r\t\tConvert file from an old pcp syntax." << endl; 1279 cout << "\t-R\t\tRemove all atoms out of sphere around a given one." << endl; 1280 cout << "\t-t x1 x2 x3\tTranslate all atoms by this vector (x1,x2,x3)." << endl; 1281 cout << "\t-T <file> Store temperatures from the config file in <file>." << endl; 1282 cout << "\t-s x1 x2 x3\tScale all atom coordinates by this vector (x1,x2,x3)." << endl; 1283 cout << "\t-u rho\tsuspend in water solution and output necessary cell lengths, average density rho and repetition." << endl; 1284 cout << "\t-v/-V\t\tGives version information." << endl; 1285 cout << "Note: config files must not begin with '-' !" << endl; 1286 delete(mol); 1287 delete(periode); 1288 return (1); 1289 break; 1290 case 'v': 1291 case 'V': 1292 cout << argv[0] << " " << VERSIONSTRING << endl; 1293 cout << "Build your own molecule position set." << endl; 1294 delete(mol); 1295 delete(periode); 1296 return (1); 1297 break; 1298 case 'e': 1299 if ((argptr >= argc) || (argv[argptr][0] == '-')) { 1300 cerr << "Not enough or invalid arguments for specifying element db: -e <db file>" << endl; 1301 } else { 1302 cout << "Using " << argv[argptr] << " as elements database." << endl; 1303 PathToDatabases = argv[argptr]; 1304 argptr+=1; 1305 } 1306 break; 1307 case 'n': 1308 cout << "I won't parse trajectories." << endl; 1309 configuration.FastParsing = true; 1310 break; 1311 default: // no match? Step on 1312 argptr++; 1313 break; 1314 } 1315 } else 1316 argptr++; 1317 } while (argptr < argc); 1318 1319 // 2. Parse the element database 1320 if (periode->LoadPeriodentafel(PathToDatabases)) { 1321 cout << Verbose(0) << "Element list loaded successfully." << endl; 1322 //periode->Output((ofstream *)&cout); 1323 } else { 1324 cout << Verbose(0) << "Element list loading failed." << endl; 1325 return 1; 1326 } 1327 // 3. Find config file name and parse if possible 1328 if (argv[1][0] != '-') { 1329 cout << Verbose(0) << "Config file given." << endl; 1330 test.open(argv[1], ios::in); 1331 if (test == NULL) { 1332 //return (1); 1333 output.open(argv[1], ios::out); 1334 if (output == NULL) { 1335 cout << Verbose(1) << "Specified config file " << argv[1] << " not found." << endl; 1336 config_present = absent; 1337 } else { 1338 cout << "Empty configuration file." << endl; 1339 ConfigFileName = argv[1]; 1340 config_present = empty; 1341 output.close(); 1342 } 1343 } else { 1344 test.close(); 1345 ConfigFileName = argv[1]; 1346 cout << Verbose(1) << "Specified config file found, parsing ... "; 1347 switch (configuration.TestSyntax(ConfigFileName, periode, mol)) { 1348 case 1: 1349 cout << "new syntax." << endl; 1350 configuration.Load(ConfigFileName, periode, mol); 1351 config_present = present; 1352 break; 1353 case 0: 1354 cout << "old syntax." << endl; 1355 configuration.LoadOld(ConfigFileName, periode, mol); 1356 config_present = present; 1357 break; 1358 default: 1359 cout << "Unknown syntax or empty, yet present file." << endl; 1360 config_present = empty; 1361 } 1362 } 1363 } else 1364 config_present = absent; 1365 // 4. parse again through options, now for those depending on elements db and config presence 1366 argptr = 1; 1367 do { 1368 cout << "Current Command line argument: " << argv[argptr] << "." << endl; 1369 if (argv[argptr][0] == '-') { 1370 argptr++; 1371 if ((config_present == present) || (config_present == empty)) { 1372 switch(argv[argptr-1][1]) { 1373 case 'p': 1374 ExitFlag = 1; 1375 if ((argptr >= argc) || (argv[argptr][0] == '-')) { 1376 ExitFlag = 255; 1377 cerr << "Not enough arguments for parsing: -p <xyz file>" << endl; 1378 } else { 1379 SaveFlag = true; 1380 cout << Verbose(1) << "Parsing xyz file for new atoms." << endl; 1381 if (!mol->AddXYZFile(argv[argptr])) 1382 cout << Verbose(2) << "File not found." << endl; 1383 else { 1384 cout << Verbose(2) << "File found and parsed." << endl; 1385 config_present = present; 1386 } 1387 } 1388 break; 1389 case 'a': 1390 ExitFlag = 1; 1391 if ((argptr >= argc) || (argv[argptr][0] == '-') || (!IsValidNumber(argv[argptr+1]))) { 1392 ExitFlag = 255; 1393 cerr << "Not enough or invalid arguments for adding atom: -a <element> <x> <y> <z>" << endl; 1394 } else { 1395 SaveFlag = true; 1396 cout << Verbose(1) << "Adding new atom with element " << argv[argptr] << " at (" << argv[argptr+1] << "," << argv[argptr+2] << "," << argv[argptr+3] << "), "; 1397 first = new atom; 1398 first->type = periode->FindElement(atoi(argv[argptr])); 1399 if (first->type != NULL) 1400 cout << Verbose(2) << "found element " << first->type->name << endl; 1401 for (int i=NDIM;i--;) 1402 first->x.x[i] = atof(argv[argptr+1+i]); 1403 if (first->type != NULL) { 1404 mol->AddAtom(first); // add to molecule 1405 if ((config_present == empty) && (mol->AtomCount != 0)) 1406 config_present = present; 1407 } else 1408 cerr << Verbose(1) << "Could not find the specified element." << endl; 1409 argptr+=4; 1410 } 1411 break; 1412 default: // no match? Don't step on (this is done in next switch's default) 1413 break; 1414 } 1415 } 1416 if (config_present == present) { 1417 switch(argv[argptr-1][1]) { 1418 case 'B': 1419 if ((argptr >= argc) || (argv[argptr][0] == '-')) { 1420 ExitFlag = 255; 1421 cerr << "Not enough or invalid arguments given for setting MPQC basis: -B <basis name>" << endl; 1422 } else { 1423 configuration.basis = argv[argptr]; 1424 cout << Verbose(1) << "Setting MPQC basis to " << configuration.basis << "." << endl; 1425 argptr+=1; 1426 } 1427 break; 1428 case 'D': 1429 ExitFlag = 1; 1430 { 1431 cout << Verbose(1) << "Depth-First-Search Analysis." << endl; 1432 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis 1433 int *MinimumRingSize = new int[mol->AtomCount]; 1434 atom ***ListOfLocalAtoms = NULL; 1435 int FragmentCounter = 0; 1436 class StackClass<bond *> *BackEdgeStack = NULL; 1437 class StackClass<bond *> *LocalBackEdgeStack = NULL; 1438 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr]), configuration.GetIsAngstroem()); 1439 mol->CreateListOfBondsPerAtom((ofstream *)&cout); 1440 Subgraphs = mol->DepthFirstSearchAnalysis((ofstream *)&cout, BackEdgeStack); 1441 if (Subgraphs != NULL) { 1442 Subgraphs->next->FillBondStructureFromReference((ofstream *)&cout, mol, (FragmentCounter = 0), ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms 1443 while (Subgraphs->next != NULL) { 1444 Subgraphs = Subgraphs->next; 1445 LocalBackEdgeStack = new StackClass<bond *> (Subgraphs->Leaf->BondCount); 1446 Subgraphs->Leaf->PickLocalBackEdges((ofstream *)&cout, ListOfLocalAtoms[FragmentCounter++], BackEdgeStack, LocalBackEdgeStack); 1447 Subgraphs->Leaf->CyclicStructureAnalysis((ofstream *)&cout, BackEdgeStack, MinimumRingSize); 1448 delete(LocalBackEdgeStack); 1449 delete(Subgraphs->previous); 1450 } 1451 delete(Subgraphs); 1452 for (int i=0;i<FragmentCounter;i++) 1453 Free((void **)&ListOfLocalAtoms[FragmentCounter], "ParseCommandLineOptions: **ListOfLocalAtoms[]"); 1454 Free((void **)&ListOfLocalAtoms, "ParseCommandLineOptions: ***ListOfLocalAtoms"); 1455 } 1456 delete(BackEdgeStack); 1457 delete[](MinimumRingSize); 1458 } 1459 //argptr+=1; 1460 break; 1461 case 'E': 1462 ExitFlag = 1; 1463 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (argv[argptr+1][0] == '-')) { 1464 ExitFlag = 255; 1465 cerr << "Not enough or invalid arguments given for changing element: -E <atom nr.> <element>" << endl; 1466 } else { 1467 SaveFlag = true; 1468 cout << Verbose(1) << "Changing atom " << argv[argptr] << " to element " << argv[argptr+1] << "." << endl; 1469 first = mol->FindAtom(atoi(argv[argptr])); 1470 first->type = periode->FindElement(atoi(argv[argptr+1])); 1471 argptr+=2; 1472 } 1473 break; 1474 case 'A': 1475 ExitFlag = 1; 1476 if ((argptr >= argc) || (argv[argptr][0] == '-')) { 1477 ExitFlag =255; 1478 cerr << "Missing source file for bonds in molecule: -A <bond sourcefile>" << endl; 1479 } else { 1480 cout << "Parsing bonds from " << argv[argptr] << "." << endl; 1481 ifstream *input = new ifstream(argv[argptr]); 1482 mol->CreateAdjacencyList2((ofstream *)&cout, input); 1483 input->close(); 1484 argptr+=1; 1485 } 1486 break; 1487 case 'N': 1488 ExitFlag = 1; 1489 if ((argptr+1 >= argc) || (argv[argptr+1][0] == '-')){ 1490 ExitFlag = 255; 1491 cerr << "Not enough or invalid arguments given for non-convex envelope: -o <radius> <tecplot output file>" << endl; 1492 } else { 1493 class Tesselation T; 1494 int N = 15; 1495 int number = 100; 1496 string filename(argv[argptr+1]); 1497 filename.append(".csv"); 1498 cout << Verbose(0) << "Evaluating non-convex envelope."; 1499 cout << Verbose(1) << "Using rolling ball of radius " << atof(argv[argptr]) << " and storing tecplot data in " << argv[argptr+1] << "." << endl; 1500 LinkedCell LCList(mol, atof(argv[argptr])); // \NOTE not twice the radius?? 1501 Find_non_convex_border((ofstream *)&cout, mol, &T, &LCList, argv[argptr+1], atof(argv[argptr])); 1502 //FindDistributionOfEllipsoids((ofstream *)&cout, &T, &LCList, N, number, filename.c_str()); 1503 argptr+=2; 1504 } 1505 break; 1506 case 'T': 1507 ExitFlag = 1; 1508 if ((argptr >= argc) || (argv[argptr][0] == '-')) { 1509 ExitFlag = 255; 1510 cerr << "Not enough or invalid arguments given for storing tempature: -T <temperature file>" << endl; 1511 } else { 1512 cout << Verbose(1) << "Storing temperatures in " << argv[argptr] << "." << endl; 1513 ofstream *output = new ofstream(argv[argptr], ios::trunc); 1514 if (!mol->OutputTemperatureFromTrajectories((ofstream *)&cout, 0, mol->MDSteps, output)) 1515 cout << Verbose(2) << "File could not be written." << endl; 1516 else 1517 cout << Verbose(2) << "File stored." << endl; 1518 output->close(); 1519 delete(output); 1520 argptr+=1; 1521 } 1522 break; 1523 case 'P': 1524 ExitFlag = 1; 1525 if ((argptr >= argc) || (argv[argptr][0] == '-')) { 1526 ExitFlag = 255; 1527 cerr << "Not enough or invalid arguments given for parsing and integrating forces: -P <forces file>" << endl; 1528 } else { 1529 SaveFlag = true; 1530 cout << Verbose(1) << "Parsing forces file and Verlet integrating." << endl; 1531 if (!mol->VerletForceIntegration(argv[argptr], configuration.Deltat, configuration.GetIsAngstroem())) 1532 cout << Verbose(2) << "File not found." << endl; 1533 else 1534 cout << Verbose(2) << "File found and parsed." << endl; 1535 argptr+=1; 1536 } 1537 break; 1538 1538 case 'R': 1539 1539 ExitFlag = 1; … … 1561 1561 } 1562 1562 break; 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 // 1733 // 1734 // 1735 // 1736 // 1737 // 1738 PrepareClustersinWater((ofstream *)&cout, &configuration, mol, volume, density);// if volume == 0, will calculate from ConvexEnvelope1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 mol->CountAtoms((ofstream *)&cout);// recount atoms1758 if (mol->AtomCount != 0) {// if there is more than none1759 count = mol->AtomCount;// is changed becausing of adding, thus has to be stored away beforehand1760 1761 1762 1763 1764 while (first->next != mol->end) {// make a list of all atoms with coordinates and element1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 for (int i=1;i<faktor;i++) {// then add this list with respective translation factor times1776 1777 1778 1779 first->x.CopyVector(vectors[k]);// use coordinate of original atom1780 first->x.AddVector(&x);// translate the coordinates1781 first->type = Elements[k];// insert original element1782 mol->AddAtom(first);// and add to the molecule (which increments ElementsInMolecule, AtomCount, ...)1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 default:// no match? Step on1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 } else {// no arguments, hence scan the elements db1816 1817 1818 1819 1820 1821 1822 1563 case 't': 1564 ExitFlag = 1; 1565 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) { 1566 ExitFlag = 255; 1567 cerr << "Not enough or invalid arguments given for translation: -t <x> <y> <z>" << endl; 1568 } else { 1569 ExitFlag = 1; 1570 SaveFlag = true; 1571 cout << Verbose(1) << "Translating all ions to new origin." << endl; 1572 for (int i=NDIM;i--;) 1573 x.x[i] = atof(argv[argptr+i]); 1574 mol->Translate((const Vector *)&x); 1575 argptr+=3; 1576 } 1577 break; 1578 case 's': 1579 ExitFlag = 1; 1580 if ((argptr >= argc) || (!IsValidNumber(argv[argptr])) ) { 1581 ExitFlag = 255; 1582 cerr << "Not enough or invalid arguments given for scaling: -s <factor/[factor_x]> [factor_y] [factor_z]" << endl; 1583 } else { 1584 SaveFlag = true; 1585 j = -1; 1586 cout << Verbose(1) << "Scaling all ion positions by factor." << endl; 1587 factor = new double[NDIM]; 1588 factor[0] = atof(argv[argptr]); 1589 if ((argptr < argc) && (IsValidNumber(argv[argptr]))) 1590 argptr++; 1591 factor[1] = atof(argv[argptr]); 1592 if ((argptr < argc) && (IsValidNumber(argv[argptr]))) 1593 argptr++; 1594 factor[2] = atof(argv[argptr]); 1595 mol->Scale(&factor); 1596 for (int i=0;i<NDIM;i++) { 1597 j += i+1; 1598 x.x[i] = atof(argv[NDIM+i]); 1599 mol->cell_size[j]*=factor[i]; 1600 } 1601 delete[](factor); 1602 argptr+=1; 1603 } 1604 break; 1605 case 'b': 1606 ExitFlag = 1; 1607 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) { 1608 ExitFlag = 255; 1609 cerr << "Not enough or invalid arguments given for centering in box: -b <length_x> <length_y> <length_z>" << endl; 1610 } else { 1611 SaveFlag = true; 1612 j = -1; 1613 cout << Verbose(1) << "Centering atoms in config file within given simulation box." << endl; 1614 j=-1; 1615 for (int i=0;i<NDIM;i++) { 1616 j += i+1; 1617 x.x[i] = atof(argv[argptr++]); 1618 mol->cell_size[j] += x.x[i]*2.; 1619 } 1620 // center 1621 mol->CenterInBox((ofstream *)&cout, &x); 1622 // update Box of atoms by boundary 1623 mol->SetBoxDimension(&x); 1624 } 1625 break; 1626 case 'c': 1627 ExitFlag = 1; 1628 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) { 1629 ExitFlag = 255; 1630 cerr << "Not enough or invalid arguments given for centering with boundary: -c <boundary_x> <boundary_y> <boundary_z>" << endl; 1631 } else { 1632 SaveFlag = true; 1633 j = -1; 1634 cout << Verbose(1) << "Centering atoms in config file within given additional boundary." << endl; 1635 // make every coordinate positive 1636 mol->CenterEdge((ofstream *)&cout, &x); 1637 // update Box of atoms by boundary 1638 mol->SetBoxDimension(&x); 1639 // translate each coordinate by boundary 1640 j=-1; 1641 for (int i=0;i<NDIM;i++) { 1642 j += i+1; 1643 x.x[i] = atof(argv[argptr++]); 1644 mol->cell_size[j] += x.x[i]*2.; 1645 } 1646 mol->Translate((const Vector *)&x); 1647 } 1648 break; 1649 case 'O': 1650 ExitFlag = 1; 1651 SaveFlag = true; 1652 cout << Verbose(1) << "Centering atoms in origin." << endl; 1653 mol->CenterOrigin((ofstream *)&cout, &x); 1654 mol->SetBoxDimension(&x); 1655 break; 1656 case 'r': 1657 ExitFlag = 1; 1658 SaveFlag = true; 1659 cout << Verbose(1) << "Converting config file from supposed old to new syntax." << endl; 1660 break; 1661 case 'F': 1662 case 'f': 1663 ExitFlag = 1; 1664 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1]))) { 1665 ExitFlag = 255; 1666 cerr << "Not enough or invalid arguments for fragmentation: -f <max. bond distance> <bond order>" << endl; 1667 } else { 1668 cout << "Fragmenting molecule with bond distance " << argv[argptr] << " angstroem, order of " << argv[argptr+1] << "." << endl; 1669 cout << Verbose(0) << "Creating connection matrix..." << endl; 1670 start = clock(); 1671 mol->CreateAdjacencyList((ofstream *)&cout, atof(argv[argptr++]), configuration.GetIsAngstroem()); 1672 cout << Verbose(0) << "Fragmenting molecule with current connection matrix ..." << endl; 1673 if (mol->first->next != mol->last) { 1674 ExitFlag = mol->FragmentMolecule((ofstream *)&cout, atoi(argv[argptr]), &configuration); 1675 } 1676 end = clock(); 1677 cout << Verbose(0) << "Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s." << endl; 1678 argptr+=2; 1679 } 1680 break; 1681 case 'm': 1682 ExitFlag = 1; 1683 j = atoi(argv[argptr++]); 1684 if ((j<0) || (j>1)) { 1685 cerr << Verbose(1) << "ERROR: Argument of '-m' should be either 0 for no-rotate or 1 for rotate." << endl; 1686 j = 0; 1687 } 1688 if (j) { 1689 SaveFlag = true; 1690 cout << Verbose(0) << "Converting to prinicipal axis system." << endl; 1691 } else 1692 cout << Verbose(0) << "Evaluating prinicipal axis." << endl; 1693 mol->PrincipalAxisSystem((ofstream *)&cout, (bool)j); 1694 break; 1695 case 'o': 1696 ExitFlag = 1; 1697 if ((argptr >= argc) || (argv[argptr][0] == '-')){ 1698 ExitFlag = 255; 1699 cerr << "Not enough or invalid arguments given for convex envelope: -o <tecplot output file>" << endl; 1700 } else { 1701 cout << Verbose(0) << "Evaluating volume of the convex envelope."; 1702 cout << Verbose(1) << "Storing tecplot data in " << argv[argptr] << "." << endl; 1703 VolumeOfConvexEnvelope((ofstream *)&cout, argv[argptr], &configuration, NULL, mol); 1704 argptr+=1; 1705 } 1706 break; 1707 case 'U': 1708 ExitFlag = 1; 1709 if ((argptr+1 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) ) { 1710 ExitFlag = 255; 1711 cerr << "Not enough or invalid arguments given for suspension with specified volume: -U <volume> <density>" << endl; 1712 volume = -1; // for case 'u': don't print error again 1713 } else { 1714 volume = atof(argv[argptr++]); 1715 cout << Verbose(0) << "Using " << volume << " angstrom^3 as the volume instead of convex envelope one's." << endl; 1716 } 1717 case 'u': 1718 ExitFlag = 1; 1719 if ((argptr >= argc) || (!IsValidNumber(argv[argptr])) ) { 1720 if (volume != -1) 1721 ExitFlag = 255; 1722 cerr << "Not enough arguments given for suspension: -u <density>" << endl; 1723 } else { 1724 double density; 1725 SaveFlag = true; 1726 cout << Verbose(0) << "Evaluating necessary cell volume for a cluster suspended in water."; 1727 density = atof(argv[argptr++]); 1728 if (density < 1.0) { 1729 cerr << Verbose(0) << "Density must be greater than 1.0g/cm^3 !" << endl; 1730 density = 1.3; 1731 } 1732 // for(int i=0;i<NDIM;i++) { 1733 // repetition[i] = atoi(argv[argptr++]); 1734 // if (repetition[i] < 1) 1735 // cerr << Verbose(0) << "ERROR: repetition value must be greater 1!" << endl; 1736 // repetition[i] = 1; 1737 // } 1738 PrepareClustersinWater((ofstream *)&cout, &configuration, mol, volume, density); // if volume == 0, will calculate from ConvexEnvelope 1739 } 1740 break; 1741 case 'd': 1742 ExitFlag = 1; 1743 if ((argptr+2 >= argc) || (!IsValidNumber(argv[argptr])) || (!IsValidNumber(argv[argptr+1])) || (!IsValidNumber(argv[argptr+2])) ) { 1744 ExitFlag = 255; 1745 cerr << "Not enough or invalid arguments given for repeating cells: -d <repeat_x> <repeat_y> <repeat_z>" << endl; 1746 } else { 1747 SaveFlag = true; 1748 for (int axis = 1; axis <= NDIM; axis++) { 1749 int faktor = atoi(argv[argptr++]); 1750 int count; 1751 element ** Elements; 1752 Vector ** vectors; 1753 if (faktor < 1) { 1754 cerr << Verbose(0) << "ERROR: Repetition faktor mus be greater than 1!" << endl; 1755 faktor = 1; 1756 } 1757 mol->CountAtoms((ofstream *)&cout); // recount atoms 1758 if (mol->AtomCount != 0) { // if there is more than none 1759 count = mol->AtomCount; // is changed becausing of adding, thus has to be stored away beforehand 1760 Elements = new element *[count]; 1761 vectors = new Vector *[count]; 1762 j = 0; 1763 first = mol->start; 1764 while (first->next != mol->end) { // make a list of all atoms with coordinates and element 1765 first = first->next; 1766 Elements[j] = first->type; 1767 vectors[j] = &first->x; 1768 j++; 1769 } 1770 if (count != j) 1771 cout << Verbose(0) << "ERROR: AtomCount " << count << " is not equal to number of atoms in molecule " << j << "!" << endl; 1772 x.Zero(); 1773 y.Zero(); 1774 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 1775 for (int i=1;i<faktor;i++) { // then add this list with respective translation factor times 1776 x.AddVector(&y); // per factor one cell width further 1777 for (int k=count;k--;) { // go through every atom of the original cell 1778 first = new atom(); // create a new body 1779 first->x.CopyVector(vectors[k]); // use coordinate of original atom 1780 first->x.AddVector(&x); // translate the coordinates 1781 first->type = Elements[k]; // insert original element 1782 mol->AddAtom(first); // and add to the molecule (which increments ElementsInMolecule, AtomCount, ...) 1783 } 1784 } 1785 // free memory 1786 delete[](Elements); 1787 delete[](vectors); 1788 // correct cell size 1789 if (axis < 0) { // if sign was negative, we have to translate everything 1790 x.Zero(); 1791 x.AddVector(&y); 1792 x.Scale(-(faktor-1)); 1793 mol->Translate(&x); 1794 } 1795 mol->cell_size[(abs(axis) == 2) ? 2 : ((abs(axis) == 3) ? 5 : 0)] *= faktor; 1796 } 1797 } 1798 } 1799 break; 1800 default: // no match? Step on 1801 if ((argptr < argc) && (argv[argptr][0] != '-')) // if it started with a '-' we've already made a step! 1802 argptr++; 1803 break; 1804 } 1805 } 1806 } else argptr++; 1807 } while (argptr < argc); 1808 if (SaveFlag) 1809 SaveConfig(ConfigFileName, &configuration, periode, molecules); 1810 if ((ExitFlag >= 1)) { 1811 delete(mol); 1812 delete(periode); 1813 return (ExitFlag); 1814 } 1815 } else { // no arguments, hence scan the elements db 1816 if (periode->LoadPeriodentafel(PathToDatabases)) 1817 cout << Verbose(0) << "Element list loaded successfully." << endl; 1818 else 1819 cout << Verbose(0) << "Element list loading failed." << endl; 1820 configuration.RetrieveConfigPathAndName("main_pcp_linux"); 1821 } 1822 return(0); 1823 1823 }; 1824 1824 … … 1827 1827 int main(int argc, char **argv) 1828 1828 { 1829 1830 1831 1832 1833 1834 1835 char choice;// menu choice char1836 Vector x,y,z,n;// coordinates for absolute point in cell volume1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 if (j) return j;// something went wrong1850 1851 1852 1829 periodentafel *periode = new periodentafel; // and a period table of all elements 1830 MoleculeListClass *molecules = new MoleculeListClass; // list of all molecules 1831 molecule *mol = NULL; 1832 config configuration; 1833 double tmp1; 1834 atom *first, *second; 1835 char choice; // menu choice char 1836 Vector x,y,z,n; // coordinates for absolute point in cell volume 1837 bool valid; // flag if input was valid or not 1838 ifstream test; 1839 ofstream output; 1840 string line; 1841 char *ConfigFileName = NULL; 1842 char *ElementsFileName = NULL; 1843 int Z; 1844 int j, axis, count, faktor; 1845 1846 // =========================== PARSE COMMAND LINE OPTIONS ==================================== 1847 j = ParseCommandLineOptions(argc, argv, molecules, periode, configuration, ConfigFileName, ElementsFileName); 1848 if (j == 1) return 0; // just for -v and -h options 1849 if (j) return j; // something went wrong 1850 1851 // General stuff 1852 if (molecules->ListOfMolecules.size() == 0) { 1853 1853 mol = new molecule(periode); 1854 1854 if (mol->cell_size[0] == 0.) { … … 1860 1860 } 1861 1861 molecules->insert(mol); 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1862 } 1863 1864 // =========================== START INTERACTIVE SESSION ==================================== 1865 1866 // now the main construction loop 1867 cout << Verbose(0) << endl << "Now comes the real construction..." << endl; 1868 do { 1869 cout << Verbose(0) << endl << endl; 1870 cout << Verbose(0) << "============Molecule list=======================" << endl; 1871 molecules->Enumerate((ofstream *)&cout); 1872 cout << Verbose(0) << "============Menu===============================" << endl; 1873 1873 cout << Verbose(0) << "a - set molecule (in)active" << endl; 1874 1874 cout << Verbose(0) << "e - edit new molecules" << endl; … … 1886 1886 cin >> choice; 1887 1887 1888 1889 1888 switch (choice) { 1889 case 'a': // (in)activate molecule 1890 1890 { 1891 1891 cout << "Enter index of molecule: "; … … 1897 1897 (*ListRunner)->ActiveFlag = !(*ListRunner)->ActiveFlag; 1898 1898 } 1899 1900 1901 1902 1903 1899 break; 1900 1901 case 'c': // edit each field of the configuration 1902 configuration.Edit(); 1903 break; 1904 1904 1905 1905 case 'e': // create molecule … … 1919 1919 break; 1920 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1921 case 'q': // quit 1922 break; 1923 1924 case 's': // save to config file 1925 SaveConfig(ConfigFileName, &configuration, periode, molecules); 1926 break; 1927 1928 case 'T': 1929 testroutine(molecules); 1930 break; 1931 1932 default: 1933 break; 1934 }; 1935 } while (choice != 'q'); 1936 1937 // save element data base 1938 if (periode->StorePeriodentafel(ElementsFileName)) //ElementsFileName 1939 cout << Verbose(0) << "Saving of elements.db successful." << endl; 1940 else 1941 cout << Verbose(0) << "Saving of elements.db failed." << endl; 1942 1943 delete(molecules); 1944 delete(periode); 1945 return (0); 1946 1946 } 1947 1947 -
src/molecules.cpp
ra5b2c3a r375b458 16 16 double LSQ (const gsl_vector * x, void * params) 17 17 { 18 19 20 21 22 23 24 25 26 27 28 18 double sum = 0.; 19 struct LSQ_params *par = (struct LSQ_params *)params; 20 Vector **vectors = par->vectors; 21 int num = par->num; 22 23 for (int i=num;i--;) { 24 for(int j=NDIM;j--;) 25 sum += (gsl_vector_get(x,j) - (vectors[i])->x[j])*(gsl_vector_get(x,j) - (vectors[i])->x[j]); 26 } 27 28 return sum; 29 29 }; 30 30 … … 36 36 molecule::molecule(periodentafel *teil) 37 37 { 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 38 // init atom chain list 39 start = new atom; 40 end = new atom; 41 start->father = NULL; 42 end->father = NULL; 43 link(start,end); 44 // init bond chain list 45 first = new bond(start, end, 1, -1); 46 last = new bond(start, end, 1, -1); 47 link(first,last); 48 // other stuff 49 MDSteps = 0; 50 last_atom = 0; 51 elemente = teil; 52 AtomCount = 0; 53 BondCount = 0; 54 NoNonBonds = 0; 55 NoNonHydrogen = 0; 56 NoCyclicBonds = 0; 57 ListOfBondsPerAtom = NULL; 58 NumberOfBondsPerAtom = NULL; 59 ElementCount = 0; 60 for(int i=MAX_ELEMENTS;i--;) 61 ElementsInMolecule[i] = 0; 62 cell_size[0] = cell_size[2] = cell_size[5]= 20.; 63 cell_size[1] = cell_size[3] = cell_size[4]= 0.; 64 strcpy(name,"none"); 65 65 }; 66 66 … … 70 70 molecule::~molecule() 71 71 { 72 73 74 75 76 77 78 79 80 81 72 if (ListOfBondsPerAtom != NULL) 73 for(int i=AtomCount;i--;) 74 Free((void **)&ListOfBondsPerAtom[i], "molecule::~molecule: ListOfBondsPerAtom[i]"); 75 Free((void **)&ListOfBondsPerAtom, "molecule::~molecule: ListOfBondsPerAtom"); 76 Free((void **)&NumberOfBondsPerAtom, "molecule::~molecule: NumberOfBondsPerAtom"); 77 CleanupMolecule(); 78 delete(first); 79 delete(last); 80 delete(end); 81 delete(start); 82 82 }; 83 83 … … 89 89 bool molecule::AddAtom(atom *pointer) 90 90 { 91 92 93 pointer->nr = last_atom++;// increase number within molecule94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 91 if (pointer != NULL) { 92 pointer->sort = &pointer->nr; 93 pointer->nr = last_atom++; // increase number within molecule 94 AtomCount++; 95 if (pointer->type != NULL) { 96 if (ElementsInMolecule[pointer->type->Z] == 0) 97 ElementCount++; 98 ElementsInMolecule[pointer->type->Z]++; // increase number of elements 99 if (pointer->type->Z != 1) 100 NoNonHydrogen++; 101 if (pointer->Name == NULL) { 102 Free((void **)&pointer->Name, "molecule::AddAtom: *pointer->Name"); 103 pointer->Name = (char *) Malloc(sizeof(char)*6, "molecule::AddAtom: *pointer->Name"); 104 sprintf(pointer->Name, "%2s%02d", pointer->type->symbol, pointer->nr+1); 105 } 106 } 107 return add(pointer, end); 108 } else 109 return false; 110 110 }; 111 111 … … 117 117 atom * molecule::AddCopyAtom(atom *pointer) 118 118 { 119 120 121 walker->type = pointer->type;// copy element of atom122 123 124 125 126 walker->nr = last_atom++;// increase number within molecule127 128 129 130 131 132 133 134 135 136 119 if (pointer != NULL) { 120 atom *walker = new atom(); 121 walker->type = pointer->type; // copy element of atom 122 walker->x.CopyVector(&pointer->x); // copy coordination 123 walker->v.CopyVector(&pointer->v); // copy velocity 124 walker->FixedIon = pointer->FixedIon; 125 walker->sort = &walker->nr; 126 walker->nr = last_atom++; // increase number within molecule 127 walker->father = pointer; //->GetTrueFather(); 128 walker->Name = (char *) Malloc(sizeof(char)*strlen(pointer->Name)+1, "molecule::AddCopyAtom: *Name"); 129 strcpy (walker->Name, pointer->Name); 130 add(walker, end); 131 if ((pointer->type != NULL) && (pointer->type->Z != 1)) 132 NoNonHydrogen++; 133 AtomCount++; 134 return walker; 135 } else 136 return NULL; 137 137 }; 138 138 … … 142 142 * -# Single Bond: Simply add new atom with bond distance rescaled to typical hydrogen one 143 143 * -# Double Bond: Here, we need the **BondList of the \a *origin atom, by scanning for the other bonds instead of 144 * 145 * 146 * 147 * 148 * 144 * *Bond, we use the through these connected atoms to determine the plane they lie in, vector::MakeNormalvector(). 145 * The orthonormal vector to this plane along with the vector in *Bond direction determines the plane the two 146 * replacing hydrogens shall lie in. Now, all remains to do is take the usual hydrogen double bond angle for the 147 * element of *origin and form the sin/cos admixture of both plane vectors for the new coordinates of the two 148 * hydrogens forming this angle with *origin. 149 149 * -# Triple Bond: The idea is to set up a tetraoid (C1-H1-H2-H3) (however the lengths \f$b\f$ of the sides of the base 150 * 151 * 152 * 153 * 154 * 155 * 156 * 157 * 158 * 159 * 160 * 161 * 162 * 150 * triangle formed by the to be added hydrogens are not equal to the typical bond distance \f$l\f$ but have to be 151 * determined from the typical angle \f$\alpha\f$ for a hydrogen triple connected to the element of *origin): 152 * We have the height \f$d\f$ as the vector in *Bond direction (from triangle C1-H1-H2). 153 * \f[ h = l \cdot \cos{\left (\frac{\alpha}{2} \right )} \qquad b = 2l \cdot \sin{\left (\frac{\alpha}{2} \right)} \quad \rightarrow \quad d = l \cdot \sqrt{\cos^2{\left (\frac{\alpha}{2} \right)}-\frac{1}{3}\cdot\sin^2{\left (\frac{\alpha}{2}\right )}} 154 * \f] 155 * vector::GetNormalvector() creates one orthonormal vector from this *Bond vector and vector::MakeNormalvector creates 156 * the third one from the former two vectors. The latter ones form the plane of the base triangle mentioned above. 157 * The lengths for these are \f$f\f$ and \f$g\f$ (from triangle H1-H2-(center of H1-H2-H3)) with knowledge that 158 * the median lines in an isosceles triangle meet in the center point with a ratio 2:1. 159 * \f[ f = \frac{b}{\sqrt{3}} \qquad g = \frac{b}{2} 160 * \f] 161 * as the coordination of all three atoms in the coordinate system of these three vectors: 162 * \f$\pmatrix{d & f & 0}\f$, \f$\pmatrix{d & -0.5 \cdot f & g}\f$ and \f$\pmatrix{d & -0.5 \cdot f & -g}\f$. 163 163 * 164 164 * \param *out output stream for debugging … … 168 168 * \param *replacement pointer to the atom which shall be copied as a hydrogen atom in this molecule 169 169 * \param **BondList list of bonds \a *replacement has (necessary to determine plane for double and triple bonds) 170 * \param NumBond 170 * \param NumBond number of bonds in \a **BondList 171 171 * \param isAngstroem whether the coordination of the given atoms is in AtomicLength (false) or Angstrom(true) 172 172 * \return number of atoms added, if < bond::BondDegree then something went wrong … … 175 175 bool molecule::AddHydrogenReplacementAtom(ofstream *out, bond *TopBond, atom *BottomOrigin, atom *TopOrigin, atom *TopReplacement, bond **BondList, int NumBond, bool IsAngstroem) 176 176 { 177 double bondlength;// bond length of the bond to be replaced/cut178 double bondangle;// bond angle of the bond to be replaced/cut179 double BondRescale;// rescale value for the hydrogen bond length180 bool AllWentWell = true;// flag gathering the boolean return value of molecule::AddAtom and other functions, as return value on exit181 182 183 double b,l,d,f,g, alpha, factors[NDIM];// hold temporary values in triple bond case for coordination determination184 Vector Orthovector1, Orthovector2;// temporary vectors in coordination construction185 Vector InBondvector;// vector in direction of *Bond186 187 188 189 // 190 191 192 193 194 195 196 197 198 199 // 200 // 201 // 202 203 204 205 206 207 208 209 210 211 212 213 214 // 215 // 216 // 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 FirstOtherAtom = new atom();// new atom235 FirstOtherAtom->type = elemente->FindElement(1);// element is Hydrogen236 237 238 239 240 241 242 FirstOtherAtom->father = NULL;// if we replace hydrogen, we mark it as our father, otherwise we are just an added hydrogen with no father243 244 InBondvector.Scale(&BondRescale);// rescale the distance vector to Hydrogen bond length245 246 FirstOtherAtom->x.AddVector(&InBondvector);// ... and add distance vector to replacement atom247 248 // 249 // 250 // 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 if (SecondOtherAtom == NULL) {// then we have an atom with valence four, but only 3 bonds: one to replace and one which is TopBond (third is FirstBond)271 272 273 274 275 // 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 FirstOtherAtom->father = NULL;// we are just an added hydrogen with no father300 SecondOtherAtom->father = NULL; //we are just an added hydrogen with no father301 302 303 304 305 306 307 308 // 309 // 310 // 311 // 312 // 313 // 314 // 315 316 317 318 319 320 321 FirstOtherAtom->x.Scale(&BondRescale);// rescale by correct BondDistance322 323 324 325 326 327 328 329 330 331 // 332 // 333 // 334 // 335 // 336 // 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 FirstOtherAtom->father = NULL; //we are just an added hydrogen with no father359 SecondOtherAtom->father = NULL; //we are just an added hydrogen with no father360 ThirdOtherAtom->father = NULL; //we are just an added hydrogen with no father361 362 363 364 // 365 // 366 // 367 368 // 369 // 370 // 371 372 373 alpha = (TopOrigin->type->HBondAngle[2])/180.*M_PI/2.;// retrieve triple bond angle from database374 l = BondRescale;// desired bond length375 b = 2.*l*sin(alpha);// base length of isosceles triangle376 d = l*sqrt(cos(alpha)*cos(alpha) - sin(alpha)*sin(alpha)/3.);// length for InBondvector377 f = b/sqrt(3.);// length for Orthvector1378 g = b/2.;// length for Orthvector2379 // 380 // *out << Verbose(3) << "The three Bond lengths: " << sqrt(d*d+f*f) << ", " << sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g) << ", "<< sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g) << endl;381 382 383 384 385 386 387 388 389 390 391 392 // 393 // 394 // 395 396 397 398 399 400 401 402 403 404 405 // 406 // 407 // 408 // 409 // 410 // 411 // 412 // 413 // 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 // 431 177 double bondlength; // bond length of the bond to be replaced/cut 178 double bondangle; // bond angle of the bond to be replaced/cut 179 double BondRescale; // rescale value for the hydrogen bond length 180 bool AllWentWell = true; // flag gathering the boolean return value of molecule::AddAtom and other functions, as return value on exit 181 bond *FirstBond = NULL, *SecondBond = NULL; // Other bonds in double bond case to determine "other" plane 182 atom *FirstOtherAtom = NULL, *SecondOtherAtom = NULL, *ThirdOtherAtom = NULL; // pointer to hydrogen atoms to be added 183 double b,l,d,f,g, alpha, factors[NDIM]; // hold temporary values in triple bond case for coordination determination 184 Vector Orthovector1, Orthovector2; // temporary vectors in coordination construction 185 Vector InBondvector; // vector in direction of *Bond 186 bond *Binder = NULL; 187 double *matrix; 188 189 // *out << Verbose(3) << "Begin of AddHydrogenReplacementAtom." << endl; 190 // create vector in direction of bond 191 InBondvector.CopyVector(&TopReplacement->x); 192 InBondvector.SubtractVector(&TopOrigin->x); 193 bondlength = InBondvector.Norm(); 194 195 // is greater than typical bond distance? Then we have to correct periodically 196 // the problem is not the H being out of the box, but InBondvector have the wrong direction 197 // due to TopReplacement or Origin being on the wrong side! 198 if (bondlength > BondDistance) { 199 // *out << Verbose(4) << "InBondvector is: "; 200 // InBondvector.Output(out); 201 // *out << endl; 202 Orthovector1.Zero(); 203 for (int i=NDIM;i--;) { 204 l = TopReplacement->x.x[i] - TopOrigin->x.x[i]; 205 if (fabs(l) > BondDistance) { // is component greater than bond distance 206 Orthovector1.x[i] = (l < 0) ? -1. : +1.; 207 } // (signs are correct, was tested!) 208 } 209 matrix = ReturnFullMatrixforSymmetric(cell_size); 210 Orthovector1.MatrixMultiplication(matrix); 211 InBondvector.SubtractVector(&Orthovector1); // subtract just the additional translation 212 Free((void **)&matrix, "molecule::AddHydrogenReplacementAtom: *matrix"); 213 bondlength = InBondvector.Norm(); 214 // *out << Verbose(4) << "Corrected InBondvector is now: "; 215 // InBondvector.Output(out); 216 // *out << endl; 217 } // periodic correction finished 218 219 InBondvector.Normalize(); 220 // get typical bond length and store as scale factor for later 221 BondRescale = TopOrigin->type->HBondDistance[TopBond->BondDegree-1]; 222 if (BondRescale == -1) { 223 cerr << Verbose(3) << "ERROR: There is no typical hydrogen bond distance in replacing bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") of degree " << TopBond->BondDegree << "!" << endl; 224 return false; 225 BondRescale = bondlength; 226 } else { 227 if (!IsAngstroem) 228 BondRescale /= (1.*AtomicLengthToAngstroem); 229 } 230 231 // discern single, double and triple bonds 232 switch(TopBond->BondDegree) { 233 case 1: 234 FirstOtherAtom = new atom(); // new atom 235 FirstOtherAtom->type = elemente->FindElement(1); // element is Hydrogen 236 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity 237 FirstOtherAtom->FixedIon = TopReplacement->FixedIon; 238 if (TopReplacement->type->Z == 1) { // neither rescale nor replace if it's already hydrogen 239 FirstOtherAtom->father = TopReplacement; 240 BondRescale = bondlength; 241 } else { 242 FirstOtherAtom->father = NULL; // if we replace hydrogen, we mark it as our father, otherwise we are just an added hydrogen with no father 243 } 244 InBondvector.Scale(&BondRescale); // rescale the distance vector to Hydrogen bond length 245 FirstOtherAtom->x.CopyVector(&TopOrigin->x); // set coordination to origin ... 246 FirstOtherAtom->x.AddVector(&InBondvector); // ... and add distance vector to replacement atom 247 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom); 248 // *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: "; 249 // FirstOtherAtom->x.Output(out); 250 // *out << endl; 251 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1); 252 Binder->Cyclic = false; 253 Binder->Type = TreeEdge; 254 break; 255 case 2: 256 // determine two other bonds (warning if there are more than two other) plus valence sanity check 257 for (int i=0;i<NumBond;i++) { 258 if (BondList[i] != TopBond) { 259 if (FirstBond == NULL) { 260 FirstBond = BondList[i]; 261 FirstOtherAtom = BondList[i]->GetOtherAtom(TopOrigin); 262 } else if (SecondBond == NULL) { 263 SecondBond = BondList[i]; 264 SecondOtherAtom = BondList[i]->GetOtherAtom(TopOrigin); 265 } else { 266 *out << Verbose(3) << "WARNING: Detected more than four bonds for atom " << TopOrigin->Name; 267 } 268 } 269 } 270 if (SecondOtherAtom == NULL) { // then we have an atom with valence four, but only 3 bonds: one to replace and one which is TopBond (third is FirstBond) 271 SecondBond = TopBond; 272 SecondOtherAtom = TopReplacement; 273 } 274 if (FirstOtherAtom != NULL) { // then we just have this double bond and the plane does not matter at all 275 // *out << Verbose(3) << "Regarding the double bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") to be constructed: Taking " << FirstOtherAtom->Name << " and " << SecondOtherAtom->Name << " along with " << TopOrigin->Name << " to determine orthogonal plane." << endl; 276 277 // determine the plane of these two with the *origin 278 AllWentWell = AllWentWell && Orthovector1.MakeNormalVector(&TopOrigin->x, &FirstOtherAtom->x, &SecondOtherAtom->x); 279 } else { 280 Orthovector1.GetOneNormalVector(&InBondvector); 281 } 282 //*out << Verbose(3)<< "Orthovector1: "; 283 //Orthovector1.Output(out); 284 //*out << endl; 285 // orthogonal vector and bond vector between origin and replacement form the new plane 286 Orthovector1.MakeNormalVector(&InBondvector); 287 Orthovector1.Normalize(); 288 //*out << Verbose(3) << "ReScaleCheck: " << Orthovector1.Norm() << " and " << InBondvector.Norm() << "." << endl; 289 290 // create the two Hydrogens ... 291 FirstOtherAtom = new atom(); 292 SecondOtherAtom = new atom(); 293 FirstOtherAtom->type = elemente->FindElement(1); 294 SecondOtherAtom->type = elemente->FindElement(1); 295 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity 296 FirstOtherAtom->FixedIon = TopReplacement->FixedIon; 297 SecondOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity 298 SecondOtherAtom->FixedIon = TopReplacement->FixedIon; 299 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father 300 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father 301 bondangle = TopOrigin->type->HBondAngle[1]; 302 if (bondangle == -1) { 303 *out << Verbose(3) << "ERROR: There is no typical hydrogen bond angle in replacing bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") of degree " << TopBond->BondDegree << "!" << endl; 304 return false; 305 bondangle = 0; 306 } 307 bondangle *= M_PI/180./2.; 308 // *out << Verbose(3) << "ReScaleCheck: InBondvector "; 309 // InBondvector.Output(out); 310 // *out << endl; 311 // *out << Verbose(3) << "ReScaleCheck: Orthovector "; 312 // Orthovector1.Output(out); 313 // *out << endl; 314 // *out << Verbose(3) << "Half the bond angle is " << bondangle << ", sin and cos of it: " << sin(bondangle) << ", " << cos(bondangle) << endl; 315 FirstOtherAtom->x.Zero(); 316 SecondOtherAtom->x.Zero(); 317 for(int i=NDIM;i--;) { // rotate by half the bond angle in both directions (InBondvector is bondangle = 0 direction) 318 FirstOtherAtom->x.x[i] = InBondvector.x[i] * cos(bondangle) + Orthovector1.x[i] * (sin(bondangle)); 319 SecondOtherAtom->x.x[i] = InBondvector.x[i] * cos(bondangle) + Orthovector1.x[i] * (-sin(bondangle)); 320 } 321 FirstOtherAtom->x.Scale(&BondRescale); // rescale by correct BondDistance 322 SecondOtherAtom->x.Scale(&BondRescale); 323 //*out << Verbose(3) << "ReScaleCheck: " << FirstOtherAtom->x.Norm() << " and " << SecondOtherAtom->x.Norm() << "." << endl; 324 for(int i=NDIM;i--;) { // and make relative to origin atom 325 FirstOtherAtom->x.x[i] += TopOrigin->x.x[i]; 326 SecondOtherAtom->x.x[i] += TopOrigin->x.x[i]; 327 } 328 // ... and add to molecule 329 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom); 330 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom); 331 // *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: "; 332 // FirstOtherAtom->x.Output(out); 333 // *out << endl; 334 // *out << Verbose(4) << "Added " << *SecondOtherAtom << " at: "; 335 // SecondOtherAtom->x.Output(out); 336 // *out << endl; 337 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1); 338 Binder->Cyclic = false; 339 Binder->Type = TreeEdge; 340 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1); 341 Binder->Cyclic = false; 342 Binder->Type = TreeEdge; 343 break; 344 case 3: 345 // take the "usual" tetraoidal angle and add the three Hydrogen in direction of the bond (height of the tetraoid) 346 FirstOtherAtom = new atom(); 347 SecondOtherAtom = new atom(); 348 ThirdOtherAtom = new atom(); 349 FirstOtherAtom->type = elemente->FindElement(1); 350 SecondOtherAtom->type = elemente->FindElement(1); 351 ThirdOtherAtom->type = elemente->FindElement(1); 352 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity 353 FirstOtherAtom->FixedIon = TopReplacement->FixedIon; 354 SecondOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity 355 SecondOtherAtom->FixedIon = TopReplacement->FixedIon; 356 ThirdOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity 357 ThirdOtherAtom->FixedIon = TopReplacement->FixedIon; 358 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father 359 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father 360 ThirdOtherAtom->father = NULL; // we are just an added hydrogen with no father 361 362 // we need to vectors orthonormal the InBondvector 363 AllWentWell = AllWentWell && Orthovector1.GetOneNormalVector(&InBondvector); 364 // *out << Verbose(3) << "Orthovector1: "; 365 // Orthovector1.Output(out); 366 // *out << endl; 367 AllWentWell = AllWentWell && Orthovector2.MakeNormalVector(&InBondvector, &Orthovector1); 368 // *out << Verbose(3) << "Orthovector2: "; 369 // Orthovector2.Output(out); 370 // *out << endl; 371 372 // create correct coordination for the three atoms 373 alpha = (TopOrigin->type->HBondAngle[2])/180.*M_PI/2.; // retrieve triple bond angle from database 374 l = BondRescale; // desired bond length 375 b = 2.*l*sin(alpha); // base length of isosceles triangle 376 d = l*sqrt(cos(alpha)*cos(alpha) - sin(alpha)*sin(alpha)/3.); // length for InBondvector 377 f = b/sqrt(3.); // length for Orthvector1 378 g = b/2.; // length for Orthvector2 379 // *out << Verbose(3) << "Bond length and half-angle: " << l << ", " << alpha << "\t (b,d,f,g) = " << b << ", " << d << ", " << f << ", " << g << ", " << endl; 380 // *out << Verbose(3) << "The three Bond lengths: " << sqrt(d*d+f*f) << ", " << sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g) << ", " << sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g) << endl; 381 factors[0] = d; 382 factors[1] = f; 383 factors[2] = 0.; 384 FirstOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors); 385 factors[1] = -0.5*f; 386 factors[2] = g; 387 SecondOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors); 388 factors[2] = -g; 389 ThirdOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors); 390 391 // rescale each to correct BondDistance 392 // FirstOtherAtom->x.Scale(&BondRescale); 393 // SecondOtherAtom->x.Scale(&BondRescale); 394 // ThirdOtherAtom->x.Scale(&BondRescale); 395 396 // and relative to *origin atom 397 FirstOtherAtom->x.AddVector(&TopOrigin->x); 398 SecondOtherAtom->x.AddVector(&TopOrigin->x); 399 ThirdOtherAtom->x.AddVector(&TopOrigin->x); 400 401 // ... and add to molecule 402 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom); 403 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom); 404 AllWentWell = AllWentWell && AddAtom(ThirdOtherAtom); 405 // *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: "; 406 // FirstOtherAtom->x.Output(out); 407 // *out << endl; 408 // *out << Verbose(4) << "Added " << *SecondOtherAtom << " at: "; 409 // SecondOtherAtom->x.Output(out); 410 // *out << endl; 411 // *out << Verbose(4) << "Added " << *ThirdOtherAtom << " at: "; 412 // ThirdOtherAtom->x.Output(out); 413 // *out << endl; 414 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1); 415 Binder->Cyclic = false; 416 Binder->Type = TreeEdge; 417 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1); 418 Binder->Cyclic = false; 419 Binder->Type = TreeEdge; 420 Binder = AddBond(BottomOrigin, ThirdOtherAtom, 1); 421 Binder->Cyclic = false; 422 Binder->Type = TreeEdge; 423 break; 424 default: 425 cerr << "ERROR: BondDegree does not state single, double or triple bond!" << endl; 426 AllWentWell = false; 427 break; 428 } 429 430 // *out << Verbose(3) << "End of AddHydrogenReplacementAtom." << endl; 431 return AllWentWell; 432 432 }; 433 433 … … 439 439 bool molecule::AddXYZFile(string filename) 440 440 { 441 442 443 444 atom *Walker = NULL;// pointer to added atom445 char shorthand[3];// shorthand for atom name446 ifstream xyzfile;// xyz file447 string line;// currently parsed line448 double x[3];// atom coordinates449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 AddAtom(Walker);// add to molecule490 491 492 493 494 441 istringstream *input = NULL; 442 int NumberOfAtoms = 0; // atom number in xyz read 443 int i, j; // loop variables 444 atom *Walker = NULL; // pointer to added atom 445 char shorthand[3]; // shorthand for atom name 446 ifstream xyzfile; // xyz file 447 string line; // currently parsed line 448 double x[3]; // atom coordinates 449 450 xyzfile.open(filename.c_str()); 451 if (!xyzfile) 452 return false; 453 454 getline(xyzfile,line,'\n'); // Read numer of atoms in file 455 input = new istringstream(line); 456 *input >> NumberOfAtoms; 457 cout << Verbose(0) << "Parsing " << NumberOfAtoms << " atoms in file." << endl; 458 getline(xyzfile,line,'\n'); // Read comment 459 cout << Verbose(1) << "Comment: " << line << endl; 460 461 if (MDSteps == 0) // no atoms yet present 462 MDSteps++; 463 for(i=0;i<NumberOfAtoms;i++){ 464 Walker = new atom; 465 getline(xyzfile,line,'\n'); 466 istringstream *item = new istringstream(line); 467 //istringstream input(line); 468 //cout << Verbose(1) << "Reading: " << line << endl; 469 *item >> shorthand; 470 *item >> x[0]; 471 *item >> x[1]; 472 *item >> x[2]; 473 Walker->type = elemente->FindElement(shorthand); 474 if (Walker->type == NULL) { 475 cerr << "Could not parse the element at line: '" << line << "', setting to H."; 476 Walker->type = elemente->FindElement(1); 477 } 478 if (Trajectories[Walker].R.size() <= (unsigned int)MDSteps) { 479 Trajectories[Walker].R.resize(MDSteps+10); 480 Trajectories[Walker].U.resize(MDSteps+10); 481 Trajectories[Walker].F.resize(MDSteps+10); 482 } 483 for(j=NDIM;j--;) { 484 Walker->x.x[j] = x[j]; 485 Trajectories[Walker].R.at(MDSteps-1).x[j] = x[j]; 486 Trajectories[Walker].U.at(MDSteps-1).x[j] = 0; 487 Trajectories[Walker].F.at(MDSteps-1).x[j] = 0; 488 } 489 AddAtom(Walker); // add to molecule 490 delete(item); 491 } 492 xyzfile.close(); 493 delete(input); 494 return true; 495 495 }; 496 496 … … 500 500 molecule *molecule::CopyMolecule() 501 501 { 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 if (Walker->father->father == Walker->father)// same atom in copy's father points to itself543 Walker->father = Walker;// set father to itself (copy of a whole molecule)544 545 Walker->father = Walker->father->father;// set father to original's father546 547 548 549 550 if (first->next != last) {// if adjaceny list is present551 552 553 554 555 502 molecule *copy = new molecule(elemente); 503 atom *CurrentAtom = NULL; 504 atom *LeftAtom = NULL, *RightAtom = NULL; 505 atom *Walker = NULL; 506 507 // copy all atoms 508 Walker = start; 509 while(Walker->next != end) { 510 Walker = Walker->next; 511 CurrentAtom = copy->AddCopyAtom(Walker); 512 } 513 514 // copy all bonds 515 bond *Binder = first; 516 bond *NewBond = NULL; 517 while(Binder->next != last) { 518 Binder = Binder->next; 519 // get the pendant atoms of current bond in the copy molecule 520 LeftAtom = copy->start; 521 while (LeftAtom->next != copy->end) { 522 LeftAtom = LeftAtom->next; 523 if (LeftAtom->father == Binder->leftatom) 524 break; 525 } 526 RightAtom = copy->start; 527 while (RightAtom->next != copy->end) { 528 RightAtom = RightAtom->next; 529 if (RightAtom->father == Binder->rightatom) 530 break; 531 } 532 NewBond = copy->AddBond(LeftAtom, RightAtom, Binder->BondDegree); 533 NewBond->Cyclic = Binder->Cyclic; 534 if (Binder->Cyclic) 535 copy->NoCyclicBonds++; 536 NewBond->Type = Binder->Type; 537 } 538 // correct fathers 539 Walker = copy->start; 540 while(Walker->next != copy->end) { 541 Walker = Walker->next; 542 if (Walker->father->father == Walker->father) // same atom in copy's father points to itself 543 Walker->father = Walker; // set father to itself (copy of a whole molecule) 544 else 545 Walker->father = Walker->father->father; // set father to original's father 546 } 547 // copy values 548 copy->CountAtoms((ofstream *)&cout); 549 copy->CountElements(); 550 if (first->next != last) { // if adjaceny list is present 551 copy->BondDistance = BondDistance; 552 copy->CreateListOfBondsPerAtom((ofstream *)&cout); 553 } 554 555 return copy; 556 556 }; 557 557 … … 564 564 bond * molecule::AddBond(atom *atom1, atom *atom2, int degree=1) 565 565 { 566 567 568 569 570 571 572 573 574 575 566 bond *Binder = NULL; 567 if ((atom1 != NULL) && (FindAtom(atom1->nr) != NULL) && (atom2 != NULL) && (FindAtom(atom2->nr) != NULL)) { 568 Binder = new bond(atom1, atom2, degree, BondCount++); 569 if ((atom1->type != NULL) && (atom1->type->Z != 1) && (atom2->type != NULL) && (atom2->type->Z != 1)) 570 NoNonBonds++; 571 add(Binder, last); 572 } else { 573 cerr << Verbose(1) << "ERROR: Could not add bond between " << atom1->Name << " and " << atom2->Name << " as one or both are not present in the molecule." << endl; 574 } 575 return Binder; 576 576 }; 577 577 … … 583 583 bool molecule::RemoveBond(bond *pointer) 584 584 { 585 586 587 585 //cerr << Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl; 586 removewithoutcheck(pointer); 587 return true; 588 588 }; 589 589 … … 595 595 bool molecule::RemoveBonds(atom *BondPartner) 596 596 { 597 598 597 cerr << Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl; 598 return false; 599 599 }; 600 600 … … 619 619 void molecule::SetBoxDimension(Vector *dim) 620 620 { 621 622 623 624 625 626 621 cell_size[0] = dim->x[0]; 622 cell_size[1] = 0.; 623 cell_size[2] = dim->x[1]; 624 cell_size[3] = 0.; 625 cell_size[4] = 0.; 626 cell_size[5] = dim->x[2]; 627 627 }; 628 628 … … 633 633 bool molecule::CenterInBox(ofstream *out, Vector *BoxLengths) 634 634 { 635 636 637 638 639 640 641 ptr = start->next;// start at first in list642 if (ptr != end) {//list not empty?643 644 645 646 647 while (ptr->next != end) {// continue with second if present648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 else {// else center in box665 666 667 668 669 670 671 672 673 674 675 635 bool status = true; 636 atom *ptr = NULL; 637 Vector *min = new Vector; 638 Vector *max = new Vector; 639 640 // gather min and max for each axis 641 ptr = start->next; // start at first in list 642 if (ptr != end) { //list not empty? 643 for (int i=NDIM;i--;) { 644 max->x[i] = ptr->x.x[i]; 645 min->x[i] = ptr->x.x[i]; 646 } 647 while (ptr->next != end) { // continue with second if present 648 ptr = ptr->next; 649 //ptr->Output(1,1,out); 650 for (int i=NDIM;i--;) { 651 max->x[i] = (max->x[i] < ptr->x.x[i]) ? ptr->x.x[i] : max->x[i]; 652 min->x[i] = (min->x[i] > ptr->x.x[i]) ? ptr->x.x[i] : min->x[i]; 653 } 654 } 655 } 656 // sanity check 657 for(int i=NDIM;i--;) { 658 if (max->x[i] - min->x[i] > BoxLengths->x[i]) 659 status = false; 660 } 661 // warn if check failed 662 if (!status) 663 *out << "WARNING: molecule is bigger than defined box!" << endl; 664 else { // else center in box 665 max->AddVector(min); 666 max->Scale(-1.); 667 max->AddVector(BoxLengths); 668 max->Scale(0.5); 669 Translate(max); 670 } 671 672 // free and exit 673 delete(min); 674 delete(max); 675 return status; 676 676 }; 677 677 … … 682 682 void molecule::CenterEdge(ofstream *out, Vector *max) 683 683 { 684 685 686 // 687 atom *ptr = start->next;// start at first in list688 if (ptr != end) {//list not empty?689 690 691 692 693 while (ptr->next != end) {// continue with second if present694 695 696 697 698 699 700 701 // 702 // 703 // 704 // 705 // 706 707 708 709 710 711 // 684 Vector *min = new Vector; 685 686 // *out << Verbose(3) << "Begin of CenterEdge." << endl; 687 atom *ptr = start->next; // start at first in list 688 if (ptr != end) { //list not empty? 689 for (int i=NDIM;i--;) { 690 max->x[i] = ptr->x.x[i]; 691 min->x[i] = ptr->x.x[i]; 692 } 693 while (ptr->next != end) { // continue with second if present 694 ptr = ptr->next; 695 //ptr->Output(1,1,out); 696 for (int i=NDIM;i--;) { 697 max->x[i] = (max->x[i] < ptr->x.x[i]) ? ptr->x.x[i] : max->x[i]; 698 min->x[i] = (min->x[i] > ptr->x.x[i]) ? ptr->x.x[i] : min->x[i]; 699 } 700 } 701 // *out << Verbose(4) << "Maximum is "; 702 // max->Output(out); 703 // *out << ", Minimum is "; 704 // min->Output(out); 705 // *out << endl; 706 min->Scale(-1.); 707 max->AddVector(min); 708 Translate(min); 709 } 710 delete(min); 711 // *out << Verbose(3) << "End of CenterEdge." << endl; 712 712 }; 713 713 … … 718 718 void molecule::CenterOrigin(ofstream *out, Vector *center) 719 719 { 720 721 atom *ptr = start->next;// start at first in list722 723 724 725 726 if (ptr != end) {//list not empty?727 while (ptr->next != end) {// continue with second if present728 729 730 731 732 733 734 720 int Num = 0; 721 atom *ptr = start->next; // start at first in list 722 723 for(int i=NDIM;i--;) // zero center vector 724 center->x[i] = 0.; 725 726 if (ptr != end) { //list not empty? 727 while (ptr->next != end) { // continue with second if present 728 ptr = ptr->next; 729 Num++; 730 center->AddVector(&ptr->x); 731 } 732 center->Scale(-1./Num); // divide through total number (and sign for direction) 733 Translate(center); 734 } 735 735 }; 736 736 … … 741 741 Vector * molecule::DetermineCenterOfAll(ofstream *out) 742 742 { 743 atom *ptr = start->next;// start at first in list744 745 746 747 748 749 750 if (ptr != end) {//list not empty?751 while (ptr->next != end) {// continue with second if present752 753 754 755 756 757 758 759 760 761 762 743 atom *ptr = start->next; // start at first in list 744 Vector *a = new Vector(); 745 Vector tmp; 746 double Num = 0; 747 748 a->Zero(); 749 750 if (ptr != end) { //list not empty? 751 while (ptr->next != end) { // continue with second if present 752 ptr = ptr->next; 753 Num += 1.; 754 tmp.CopyVector(&ptr->x); 755 a->AddVector(&tmp); 756 } 757 a->Scale(-1./Num); // divide through total mass (and sign for direction) 758 } 759 //cout << Verbose(1) << "Resulting center of gravity: "; 760 //a->Output(out); 761 //cout << endl; 762 return a; 763 763 }; 764 764 … … 769 769 Vector * molecule::DetermineCenterOfGravity(ofstream *out) 770 770 { 771 atom *ptr = start->next;// start at first in list772 773 774 775 776 777 778 if (ptr != end) {//list not empty?779 while (ptr->next != end) {// continue with second if present780 781 782 783 tmp.Scale(ptr->type->mass);// scale by mass784 785 786 787 788 // 789 // 790 // 791 771 atom *ptr = start->next; // start at first in list 772 Vector *a = new Vector(); 773 Vector tmp; 774 double Num = 0; 775 776 a->Zero(); 777 778 if (ptr != end) { //list not empty? 779 while (ptr->next != end) { // continue with second if present 780 ptr = ptr->next; 781 Num += ptr->type->mass; 782 tmp.CopyVector(&ptr->x); 783 tmp.Scale(ptr->type->mass); // scale by mass 784 a->AddVector(&tmp); 785 } 786 a->Scale(-1./Num); // divide through total mass (and sign for direction) 787 } 788 // *out << Verbose(1) << "Resulting center of gravity: "; 789 // a->Output(out); 790 // *out << endl; 791 return a; 792 792 }; 793 793 … … 798 798 void molecule::CenterGravity(ofstream *out, Vector *center) 799 799 { 800 801 802 803 804 805 806 800 if (center == NULL) { 801 DetermineCenter(*center); 802 Translate(center); 803 delete(center); 804 } else { 805 Translate(center); 806 } 807 807 }; 808 808 … … 812 812 void molecule::Scale(double **factor) 813 813 { 814 815 816 817 818 819 820 821 814 atom *ptr = start; 815 816 while (ptr->next != end) { 817 ptr = ptr->next; 818 for (int j=0;j<MDSteps;j++) 819 Trajectories[ptr].R.at(j).Scale(factor); 820 ptr->x.Scale(factor); 821 } 822 822 }; 823 823 … … 827 827 void molecule::Translate(const Vector *trans) 828 828 { 829 830 831 832 833 834 835 836 829 atom *ptr = start; 830 831 while (ptr->next != end) { 832 ptr = ptr->next; 833 for (int j=0;j<MDSteps;j++) 834 Trajectories[ptr].R.at(j).Translate(trans); 835 ptr->x.Translate(trans); 836 } 837 837 }; 838 838 … … 842 842 void molecule::Mirror(const Vector *n) 843 843 { 844 845 846 847 848 849 850 851 844 atom *ptr = start; 845 846 while (ptr->next != end) { 847 ptr = ptr->next; 848 for (int j=0;j<MDSteps;j++) 849 Trajectories[ptr].R.at(j).Mirror(n); 850 ptr->x.Mirror(n); 851 } 852 852 }; 853 853 … … 857 857 void molecule::DetermineCenter(Vector &Center) 858 858 { 859 860 861 862 863 864 865 866 867 868 869 870 859 atom *Walker = start; 860 bond *Binder = NULL; 861 double *matrix = ReturnFullMatrixforSymmetric(cell_size); 862 double tmp; 863 bool flag; 864 Vector Testvector, Translationvector; 865 866 do { 867 Center.Zero(); 868 flag = true; 869 while (Walker->next != end) { 870 Walker = Walker->next; 871 871 #ifdef ADDHYDROGEN 872 872 if (Walker->type->Z != 1) { 873 873 #endif 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 874 Testvector.CopyVector(&Walker->x); 875 Testvector.InverseMatrixMultiplication(matrix); 876 Translationvector.Zero(); 877 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) { 878 Binder = ListOfBondsPerAtom[Walker->nr][i]; 879 if (Walker->nr < Binder->GetOtherAtom(Walker)->nr) // otherwise we shift one to, the other fro and gain nothing 880 for (int j=0;j<NDIM;j++) { 881 tmp = Walker->x.x[j] - Binder->GetOtherAtom(Walker)->x.x[j]; 882 if ((fabs(tmp)) > BondDistance) { 883 flag = false; 884 cout << Verbose(0) << "Hit: atom " << Walker->Name << " in bond " << *Binder << " has to be shifted due to " << tmp << "." << endl; 885 if (tmp > 0) 886 Translationvector.x[j] -= 1.; 887 else 888 Translationvector.x[j] += 1.; 889 } 890 } 891 } 892 Testvector.AddVector(&Translationvector); 893 Testvector.MatrixMultiplication(matrix); 894 Center.AddVector(&Testvector); 895 cout << Verbose(1) << "vector is: "; 896 Testvector.Output((ofstream *)&cout); 897 cout << endl; 898 898 #ifdef ADDHYDROGEN 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 899 // now also change all hydrogens 900 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) { 901 Binder = ListOfBondsPerAtom[Walker->nr][i]; 902 if (Binder->GetOtherAtom(Walker)->type->Z == 1) { 903 Testvector.CopyVector(&Binder->GetOtherAtom(Walker)->x); 904 Testvector.InverseMatrixMultiplication(matrix); 905 Testvector.AddVector(&Translationvector); 906 Testvector.MatrixMultiplication(matrix); 907 Center.AddVector(&Testvector); 908 cout << Verbose(1) << "Hydrogen vector is: "; 909 Testvector.Output((ofstream *)&cout); 910 cout << endl; 911 } 912 } 913 } 914 914 #endif 915 916 917 918 915 } 916 } while (!flag); 917 Free((void **)&matrix, "molecule::DetermineCenter: *matrix"); 918 Center.Scale(1./(double)AtomCount); 919 919 }; 920 920 … … 925 925 void molecule::PrincipalAxisSystem(ofstream *out, bool DoRotate) 926 926 { 927 atom *ptr = start;// start at first in list928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 927 atom *ptr = start; // start at first in list 928 double InertiaTensor[NDIM*NDIM]; 929 Vector *CenterOfGravity = DetermineCenterOfGravity(out); 930 931 CenterGravity(out, CenterOfGravity); 932 933 // reset inertia tensor 934 for(int i=0;i<NDIM*NDIM;i++) 935 InertiaTensor[i] = 0.; 936 937 // sum up inertia tensor 938 while (ptr->next != end) { 939 ptr = ptr->next; 940 Vector x; 941 x.CopyVector(&ptr->x); 942 //x.SubtractVector(CenterOfGravity); 943 InertiaTensor[0] += ptr->type->mass*(x.x[1]*x.x[1] + x.x[2]*x.x[2]); 944 InertiaTensor[1] += ptr->type->mass*(-x.x[0]*x.x[1]); 945 InertiaTensor[2] += ptr->type->mass*(-x.x[0]*x.x[2]); 946 InertiaTensor[3] += ptr->type->mass*(-x.x[1]*x.x[0]); 947 InertiaTensor[4] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[2]*x.x[2]); 948 InertiaTensor[5] += ptr->type->mass*(-x.x[1]*x.x[2]); 949 InertiaTensor[6] += ptr->type->mass*(-x.x[2]*x.x[0]); 950 InertiaTensor[7] += ptr->type->mass*(-x.x[2]*x.x[1]); 951 InertiaTensor[8] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[1]*x.x[1]); 952 } 953 // print InertiaTensor for debugging 954 *out << "The inertia tensor is:" << endl; 955 for(int i=0;i<NDIM;i++) { 956 for(int j=0;j<NDIM;j++) 957 *out << InertiaTensor[i*NDIM+j] << " "; 958 *out << endl; 959 } 960 *out << endl; 961 962 // diagonalize to determine principal axis system 963 gsl_eigen_symmv_workspace *T = gsl_eigen_symmv_alloc(NDIM); 964 gsl_matrix_view m = gsl_matrix_view_array(InertiaTensor, NDIM, NDIM); 965 gsl_vector *eval = gsl_vector_alloc(NDIM); 966 gsl_matrix *evec = gsl_matrix_alloc(NDIM, NDIM); 967 gsl_eigen_symmv(&m.matrix, eval, evec, T); 968 gsl_eigen_symmv_free(T); 969 gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_ABS_DESC); 970 971 for(int i=0;i<NDIM;i++) { 972 *out << Verbose(1) << "eigenvalue = " << gsl_vector_get(eval, i); 973 *out << ", eigenvector = (" << evec->data[i * evec->tda + 0] << "," << evec->data[i * evec->tda + 1] << "," << evec->data[i * evec->tda + 2] << ")" << endl; 974 } 975 976 // check whether we rotate or not 977 if (DoRotate) { 978 *out << Verbose(1) << "Transforming molecule into PAS ... "; 979 // the eigenvectors specify the transformation matrix 980 ptr = start; 981 while (ptr->next != end) { 982 ptr = ptr->next; 983 for (int j=0;j<MDSteps;j++) 984 Trajectories[ptr].R.at(j).MatrixMultiplication(evec->data); 985 ptr->x.MatrixMultiplication(evec->data); 986 } 987 *out << "done." << endl; 988 989 // summing anew for debugging (resulting matrix has to be diagonal!) 990 // reset inertia tensor 991 for(int i=0;i<NDIM*NDIM;i++) 992 InertiaTensor[i] = 0.; 993 994 // sum up inertia tensor 995 ptr = start; 996 while (ptr->next != end) { 997 ptr = ptr->next; 998 Vector x; 999 x.CopyVector(&ptr->x); 1000 //x.SubtractVector(CenterOfGravity); 1001 InertiaTensor[0] += ptr->type->mass*(x.x[1]*x.x[1] + x.x[2]*x.x[2]); 1002 InertiaTensor[1] += ptr->type->mass*(-x.x[0]*x.x[1]); 1003 InertiaTensor[2] += ptr->type->mass*(-x.x[0]*x.x[2]); 1004 InertiaTensor[3] += ptr->type->mass*(-x.x[1]*x.x[0]); 1005 InertiaTensor[4] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[2]*x.x[2]); 1006 InertiaTensor[5] += ptr->type->mass*(-x.x[1]*x.x[2]); 1007 InertiaTensor[6] += ptr->type->mass*(-x.x[2]*x.x[0]); 1008 InertiaTensor[7] += ptr->type->mass*(-x.x[2]*x.x[1]); 1009 InertiaTensor[8] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[1]*x.x[1]); 1010 } 1011 // print InertiaTensor for debugging 1012 *out << "The inertia tensor is:" << endl; 1013 for(int i=0;i<NDIM;i++) { 1014 for(int j=0;j<NDIM;j++) 1015 *out << InertiaTensor[i*NDIM+j] << " "; 1016 *out << endl; 1017 } 1018 *out << endl; 1019 } 1020 1021 // free everything 1022 delete(CenterOfGravity); 1023 gsl_vector_free(eval); 1024 gsl_matrix_free(evec); 1025 1025 }; 1026 1026 … … 1036 1036 bool molecule::VerletForceIntegration(char *file, double delta_t, bool IsAngstroem) 1037 1037 { 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 CountElements();// make sure ElementsInMolecule is up to date1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 // 1065 // 1066 // 1067 // 1068 // 1069 // 1070 // 1071 // 1072 // 1073 // 1074 1075 1076 1077 1078 1079 a = delta_t*0.5/IonMass;// (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 Trajectories[walker].R.at(MDSteps).x[d] += 0.5*delta_t*delta_t*(Trajectories[walker].F.at(MDSteps-1).x[d])/IonMass;// F = m * a and s = 0.5 * F/m * t^2 = F * a * t1099 1100 1101 1102 1103 1104 1105 // 1106 // 1107 // cout << Trajectories[walker].R.at(MDSteps).x[d] << " ";// next step1108 // 1109 // 1110 // cout << Trajectories[walker].U.at(MDSteps).x[d] << " ";// next step1111 // 1112 1113 1114 1115 1116 1117 1118 1119 // 1120 // 1121 // 1122 // 1123 // 1124 // 1125 // IonMass += walker->type->mass;// sum up total mass1126 // 1127 // 1128 // 1129 // 1130 // 1131 // 1132 // 1133 // 1134 // 1135 // 1136 // 1137 1138 1139 1140 1141 1038 element *runner = elemente->start; 1039 atom *walker = NULL; 1040 int AtomNo; 1041 ifstream input(file); 1042 string token; 1043 stringstream item; 1044 double a, IonMass; 1045 ForceMatrix Force; 1046 Vector tmpvector; 1047 1048 CountElements(); // make sure ElementsInMolecule is up to date 1049 1050 // check file 1051 if (input == NULL) { 1052 return false; 1053 } else { 1054 // parse file into ForceMatrix 1055 if (!Force.ParseMatrix(file, 0,0,0)) { 1056 cerr << "Could not parse Force Matrix file " << file << "." << endl; 1057 return false; 1058 } 1059 if (Force.RowCounter[0] != AtomCount) { 1060 cerr << "Mismatch between number of atoms in file " << Force.RowCounter[0] << " and in molecule " << AtomCount << "." << endl; 1061 return false; 1062 } 1063 // correct Forces 1064 // for(int d=0;d<NDIM;d++) 1065 // tmpvector.x[d] = 0.; 1066 // for(int i=0;i<AtomCount;i++) 1067 // for(int d=0;d<NDIM;d++) { 1068 // tmpvector.x[d] += Force.Matrix[0][i][d+5]; 1069 // } 1070 // for(int i=0;i<AtomCount;i++) 1071 // for(int d=0;d<NDIM;d++) { 1072 // Force.Matrix[0][i][d+5] -= tmpvector.x[d]/(double)AtomCount; 1073 // } 1074 // and perform Verlet integration for each atom with position, velocity and force vector 1075 runner = elemente->start; 1076 while (runner->next != elemente->end) { // go through every element 1077 runner = runner->next; 1078 IonMass = runner->mass; 1079 a = delta_t*0.5/IonMass; // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a 1080 if (ElementsInMolecule[runner->Z]) { // if this element got atoms 1081 AtomNo = 0; 1082 walker = start; 1083 while (walker->next != end) { // go through every atom of this element 1084 walker = walker->next; 1085 if (walker->type == runner) { // if this atom fits to element 1086 // check size of vectors 1087 if (Trajectories[walker].R.size() <= (unsigned int)(MDSteps)) { 1088 //cout << "Increasing size for trajectory array of " << *walker << " to " << (size+10) << "." << endl; 1089 Trajectories[walker].R.resize(MDSteps+10); 1090 Trajectories[walker].U.resize(MDSteps+10); 1091 Trajectories[walker].F.resize(MDSteps+10); 1092 } 1093 // 1. calculate x(t+\delta t) 1094 for (int d=0; d<NDIM; d++) { 1095 Trajectories[walker].F.at(MDSteps).x[d] = -Force.Matrix[0][AtomNo][d+5]; 1096 Trajectories[walker].R.at(MDSteps).x[d] = Trajectories[walker].R.at(MDSteps-1).x[d]; 1097 Trajectories[walker].R.at(MDSteps).x[d] += delta_t*(Trajectories[walker].U.at(MDSteps-1).x[d]); 1098 Trajectories[walker].R.at(MDSteps).x[d] += 0.5*delta_t*delta_t*(Trajectories[walker].F.at(MDSteps-1).x[d])/IonMass; // F = m * a and s = 0.5 * F/m * t^2 = F * a * t 1099 } 1100 // 2. Calculate v(t+\delta t) 1101 for (int d=0; d<NDIM; d++) { 1102 Trajectories[walker].U.at(MDSteps).x[d] = Trajectories[walker].U.at(MDSteps-1).x[d]; 1103 Trajectories[walker].U.at(MDSteps).x[d] += 0.5*delta_t*(Trajectories[walker].F.at(MDSteps-1).x[d]+Trajectories[walker].F.at(MDSteps).x[d])/IonMass; 1104 } 1105 // cout << "Integrated position&velocity of step " << (MDSteps) << ": ("; 1106 // for (int d=0;d<NDIM;d++) 1107 // cout << Trajectories[walker].R.at(MDSteps).x[d] << " "; // next step 1108 // cout << ")\t("; 1109 // for (int d=0;d<NDIM;d++) 1110 // cout << Trajectories[walker].U.at(MDSteps).x[d] << " "; // next step 1111 // cout << ")" << endl; 1112 // next atom 1113 AtomNo++; 1114 } 1115 } 1116 } 1117 } 1118 } 1119 // // correct velocities (rather momenta) so that center of mass remains motionless 1120 // tmpvector.zero() 1121 // IonMass = 0.; 1122 // walker = start; 1123 // while (walker->next != end) { // go through every atom 1124 // walker = walker->next; 1125 // IonMass += walker->type->mass; // sum up total mass 1126 // for(int d=0;d<NDIM;d++) { 1127 // tmpvector.x[d] += Trajectories[walker].U.at(MDSteps).x[d]*walker->type->mass; 1128 // } 1129 // } 1130 // walker = start; 1131 // while (walker->next != end) { // go through every atom of this element 1132 // walker = walker->next; 1133 // for(int d=0;d<NDIM;d++) { 1134 // Trajectories[walker].U.at(MDSteps).x[d] -= tmpvector.x[d]*walker->type->mass/IonMass; 1135 // } 1136 // } 1137 MDSteps++; 1138 1139 1140 // exit 1141 return true; 1142 1142 }; 1143 1143 … … 1147 1147 void molecule::Align(Vector *n) 1148 1148 { 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 ptr->x.x[0] =cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];1164 1165 1166 1167 Trajectories[ptr].R.at(j).x[0] =cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2];1168 1169 1170 1171 1172 1173 n->x[0] = cos(alpha) * tmp +sin(alpha) * n->x[2];1174 n->x[2] = -sin(alpha) * tmp +cos(alpha) * n->x[2];1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 ptr->x.x[1] =cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];1187 1188 1189 1190 Trajectories[ptr].R.at(j).x[1] =cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2];1191 1192 1193 1194 1195 1196 n->x[1] = cos(alpha) * tmp +sin(alpha) * n->x[2];1197 n->x[2] = -sin(alpha) * tmp +cos(alpha) * n->x[2];1198 1199 1200 1201 1202 1149 atom *ptr = start; 1150 double alpha, tmp; 1151 Vector z_axis; 1152 z_axis.x[0] = 0.; 1153 z_axis.x[1] = 0.; 1154 z_axis.x[2] = 1.; 1155 1156 // rotate on z-x plane 1157 cout << Verbose(0) << "Begin of Aligning all atoms." << endl; 1158 alpha = atan(-n->x[0]/n->x[2]); 1159 cout << Verbose(1) << "Z-X-angle: " << alpha << " ... "; 1160 while (ptr->next != end) { 1161 ptr = ptr->next; 1162 tmp = ptr->x.x[0]; 1163 ptr->x.x[0] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2]; 1164 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2]; 1165 for (int j=0;j<MDSteps;j++) { 1166 tmp = Trajectories[ptr].R.at(j).x[0]; 1167 Trajectories[ptr].R.at(j).x[0] = cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2]; 1168 Trajectories[ptr].R.at(j).x[2] = -sin(alpha) * tmp + cos(alpha) * Trajectories[ptr].R.at(j).x[2]; 1169 } 1170 } 1171 // rotate n vector 1172 tmp = n->x[0]; 1173 n->x[0] = cos(alpha) * tmp + sin(alpha) * n->x[2]; 1174 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2]; 1175 cout << Verbose(1) << "alignment vector after first rotation: "; 1176 n->Output((ofstream *)&cout); 1177 cout << endl; 1178 1179 // rotate on z-y plane 1180 ptr = start; 1181 alpha = atan(-n->x[1]/n->x[2]); 1182 cout << Verbose(1) << "Z-Y-angle: " << alpha << " ... "; 1183 while (ptr->next != end) { 1184 ptr = ptr->next; 1185 tmp = ptr->x.x[1]; 1186 ptr->x.x[1] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2]; 1187 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2]; 1188 for (int j=0;j<MDSteps;j++) { 1189 tmp = Trajectories[ptr].R.at(j).x[1]; 1190 Trajectories[ptr].R.at(j).x[1] = cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2]; 1191 Trajectories[ptr].R.at(j).x[2] = -sin(alpha) * tmp + cos(alpha) * Trajectories[ptr].R.at(j).x[2]; 1192 } 1193 } 1194 // rotate n vector (for consistency check) 1195 tmp = n->x[1]; 1196 n->x[1] = cos(alpha) * tmp + sin(alpha) * n->x[2]; 1197 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2]; 1198 1199 cout << Verbose(1) << "alignment vector after second rotation: "; 1200 n->Output((ofstream *)&cout); 1201 cout << Verbose(1) << endl; 1202 cout << Verbose(0) << "End of Aligning all atoms." << endl; 1203 1203 }; 1204 1204 … … 1209 1209 bool molecule::RemoveAtom(atom *pointer) 1210 1210 { 1211 if (ElementsInMolecule[pointer->type->Z] != 0){ // this would indicate an error1212 ElementsInMolecule[pointer->type->Z]--;// decrease number of atom of this element1213 1214 1215 1216 if (ElementsInMolecule[pointer->type->Z] == 0)// was last atom of this element?1217 1218 1219 1211 if (ElementsInMolecule[pointer->type->Z] != 0) { // this would indicate an error 1212 ElementsInMolecule[pointer->type->Z]--; // decrease number of atom of this element 1213 AtomCount--; 1214 } else 1215 cerr << "ERROR: Atom " << pointer->Name << " is of element " << pointer->type->Z << " but the entry in the table of the molecule is 0!" << endl; 1216 if (ElementsInMolecule[pointer->type->Z] == 0) // was last atom of this element? 1217 ElementCount--; 1218 Trajectories.erase(pointer); 1219 return remove(pointer, start, end); 1220 1220 }; 1221 1221 … … 1244 1244 bool molecule::CleanupMolecule() 1245 1245 { 1246 1246 return (cleanup(start,end) && cleanup(first,last)); 1247 1247 }; 1248 1248 … … 1251 1251 * \return pointer to atom or NULL 1252 1252 */ 1253 atom * molecule::FindAtom(int Nr) 1254 1255 1256 1257 1258 1259 1260 1261 1253 atom * molecule::FindAtom(int Nr) const{ 1254 atom * walker = find(&Nr, start,end); 1255 if (walker != NULL) { 1256 //cout << Verbose(0) << "Found Atom Nr. " << walker->nr << endl; 1257 return walker; 1258 } else { 1259 cout << Verbose(0) << "Atom not found in list." << endl; 1260 return NULL; 1261 } 1262 1262 }; 1263 1263 … … 1267 1267 atom * molecule::AskAtom(string text) 1268 1268 { 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1269 int No; 1270 atom *ion = NULL; 1271 do { 1272 //cout << Verbose(0) << "============Atom list==========================" << endl; 1273 //mol->Output((ofstream *)&cout); 1274 //cout << Verbose(0) << "===============================================" << endl; 1275 cout << Verbose(0) << text; 1276 cin >> No; 1277 ion = this->FindAtom(No); 1278 } while (ion == NULL); 1279 return ion; 1280 1280 }; 1281 1281 … … 1286 1286 bool molecule::CheckBounds(const Vector *x) const 1287 1287 { 1288 1289 1290 1291 1292 1293 1294 1295 1288 bool result = true; 1289 int j =-1; 1290 for (int i=0;i<NDIM;i++) { 1291 j += i+1; 1292 result = result && ((x->x[i] >= 0) && (x->x[i] < cell_size[j])); 1293 } 1294 //return result; 1295 return true; /// probably not gonna use the check no more 1296 1296 }; 1297 1297 … … 1303 1303 double LeastSquareDistance (const gsl_vector * x, void * params) 1304 1304 { 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 c.CopyVector(&ptr->x);// copy vector to temporary one1322 c.SubtractVector(&a);// subtract offset vector1323 t = c.ScalarProduct(&b);// get direction parameter1324 d.CopyVector(&b);// and create vector1325 1326 c.SubtractVector(&d);// ... yielding distance vector1327 res += d.ScalarProduct((const Vector *)&d);// add squared distance1328 1329 1330 1305 double res = 0, t; 1306 Vector a,b,c,d; 1307 struct lsq_params *par = (struct lsq_params *)params; 1308 atom *ptr = par->mol->start; 1309 1310 // initialize vectors 1311 a.x[0] = gsl_vector_get(x,0); 1312 a.x[1] = gsl_vector_get(x,1); 1313 a.x[2] = gsl_vector_get(x,2); 1314 b.x[0] = gsl_vector_get(x,3); 1315 b.x[1] = gsl_vector_get(x,4); 1316 b.x[2] = gsl_vector_get(x,5); 1317 // go through all atoms 1318 while (ptr != par->mol->end) { 1319 ptr = ptr->next; 1320 if (ptr->type == ((struct lsq_params *)params)->type) { // for specific type 1321 c.CopyVector(&ptr->x); // copy vector to temporary one 1322 c.SubtractVector(&a); // subtract offset vector 1323 t = c.ScalarProduct(&b); // get direction parameter 1324 d.CopyVector(&b); // and create vector 1325 d.Scale(&t); 1326 c.SubtractVector(&d); // ... yielding distance vector 1327 res += d.ScalarProduct((const Vector *)&d); // add squared distance 1328 } 1329 } 1330 return res; 1331 1331 }; 1332 1332 … … 1336 1336 void molecule::GetAlignvector(struct lsq_params * par) const 1337 1337 { 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 gsl_vector_set (par->x, 0, 0.0);// offset1361 1362 1363 gsl_vector_set (par->x, 3, 0.0);// direction1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1338 int np = 6; 1339 1340 const gsl_multimin_fminimizer_type *T = 1341 gsl_multimin_fminimizer_nmsimplex; 1342 gsl_multimin_fminimizer *s = NULL; 1343 gsl_vector *ss; 1344 gsl_multimin_function minex_func; 1345 1346 size_t iter = 0, i; 1347 int status; 1348 double size; 1349 1350 /* Initial vertex size vector */ 1351 ss = gsl_vector_alloc (np); 1352 1353 /* Set all step sizes to 1 */ 1354 gsl_vector_set_all (ss, 1.0); 1355 1356 /* Starting point */ 1357 par->x = gsl_vector_alloc (np); 1358 par->mol = this; 1359 1360 gsl_vector_set (par->x, 0, 0.0); // offset 1361 gsl_vector_set (par->x, 1, 0.0); 1362 gsl_vector_set (par->x, 2, 0.0); 1363 gsl_vector_set (par->x, 3, 0.0); // direction 1364 gsl_vector_set (par->x, 4, 0.0); 1365 gsl_vector_set (par->x, 5, 1.0); 1366 1367 /* Initialize method and iterate */ 1368 minex_func.f = &LeastSquareDistance; 1369 minex_func.n = np; 1370 minex_func.params = (void *)par; 1371 1372 s = gsl_multimin_fminimizer_alloc (T, np); 1373 gsl_multimin_fminimizer_set (s, &minex_func, par->x, ss); 1374 1375 do 1376 { 1377 iter++; 1378 status = gsl_multimin_fminimizer_iterate(s); 1379 1380 if (status) 1381 break; 1382 1383 size = gsl_multimin_fminimizer_size (s); 1384 status = gsl_multimin_test_size (size, 1e-2); 1385 1386 if (status == GSL_SUCCESS) 1387 { 1388 printf ("converged to minimum at\n"); 1389 } 1390 1391 printf ("%5d ", (int)iter); 1392 for (i = 0; i < (size_t)np; i++) 1393 { 1394 printf ("%10.3e ", gsl_vector_get (s->x, i)); 1395 } 1396 printf ("f() = %7.3f size = %.3f\n", s->fval, size); 1397 } 1398 while (status == GSL_CONTINUE && iter < 100); 1399 1400 for (i=0;i<(size_t)np;i++) 1401 gsl_vector_set(par->x, i, gsl_vector_get(s->x, i)); 1402 //gsl_vector_free(par->x); 1403 gsl_vector_free(ss); 1404 gsl_multimin_fminimizer_free (s); 1405 1405 }; 1406 1406 … … 1410 1410 bool molecule::Output(ofstream *out) 1411 1411 { 1412 1413 1414 1415 1416 1417 1418 1419 1420 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2]MoveType (0 MoveIon, 1 FixedIon)" << endl;1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1412 element *runner; 1413 atom *walker = NULL; 1414 int ElementNo, AtomNo; 1415 CountElements(); 1416 1417 if (out == NULL) { 1418 return false; 1419 } else { 1420 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl; 1421 ElementNo = 0; 1422 runner = elemente->start; 1423 while (runner->next != elemente->end) { // go through every element 1424 runner = runner->next; 1425 if (ElementsInMolecule[runner->Z]) { // if this element got atoms 1426 ElementNo++; 1427 AtomNo = 0; 1428 walker = start; 1429 while (walker->next != end) { // go through every atom of this element 1430 walker = walker->next; 1431 if (walker->type == runner) { // if this atom fits to element 1432 AtomNo++; 1433 walker->Output(ElementNo, AtomNo, out); // removed due to trajectories 1434 } 1435 } 1436 } 1437 } 1438 return true; 1439 } 1440 1440 }; 1441 1441 … … 1445 1445 bool molecule::OutputTrajectories(ofstream *out) 1446 1446 { 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2]MoveType (0 MoveIon, 1 FixedIon)" << endl;1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 *out << "Ion_Type" << ElementNo << "_" << AtomNo << "\t"<< fixed << setprecision(9) << showpoint;1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1447 element *runner = NULL; 1448 atom *walker = NULL; 1449 int ElementNo, AtomNo; 1450 CountElements(); 1451 1452 if (out == NULL) { 1453 return false; 1454 } else { 1455 for (int step = 0; step < MDSteps; step++) { 1456 if (step == 0) { 1457 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl; 1458 } else { 1459 *out << "# ====== MD step " << step << " =========" << endl; 1460 } 1461 ElementNo = 0; 1462 runner = elemente->start; 1463 while (runner->next != elemente->end) { // go through every element 1464 runner = runner->next; 1465 if (ElementsInMolecule[runner->Z]) { // if this element got atoms 1466 ElementNo++; 1467 AtomNo = 0; 1468 walker = start; 1469 while (walker->next != end) { // go through every atom of this element 1470 walker = walker->next; 1471 if (walker->type == runner) { // if this atom fits to element 1472 AtomNo++; 1473 *out << "Ion_Type" << ElementNo << "_" << AtomNo << "\t" << fixed << setprecision(9) << showpoint; 1474 *out << Trajectories[walker].R.at(step).x[0] << "\t" << Trajectories[walker].R.at(step).x[1] << "\t" << Trajectories[walker].R.at(step).x[2]; 1475 *out << "\t" << walker->FixedIon; 1476 if (Trajectories[walker].U.at(step).Norm() > MYEPSILON) 1477 *out << "\t" << scientific << setprecision(6) << Trajectories[walker].U.at(step).x[0] << "\t" << Trajectories[walker].U.at(step).x[1] << "\t" << Trajectories[walker].U.at(step).x[2] << "\t"; 1478 if (Trajectories[walker].F.at(step).Norm() > MYEPSILON) 1479 *out << "\t" << scientific << setprecision(6) << Trajectories[walker].F.at(step).x[0] << "\t" << Trajectories[walker].F.at(step).x[1] << "\t" << Trajectories[walker].F.at(step).x[2] << "\t"; 1480 *out << "\t# Number in molecule " << walker->nr << endl; 1481 } 1482 } 1483 } 1484 } 1485 } 1486 return true; 1487 } 1488 1488 }; 1489 1489 … … 1493 1493 void molecule::OutputListOfBonds(ofstream *out) const 1494 1494 { 1495 1496 1497 1498 1495 *out << Verbose(2) << endl << "From Contents of ListOfBondsPerAtom, all non-hydrogen atoms:" << endl; 1496 atom *Walker = start; 1497 while (Walker->next != end) { 1498 Walker = Walker->next; 1499 1499 #ifdef ADDHYDROGEN 1500 if (Walker->type->Z != 1) {// regard only non-hydrogen1500 if (Walker->type->Z != 1) { // regard only non-hydrogen 1501 1501 #endif 1502 1503 1504 1505 1502 *out << Verbose(2) << "Atom " << Walker->Name << " has Bonds: "<<endl; 1503 for(int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) { 1504 *out << Verbose(3) << *(ListOfBondsPerAtom)[Walker->nr][j] << endl; 1505 } 1506 1506 #ifdef ADDHYDROGEN 1507 1507 } 1508 1508 #endif 1509 1510 1509 } 1510 *out << endl; 1511 1511 }; 1512 1512 … … 1514 1514 * \param *out stream pointer 1515 1515 */ 1516 bool molecule::Checkout(ofstream *out) 1517 { 1518 1516 bool molecule::Checkout(ofstream *out) const 1517 { 1518 return elemente->Checkout(out, ElementsInMolecule); 1519 1519 }; 1520 1520 … … 1524 1524 bool molecule::OutputTrajectoriesXYZ(ofstream *out) 1525 1525 { 1526 1527 1528 1529 1530 now = time((time_t *)NULL);// Get the system time and put it into 'now' as 'calender time'1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1526 atom *walker = NULL; 1527 int No = 0; 1528 time_t now; 1529 1530 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time' 1531 walker = start; 1532 while (walker->next != end) { // go through every atom and count 1533 walker = walker->next; 1534 No++; 1535 } 1536 if (out != NULL) { 1537 for (int step=0;step<MDSteps;step++) { 1538 *out << No << "\n\tCreated by molecuilder, step " << step << ", on " << ctime(&now); 1539 walker = start; 1540 while (walker->next != end) { // go through every atom of this element 1541 walker = walker->next; 1542 *out << walker->type->symbol << "\t" << Trajectories[walker].R.at(step).x[0] << "\t" << Trajectories[walker].R.at(step).x[1] << "\t" << Trajectories[walker].R.at(step).x[2] << endl; 1543 } 1544 } 1545 return true; 1546 } else 1547 return false; 1548 1548 }; 1549 1549 … … 1553 1553 bool molecule::OutputXYZ(ofstream *out) const 1554 1554 { 1555 1556 1557 1558 1559 1560 now = time((time_t *)NULL);// Get the system time and put it into 'now' as 'calender time'1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1555 atom *walker = NULL; 1556 int AtomNo = 0, ElementNo; 1557 time_t now; 1558 element *runner = NULL; 1559 1560 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time' 1561 walker = start; 1562 while (walker->next != end) { // go through every atom and count 1563 walker = walker->next; 1564 AtomNo++; 1565 } 1566 if (out != NULL) { 1567 *out << AtomNo << "\n\tCreated by molecuilder on " << ctime(&now); 1568 ElementNo = 0; 1569 runner = elemente->start; 1570 while (runner->next != elemente->end) { // go through every element 1571 runner = runner->next; 1572 if (ElementsInMolecule[runner->Z]) { // if this element got atoms 1573 ElementNo++; 1574 walker = start; 1575 while (walker->next != end) { // go through every atom of this element 1576 walker = walker->next; 1577 if (walker->type == runner) { // if this atom fits to element 1578 walker->OutputXYZLine(out); 1579 } 1580 } 1581 } 1582 } 1583 return true; 1584 } else 1585 return false; 1586 1586 }; 1587 1587 … … 1591 1591 void molecule::CountAtoms(ofstream *out) 1592 1592 { 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 Walker->nr = i;// update number in molecule (for easier referencing in FragmentMolecule lateron)1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1593 int i = 0; 1594 atom *Walker = start; 1595 while (Walker->next != end) { 1596 Walker = Walker->next; 1597 i++; 1598 } 1599 if ((AtomCount == 0) || (i != AtomCount)) { 1600 *out << Verbose(3) << "Mismatch in AtomCount " << AtomCount << " and recounted number " << i << ", renaming all." << endl; 1601 AtomCount = i; 1602 1603 // count NonHydrogen atoms and give each atom a unique name 1604 if (AtomCount != 0) { 1605 i=0; 1606 NoNonHydrogen = 0; 1607 Walker = start; 1608 while (Walker->next != end) { 1609 Walker = Walker->next; 1610 Walker->nr = i; // update number in molecule (for easier referencing in FragmentMolecule lateron) 1611 if (Walker->type->Z != 1) // count non-hydrogen atoms whilst at it 1612 NoNonHydrogen++; 1613 Free((void **)&Walker->Name, "molecule::CountAtoms: *walker->Name"); 1614 Walker->Name = (char *) Malloc(sizeof(char)*6, "molecule::CountAtoms: *walker->Name"); 1615 sprintf(Walker->Name, "%2s%02d", Walker->type->symbol, Walker->nr+1); 1616 *out << "Naming atom nr. " << Walker->nr << " " << Walker->Name << "." << endl; 1617 i++; 1618 } 1619 } else 1620 *out << Verbose(3) << "AtomCount is still " << AtomCount << ", thus counting nothing." << endl; 1621 } 1622 1622 }; 1623 1623 … … 1626 1626 void molecule::CountElements() 1627 1627 { 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1628 int i = 0; 1629 for(i=MAX_ELEMENTS;i--;) 1630 ElementsInMolecule[i] = 0; 1631 ElementCount = 0; 1632 1633 atom *walker = start; 1634 while (walker->next != end) { 1635 walker = walker->next; 1636 ElementsInMolecule[walker->type->Z]++; 1637 i++; 1638 } 1639 for(i=MAX_ELEMENTS;i--;) 1640 ElementCount += (ElementsInMolecule[i] != 0 ? 1 : 0); 1641 1641 }; 1642 1642 … … 1648 1648 int molecule::CountCyclicBonds(ofstream *out) 1649 1649 { 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1650 int No = 0; 1651 int *MinimumRingSize = NULL; 1652 MoleculeLeafClass *Subgraphs = NULL; 1653 class StackClass<bond *> *BackEdgeStack = NULL; 1654 bond *Binder = first; 1655 if ((Binder->next != last) && (Binder->next->Type == Undetermined)) { 1656 *out << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl; 1657 Subgraphs = DepthFirstSearchAnalysis(out, BackEdgeStack); 1658 while (Subgraphs->next != NULL) { 1659 Subgraphs = Subgraphs->next; 1660 delete(Subgraphs->previous); 1661 } 1662 delete(Subgraphs); 1663 delete[](MinimumRingSize); 1664 } 1665 while(Binder->next != last) { 1666 Binder = Binder->next; 1667 if (Binder->Cyclic) 1668 No++; 1669 } 1670 delete(BackEdgeStack); 1671 return No; 1672 1672 }; 1673 1673 /** Returns Shading as a char string. … … 1677 1677 string molecule::GetColor(enum Shading color) 1678 1678 { 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1679 switch(color) { 1680 case white: 1681 return "white"; 1682 break; 1683 case lightgray: 1684 return "lightgray"; 1685 break; 1686 case darkgray: 1687 return "darkgray"; 1688 break; 1689 case black: 1690 return "black"; 1691 break; 1692 default: 1693 return "uncolored"; 1694 break; 1695 }; 1696 1696 }; 1697 1697 … … 1702 1702 void molecule::CalculateOrbitals(class config &configuration) 1703 1703 { 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1704 configuration.MaxPsiDouble = configuration.PsiMaxNoDown = configuration.PsiMaxNoUp = configuration.PsiType = 0; 1705 for(int i=MAX_ELEMENTS;i--;) { 1706 if (ElementsInMolecule[i] != 0) { 1707 //cout << "CalculateOrbitals: " << elemente->FindElement(i)->name << " has a valence of " << (int)elemente->FindElement(i)->Valence << " and there are " << ElementsInMolecule[i] << " of it." << endl; 1708 configuration.MaxPsiDouble += ElementsInMolecule[i]*((int)elemente->FindElement(i)->Valence); 1709 } 1710 } 1711 configuration.PsiMaxNoDown = configuration.MaxPsiDouble/2 + (configuration.MaxPsiDouble % 2); 1712 configuration.PsiMaxNoUp = configuration.MaxPsiDouble/2; 1713 configuration.MaxPsiDouble /= 2; 1714 configuration.PsiType = (configuration.PsiMaxNoDown == configuration.PsiMaxNoUp) ? 0 : 1; 1715 if ((configuration.PsiType == 1) && (configuration.ProcPEPsi < 2)) { 1716 configuration.ProcPEGamma /= 2; 1717 configuration.ProcPEPsi *= 2; 1718 } else { 1719 configuration.ProcPEGamma *= configuration.ProcPEPsi; 1720 configuration.ProcPEPsi = 1; 1721 } 1722 configuration.InitMaxMinStopStep = configuration.MaxMinStopStep = configuration.MaxPsiDouble; 1723 1723 }; 1724 1724 … … 1729 1729 { 1730 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1731 // 1 We will parse bonds out of the dbond file created by tremolo. 1732 int atom1, atom2, temp; 1733 atom *Walker, *OtherWalker; 1734 1735 if (!input) 1736 { 1737 cout << Verbose(1) << "Opening silica failed \n"; 1738 }; 1739 1740 *input >> ws >> atom1; 1741 *input >> ws >> atom2; 1742 cout << Verbose(1) << "Scanning file\n"; 1743 while (!input->eof()) // Check whether we read everything already 1744 { 1745 *input >> ws >> atom1; 1746 *input >> ws >> atom2; 1747 if(atom2<atom1) //Sort indices of atoms in order 1748 { 1749 temp=atom1; 1750 atom1=atom2; 1751 atom2=temp; 1752 }; 1753 1754 Walker=start; 1755 while(Walker-> nr != atom1) // Find atom corresponding to first index 1756 { 1757 Walker = Walker->next; 1758 }; 1759 OtherWalker = Walker->next; 1760 while(OtherWalker->nr != atom2) // Find atom corresponding to second index 1761 { 1762 OtherWalker= OtherWalker->next; 1763 }; 1764 AddBond(Walker, OtherWalker); //Add the bond between the two atoms with respective indices. 1765 1766 } 1767 1768 CreateListOfBondsPerAtom(out); 1769 1769 1770 1770 }; … … 1777 1777 * To make it O(N log N) the function uses the linked-cell technique as follows: 1778 1778 * The procedure is step-wise: 1779 * 1780 * 1781 * 1782 * 1783 * 1784 * 1785 * 1786 * 1779 * -# Remove every bond in list 1780 * -# Count the atoms in the molecule with CountAtoms() 1781 * -# partition cell into smaller linked cells of size \a bonddistance 1782 * -# put each atom into its corresponding cell 1783 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true 1784 * -# create the list of bonds via CreateListOfBondsPerAtom() 1785 * -# correct the bond degree iteratively (single->double->triple bond) 1786 * -# finally print the bond list to \a *out if desired 1787 1787 * \param *out out stream for printing the matrix, NULL if no output 1788 1788 * \param bonddistance length of linked cells (i.e. maximum minimal length checked) … … 1792 1792 { 1793 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 if ((first->next != last) && (last->previous != first)) {// there are bonds present1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 //*out << Verbose(1) << "divisor[" << i << "]= " << divisor[i] << "." << endl;1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 if (CellList[index] == NULL)// allocate molecule if not done1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 while (Walker->next != CellList[Index]->end) {// go through every atom1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 if (CellList[index] != NULL) {// if there are any atoms in this cell1876 1877 while(OtherWalker->next != CellList[index]->end) {// go through every atom in this cell1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 AddBond(Walker->father, OtherWalker->father, 1);// also increases molecule::BondCount1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1794 atom *Walker = NULL, *OtherWalker = NULL, *Candidate = NULL; 1795 int No, NoBonds, CandidateBondNo; 1796 int NumberCells, divisor[NDIM], n[NDIM], N[NDIM], index, Index, j; 1797 molecule **CellList; 1798 double distance, MinDistance, MaxDistance; 1799 double *matrix = ReturnFullMatrixforSymmetric(cell_size); 1800 Vector x; 1801 int FalseBondDegree = 0; 1802 1803 BondDistance = bonddistance; // * ((IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem); 1804 *out << Verbose(0) << "Begin of CreateAdjacencyList." << endl; 1805 // remove every bond from the list 1806 if ((first->next != last) && (last->previous != first)) { // there are bonds present 1807 cleanup(first,last); 1808 } 1809 1810 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering) 1811 CountAtoms(out); 1812 *out << Verbose(1) << "AtomCount " << AtomCount << "." << endl; 1813 1814 if (AtomCount != 0) { 1815 // 1. find divisor for each axis, such that a sphere with radius of at least bonddistance can be placed into each cell 1816 j=-1; 1817 for (int i=0;i<NDIM;i++) { 1818 j += i+1; 1819 divisor[i] = (int)floor(cell_size[j]/bonddistance); // take smaller value such that size of linked cell is at least bonddistance 1820 //*out << Verbose(1) << "divisor[" << i << "] = " << divisor[i] << "." << endl; 1821 } 1822 // 2a. allocate memory for the cell list 1823 NumberCells = divisor[0]*divisor[1]*divisor[2]; 1824 *out << Verbose(1) << "Allocating " << NumberCells << " cells." << endl; 1825 CellList = (molecule **) Malloc(sizeof(molecule *)*NumberCells, "molecule::CreateAdjacencyList - ** CellList"); 1826 for (int i=NumberCells;i--;) 1827 CellList[i] = NULL; 1828 1829 // 2b. put all atoms into its corresponding list 1830 Walker = start; 1831 while(Walker->next != end) { 1832 Walker = Walker->next; 1833 //*out << Verbose(1) << "Current atom is " << *Walker << " with coordinates "; 1834 //Walker->x.Output(out); 1835 //*out << "." << endl; 1836 // compute the cell by the atom's coordinates 1837 j=-1; 1838 for (int i=0;i<NDIM;i++) { 1839 j += i+1; 1840 x.CopyVector(&(Walker->x)); 1841 x.KeepPeriodic(out, matrix); 1842 n[i] = (int)floor(x.x[i]/cell_size[j]*(double)divisor[i]); 1843 } 1844 index = n[2] + (n[1] + n[0] * divisor[1]) * divisor[2]; 1845 //*out << Verbose(1) << "Atom " << *Walker << " goes into cell number [" << n[0] << "," << n[1] << "," << n[2] << "] = " << index << "." << endl; 1846 // add copy atom to this cell 1847 if (CellList[index] == NULL) // allocate molecule if not done 1848 CellList[index] = new molecule(elemente); 1849 OtherWalker = CellList[index]->AddCopyAtom(Walker); // add a copy of walker to this atom, father will be walker for later reference 1850 //*out << Verbose(1) << "Copy Atom is " << *OtherWalker << "." << endl; 1851 } 1852 //for (int i=0;i<NumberCells;i++) 1853 //*out << Verbose(1) << "Cell number " << i << ": " << CellList[i] << "." << endl; 1854 1855 1856 // 3a. go through every cell 1857 for (N[0]=divisor[0];N[0]--;) 1858 for (N[1]=divisor[1];N[1]--;) 1859 for (N[2]=divisor[2];N[2]--;) { 1860 Index = N[2] + (N[1] + N[0] * divisor[1]) * divisor[2]; 1861 if (CellList[Index] != NULL) { // if there atoms in this cell 1862 //*out << Verbose(1) << "Current cell is " << Index << "." << endl; 1863 // 3b. for every atom therein 1864 Walker = CellList[Index]->start; 1865 while (Walker->next != CellList[Index]->end) { // go through every atom 1866 Walker = Walker->next; 1867 //*out << Verbose(0) << "Current Atom is " << *Walker << "." << endl; 1868 // 3c. check for possible bond between each atom in this and every one in the 27 cells 1869 for (n[0]=-1;n[0]<=1;n[0]++) 1870 for (n[1]=-1;n[1]<=1;n[1]++) 1871 for (n[2]=-1;n[2]<=1;n[2]++) { 1872 // compute the index of this comparison cell and make it periodic 1873 index = ((N[2]+n[2]+divisor[2])%divisor[2]) + (((N[1]+n[1]+divisor[1])%divisor[1]) + ((N[0]+n[0]+divisor[0])%divisor[0]) * divisor[1]) * divisor[2]; 1874 //*out << Verbose(1) << "Number of comparison cell is " << index << "." << endl; 1875 if (CellList[index] != NULL) { // if there are any atoms in this cell 1876 OtherWalker = CellList[index]->start; 1877 while(OtherWalker->next != CellList[index]->end) { // go through every atom in this cell 1878 OtherWalker = OtherWalker->next; 1879 //*out << Verbose(0) << "Current comparison atom is " << *OtherWalker << "." << endl; 1880 /// \todo periodic check is missing here! 1881 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl; 1882 MinDistance = OtherWalker->type->CovalentRadius + Walker->type->CovalentRadius; 1883 MinDistance *= (IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem; 1884 MaxDistance = MinDistance + BONDTHRESHOLD; 1885 MinDistance -= BONDTHRESHOLD; 1886 distance = OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size); 1887 if ((OtherWalker->father->nr > Walker->father->nr) && (distance <= MaxDistance*MaxDistance) && (distance >= MinDistance*MinDistance)) { // create bond if distance is smaller 1888 //*out << Verbose(1) << "Adding Bond between " << *Walker << " and " << *OtherWalker << " in distance " << sqrt(distance) << "." << endl; 1889 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount 1890 } else { 1891 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl; 1892 } 1893 } 1894 } 1895 } 1896 } 1897 } 1898 } 1899 1900 1901 1902 // 4. free the cell again 1903 for (int i=NumberCells;i--;) 1904 if (CellList[i] != NULL) { 1905 delete(CellList[i]); 1906 } 1907 Free((void **)&CellList, "molecule::CreateAdjacencyList - ** CellList"); 1908 1909 // create the adjacency list per atom 1910 CreateListOfBondsPerAtom(out); 1911 1912 // correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees, 1913 // iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene 1914 // preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of 1915 // double bonds as was expected. 1916 if (BondCount != 0) { 1917 NoCyclicBonds = 0; 1918 *out << Verbose(1) << "Correcting Bond degree of each bond ... "; 1919 do { 1920 No = 0; // No acts as breakup flag (if 1 we still continue) 1921 Walker = start; 1922 while (Walker->next != end) { // go through every atom 1923 Walker = Walker->next; 1924 // count valence of first partner 1925 NoBonds = 0; 1926 for(j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) 1927 NoBonds += ListOfBondsPerAtom[Walker->nr][j]->BondDegree; 1928 *out << Verbose(3) << "Walker " << *Walker << ": " << (int)Walker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl; 1929 if ((int)(Walker->type->NoValenceOrbitals) > NoBonds) { // we have a mismatch, check all bonding partners for mismatch 1930 Candidate = NULL; 1931 CandidateBondNo = -1; 1932 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through each of its bond partners 1933 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker); 1934 // count valence of second partner 1935 NoBonds = 0; 1936 for(j=0;j<NumberOfBondsPerAtom[OtherWalker->nr];j++) 1937 NoBonds += ListOfBondsPerAtom[OtherWalker->nr][j]->BondDegree; 1938 *out << Verbose(3) << "OtherWalker " << *OtherWalker << ": " << (int)OtherWalker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl; 1939 if ((int)(OtherWalker->type->NoValenceOrbitals) > NoBonds) { // check if possible candidate 1940 if ((Candidate == NULL) || (NumberOfBondsPerAtom[Candidate->nr] > NumberOfBondsPerAtom[OtherWalker->nr])) { // pick the one with fewer number of bonds first 1941 Candidate = OtherWalker; 1942 CandidateBondNo = i; 1943 *out << Verbose(3) << "New candidate is " << *Candidate << "." << endl; 1944 } 1945 } 1946 } 1947 if ((Candidate != NULL) && (CandidateBondNo != -1)) { 1948 ListOfBondsPerAtom[Walker->nr][CandidateBondNo]->BondDegree++; 1949 *out << Verbose(2) << "Increased bond degree for bond " << *ListOfBondsPerAtom[Walker->nr][CandidateBondNo] << "." << endl; 1950 } else 1951 *out << Verbose(2) << "Could not find correct degree for atom " << *Walker << "." << endl; 1952 FalseBondDegree++; 1953 } 1954 } 1955 } while (No); 1956 *out << " done." << endl; 1957 } else 1958 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl; 1959 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << bonddistance << ", " << FalseBondDegree << " bonds could not be corrected." << endl; 1960 1961 // output bonds for debugging (if bond chain list was correctly installed) 1962 *out << Verbose(1) << endl << "From contents of bond chain list:"; 1963 bond *Binder = first; 1964 while(Binder->next != last) { 1965 Binder = Binder->next; 1966 *out << *Binder << "\t" << endl; 1967 } 1968 *out << endl; 1969 } else 1970 *out << Verbose(1) << "AtomCount is " << AtomCount << ", thus no bonds, no connections!." << endl; 1971 *out << Verbose(0) << "End of CreateAdjacencyList." << endl; 1972 Free((void **)&matrix, "molecule::CreateAdjacencyList: *matrix"); 1973 1973 1974 1974 }; … … 1986 1986 MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, class StackClass<bond *> *&BackEdgeStack) 1987 1987 { 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 } while (1);// (3)2051 2052 2053 2054 2055 2056 } while (1);// (2)2057 2058 2059 2060 2061 2062 2063 2064 2065 // (6)(Ancestor of Walker is not Root)2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 if (!BackStepping) {// coming from (8) want to go to (3)2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 // (11) Root is separation vertex,set Walker to Root and go to (4)2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 *out << " ===";2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 1988 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount); 1989 BackEdgeStack = new StackClass<bond *> (BondCount); 1990 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL); 1991 MoleculeLeafClass *LeafWalker = SubGraphs; 1992 int CurrentGraphNr = 0, OldGraphNr; 1993 int ComponentNumber = 0; 1994 atom *Walker = NULL, *OtherAtom = NULL, *Root = start->next; 1995 bond *Binder = NULL; 1996 bool BackStepping = false; 1997 1998 *out << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl; 1999 2000 ResetAllBondsToUnused(); 2001 ResetAllAtomNumbers(); 2002 InitComponentNumbers(); 2003 BackEdgeStack->ClearStack(); 2004 while (Root != end) { // if there any atoms at all 2005 // (1) mark all edges unused, empty stack, set atom->GraphNr = 0 for all 2006 AtomStack->ClearStack(); 2007 2008 // put into new subgraph molecule and add this to list of subgraphs 2009 LeafWalker = new MoleculeLeafClass(LeafWalker); 2010 LeafWalker->Leaf = new molecule(elemente); 2011 LeafWalker->Leaf->AddCopyAtom(Root); 2012 2013 OldGraphNr = CurrentGraphNr; 2014 Walker = Root; 2015 do { // (10) 2016 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom 2017 if (!BackStepping) { // if we don't just return from (8) 2018 Walker->GraphNr = CurrentGraphNr; 2019 Walker->LowpointNr = CurrentGraphNr; 2020 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl; 2021 AtomStack->Push(Walker); 2022 CurrentGraphNr++; 2023 } 2024 do { // (3) if Walker has no unused egdes, go to (5) 2025 BackStepping = false; // reset backstepping flag for (8) 2026 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused 2027 Binder = FindNextUnused(Walker); 2028 if (Binder == NULL) 2029 break; 2030 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl; 2031 // (4) Mark Binder used, ... 2032 Binder->MarkUsed(black); 2033 OtherAtom = Binder->GetOtherAtom(Walker); 2034 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl; 2035 if (OtherAtom->GraphNr != -1) { 2036 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3) 2037 Binder->Type = BackEdge; 2038 BackEdgeStack->Push(Binder); 2039 Walker->LowpointNr = ( Walker->LowpointNr < OtherAtom->GraphNr ) ? Walker->LowpointNr : OtherAtom->GraphNr; 2040 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl; 2041 } else { 2042 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2) 2043 Binder->Type = TreeEdge; 2044 OtherAtom->Ancestor = Walker; 2045 Walker = OtherAtom; 2046 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl; 2047 break; 2048 } 2049 Binder = NULL; 2050 } while (1); // (3) 2051 if (Binder == NULL) { 2052 *out << Verbose(2) << "No more Unused Bonds." << endl; 2053 break; 2054 } else 2055 Binder = NULL; 2056 } while (1); // (2) 2057 2058 // if we came from backstepping, yet there were no more unused bonds, we end up here with no Ancestor, because Walker is Root! Then we are finished! 2059 if ((Walker == Root) && (Binder == NULL)) 2060 break; 2061 2062 // (5) if Ancestor of Walker is ... 2063 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl; 2064 if (Walker->Ancestor->GraphNr != Root->GraphNr) { 2065 // (6) (Ancestor of Walker is not Root) 2066 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) { 2067 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8) 2068 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr; 2069 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl; 2070 } else { 2071 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component 2072 Walker->Ancestor->SeparationVertex = true; 2073 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl; 2074 SetNextComponentNumber(Walker->Ancestor, ComponentNumber); 2075 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << ComponentNumber << "." << endl; 2076 SetNextComponentNumber(Walker, ComponentNumber); 2077 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << ComponentNumber << "." << endl; 2078 do { 2079 OtherAtom = AtomStack->PopLast(); 2080 LeafWalker->Leaf->AddCopyAtom(OtherAtom); 2081 SetNextComponentNumber(OtherAtom, ComponentNumber); 2082 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl; 2083 } while (OtherAtom != Walker); 2084 ComponentNumber++; 2085 } 2086 // (8) Walker becomes its Ancestor, go to (3) 2087 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl; 2088 Walker = Walker->Ancestor; 2089 BackStepping = true; 2090 } 2091 if (!BackStepping) { // coming from (8) want to go to (3) 2092 // (9) remove all from stack till Walker (including), these and Root form a component 2093 AtomStack->Output(out); 2094 SetNextComponentNumber(Root, ComponentNumber); 2095 *out << Verbose(3) << "(9) Root[" << Root->Name << "]'s Component is " << ComponentNumber << "." << endl; 2096 SetNextComponentNumber(Walker, ComponentNumber); 2097 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << ComponentNumber << "." << endl; 2098 do { 2099 OtherAtom = AtomStack->PopLast(); 2100 LeafWalker->Leaf->AddCopyAtom(OtherAtom); 2101 SetNextComponentNumber(OtherAtom, ComponentNumber); 2102 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl; 2103 } while (OtherAtom != Walker); 2104 ComponentNumber++; 2105 2106 // (11) Root is separation vertex, set Walker to Root and go to (4) 2107 Walker = Root; 2108 Binder = FindNextUnused(Walker); 2109 *out << Verbose(1) << "(10) Walker is Root[" << Root->Name << "], next Unused Bond is " << Binder << "." << endl; 2110 if (Binder != NULL) { // Root is separation vertex 2111 *out << Verbose(1) << "(11) Root is a separation vertex." << endl; 2112 Walker->SeparationVertex = true; 2113 } 2114 } 2115 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges 2116 2117 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph 2118 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << CurrentGraphNr << "." << endl; 2119 LeafWalker->Leaf->Output(out); 2120 *out << endl; 2121 2122 // step on to next root 2123 while ((Root != end) && (Root->GraphNr != -1)) { 2124 //*out << Verbose(1) << "Current next subgraph root candidate is " << Root->Name << "." << endl; 2125 if (Root->GraphNr != -1) // if already discovered, step on 2126 Root = Root->next; 2127 } 2128 } 2129 // set cyclic bond criterium on "same LP" basis 2130 Binder = first; 2131 while(Binder->next != last) { 2132 Binder = Binder->next; 2133 if (Binder->rightatom->LowpointNr == Binder->leftatom->LowpointNr) { // cyclic ?? 2134 Binder->Cyclic = true; 2135 NoCyclicBonds++; 2136 } 2137 } 2138 2139 2140 *out << Verbose(1) << "Final graph info for each atom is:" << endl; 2141 Walker = start; 2142 while (Walker->next != end) { 2143 Walker = Walker->next; 2144 *out << Verbose(2) << "Atom " << Walker->Name << " is " << ((Walker->SeparationVertex) ? "a" : "not a") << " separation vertex, components are "; 2145 OutputComponentNumber(out, Walker); 2146 *out << " with Lowpoint " << Walker->LowpointNr << " and Graph Nr. " << Walker->GraphNr << "." << endl; 2147 } 2148 2149 *out << Verbose(1) << "Final graph info for each bond is:" << endl; 2150 Binder = first; 2151 while(Binder->next != last) { 2152 Binder = Binder->next; 2153 *out << Verbose(2) << ((Binder->Type == TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <"; 2154 *out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp."; 2155 OutputComponentNumber(out, Binder->leftatom); 2156 *out << " === "; 2157 *out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp."; 2158 OutputComponentNumber(out, Binder->rightatom); 2159 *out << ">." << endl; 2160 if (Binder->Cyclic) // cyclic ?? 2161 *out << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl; 2162 } 2163 2164 // free all and exit 2165 delete(AtomStack); 2166 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl; 2167 return SubGraphs; 2168 2168 }; 2169 2169 … … 2178 2178 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond 2179 2179 */ 2180 void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * 2181 { 2182 2183 2184 2185 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount);// will hold the current ring2186 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount);// contains all "touched" atoms (that need to be reset after BFS loop)2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 BFSStack->ClearStack();// start with empty BFS stack2211 2212 2213 2214 2215 do {// look for Root2216 2217 2218 2219 2220 2221 2180 void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize) 2181 { 2182 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList"); 2183 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList"); 2184 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CyclicStructureAnalysis: *ColorList"); 2185 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount); // will hold the current ring 2186 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount); // contains all "touched" atoms (that need to be reset after BFS loop) 2187 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL; 2188 bond *Binder = NULL, *BackEdge = NULL; 2189 int RingSize, NumCycles, MinRingSize = -1; 2190 2191 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray 2192 for (int i=AtomCount;i--;) { 2193 PredecessorList[i] = NULL; 2194 ShortestPathList[i] = -1; 2195 ColorList[i] = white; 2196 } 2197 2198 *out << Verbose(1) << "Back edge list - "; 2199 BackEdgeStack->Output(out); 2200 2201 *out << Verbose(1) << "Analysing cycles ... " << endl; 2202 NumCycles = 0; 2203 while (!BackEdgeStack->IsEmpty()) { 2204 BackEdge = BackEdgeStack->PopFirst(); 2205 // this is the target 2206 Root = BackEdge->leftatom; 2207 // this is the source point 2208 Walker = BackEdge->rightatom; 2209 ShortestPathList[Walker->nr] = 0; 2210 BFSStack->ClearStack(); // start with empty BFS stack 2211 BFSStack->Push(Walker); 2212 TouchedStack->Push(Walker); 2213 *out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl; 2214 OtherAtom = NULL; 2215 do { // look for Root 2216 Walker = BFSStack->PopFirst(); 2217 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl; 2218 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { 2219 Binder = ListOfBondsPerAtom[Walker->nr][i]; 2220 if (Binder != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder) 2221 OtherAtom = Binder->GetOtherAtom(Walker); 2222 2222 #ifdef ADDHYDROGEN 2223 2223 if (OtherAtom->type->Z != 1) { 2224 2224 #endif 2225 2226 2227 2228 2229 PredecessorList[OtherAtom->nr] = Walker;// Walker is the predecessor2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2225 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl; 2226 if (ColorList[OtherAtom->nr] == white) { 2227 TouchedStack->Push(OtherAtom); 2228 ColorList[OtherAtom->nr] = lightgray; 2229 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor 2230 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1; 2231 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl; 2232 //if (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance 2233 *out << Verbose(3) << "Putting OtherAtom into queue." << endl; 2234 BFSStack->Push(OtherAtom); 2235 //} 2236 } else { 2237 *out << Verbose(3) << "Not Adding, has already been visited." << endl; 2238 } 2239 if (OtherAtom == Root) 2240 break; 2241 2241 #ifdef ADDHYDROGEN 2242 2243 2244 2245 2242 } else { 2243 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl; 2244 ColorList[OtherAtom->nr] = black; 2245 } 2246 2246 #endif 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 if (!OtherAtom->GetTrueFather()->IsCyclic)// if one bond in the loop is not marked as cyclic, we haven't found this cycle yet2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 TouchedStack->Push(OtherAtom);// last was wrongly popped2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 *out << Walker->Name << "with a length of " << RingSize << "." << endl << endl;2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 BFSStack->ClearStack();// start with empty BFS stack2326 2327 2328 2329 2330 while (OtherAtom != NULL) {// look for Root2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 PredecessorList[OtherAtom->nr] = Walker;// Walker is the predecessor2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2247 } else { 2248 *out << Verbose(2) << "Bond " << *Binder << " not Visiting, is the back edge." << endl; 2249 } 2250 } 2251 ColorList[Walker->nr] = black; 2252 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl; 2253 if (OtherAtom == Root) { // if we have found the root, check whether this cycle wasn't already found beforehand 2254 // step through predecessor list 2255 while (OtherAtom != BackEdge->rightatom) { 2256 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet 2257 break; 2258 else 2259 OtherAtom = PredecessorList[OtherAtom->nr]; 2260 } 2261 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already 2262 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl;\ 2263 do { 2264 OtherAtom = TouchedStack->PopLast(); 2265 if (PredecessorList[OtherAtom->nr] == Walker) { 2266 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl; 2267 PredecessorList[OtherAtom->nr] = NULL; 2268 ShortestPathList[OtherAtom->nr] = -1; 2269 ColorList[OtherAtom->nr] = white; 2270 BFSStack->RemoveItem(OtherAtom); 2271 } 2272 } while ((!TouchedStack->IsEmpty()) && (PredecessorList[OtherAtom->nr] == NULL)); 2273 TouchedStack->Push(OtherAtom); // last was wrongly popped 2274 OtherAtom = BackEdge->rightatom; // set to not Root 2275 } else 2276 OtherAtom = Root; 2277 } 2278 } while ((!BFSStack->IsEmpty()) && (OtherAtom != Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]))); 2279 2280 if (OtherAtom == Root) { 2281 // now climb back the predecessor list and thus find the cycle members 2282 NumCycles++; 2283 RingSize = 1; 2284 Root->GetTrueFather()->IsCyclic = true; 2285 *out << Verbose(1) << "Found ring contains: "; 2286 Walker = Root; 2287 while (Walker != BackEdge->rightatom) { 2288 *out << Walker->Name << " <-> "; 2289 Walker = PredecessorList[Walker->nr]; 2290 Walker->GetTrueFather()->IsCyclic = true; 2291 RingSize++; 2292 } 2293 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl; 2294 // walk through all and set MinimumRingSize 2295 Walker = Root; 2296 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize; 2297 while (Walker != BackEdge->rightatom) { 2298 Walker = PredecessorList[Walker->nr]; 2299 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr]) 2300 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize; 2301 } 2302 if ((RingSize < MinRingSize) || (MinRingSize == -1)) 2303 MinRingSize = RingSize; 2304 } else { 2305 *out << Verbose(1) << "No ring containing " << *Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl; 2306 } 2307 2308 // now clean the lists 2309 while (!TouchedStack->IsEmpty()){ 2310 Walker = TouchedStack->PopFirst(); 2311 PredecessorList[Walker->nr] = NULL; 2312 ShortestPathList[Walker->nr] = -1; 2313 ColorList[Walker->nr] = white; 2314 } 2315 } 2316 if (MinRingSize != -1) { 2317 // go over all atoms 2318 Root = start; 2319 while(Root->next != end) { 2320 Root = Root->next; 2321 2322 if (MinimumRingSize[Root->GetTrueFather()->nr] == AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is 2323 Walker = Root; 2324 ShortestPathList[Walker->nr] = 0; 2325 BFSStack->ClearStack(); // start with empty BFS stack 2326 BFSStack->Push(Walker); 2327 TouchedStack->Push(Walker); 2328 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl; 2329 OtherAtom = Walker; 2330 while (OtherAtom != NULL) { // look for Root 2331 Walker = BFSStack->PopFirst(); 2332 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl; 2333 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { 2334 Binder = ListOfBondsPerAtom[Walker->nr][i]; 2335 if ((Binder != BackEdge) || (NumberOfBondsPerAtom[Walker->nr] == 1)) { // only walk along DFS spanning tree (otherwise we always find SP of 1 being backedge Binder), but terminal hydrogens may be connected via backedge, hence extra check 2336 OtherAtom = Binder->GetOtherAtom(Walker); 2337 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl; 2338 if (ColorList[OtherAtom->nr] == white) { 2339 TouchedStack->Push(OtherAtom); 2340 ColorList[OtherAtom->nr] = lightgray; 2341 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor 2342 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1; 2343 //*out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl; 2344 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring 2345 MinimumRingSize[Root->GetTrueFather()->nr] = ShortestPathList[OtherAtom->nr]+MinimumRingSize[OtherAtom->GetTrueFather()->nr]; 2346 OtherAtom = NULL; //break; 2347 break; 2348 } else 2349 BFSStack->Push(OtherAtom); 2350 } else { 2351 //*out << Verbose(3) << "Not Adding, has already been visited." << endl; 2352 } 2353 } else { 2354 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl; 2355 } 2356 } 2357 ColorList[Walker->nr] = black; 2358 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl; 2359 } 2360 2361 // now clean the lists 2362 while (!TouchedStack->IsEmpty()){ 2363 Walker = TouchedStack->PopFirst(); 2364 PredecessorList[Walker->nr] = NULL; 2365 ShortestPathList[Walker->nr] = -1; 2366 ColorList[Walker->nr] = white; 2367 } 2368 } 2369 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl; 2370 } 2371 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl; 2372 } else 2373 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl; 2374 2375 Free((void **)&PredecessorList, "molecule::CyclicStructureAnalysis: **PredecessorList"); 2376 Free((void **)&ShortestPathList, "molecule::CyclicStructureAnalysis: **ShortestPathList"); 2377 Free((void **)&ColorList, "molecule::CyclicStructureAnalysis: **ColorList"); 2378 delete(BFSStack); 2379 2379 }; 2380 2380 … … 2386 2386 void molecule::SetNextComponentNumber(atom *vertex, int nr) 2387 2387 { 2388 2389 2390 2391 if (vertex->ComponentNr[i] == -1) {// check if not yet used2392 2393 2394 2395 2396 break;// breaking here will not cause error!2397 2398 2399 2400 2401 2388 int i=0; 2389 if (vertex != NULL) { 2390 for(;i<NumberOfBondsPerAtom[vertex->nr];i++) { 2391 if (vertex->ComponentNr[i] == -1) { // check if not yet used 2392 vertex->ComponentNr[i] = nr; 2393 break; 2394 } 2395 else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time 2396 break; // breaking here will not cause error! 2397 } 2398 if (i == NumberOfBondsPerAtom[vertex->nr]) 2399 cerr << "Error: All Component entries are already occupied!" << endl; 2400 } else 2401 cerr << "Error: Given vertex is NULL!" << endl; 2402 2402 }; 2403 2403 … … 2407 2407 void molecule::OutputComponentNumber(ofstream *out, atom *vertex) 2408 2408 { 2409 2410 *out << vertex->ComponentNr[i] << "";2409 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++) 2410 *out << vertex->ComponentNr[i] << " "; 2411 2411 }; 2412 2412 … … 2415 2415 void molecule::InitComponentNumbers() 2416 2416 { 2417 2418 2419 2420 2421 2422 2423 2424 2425 2417 atom *Walker = start; 2418 while(Walker->next != end) { 2419 Walker = Walker->next; 2420 if (Walker->ComponentNr != NULL) 2421 Free((void **)&Walker->ComponentNr, "molecule::InitComponentNumbers: **Walker->ComponentNr"); 2422 Walker->ComponentNr = (int *) Malloc(sizeof(int)*NumberOfBondsPerAtom[Walker->nr], "molecule::InitComponentNumbers: *Walker->ComponentNr"); 2423 for (int i=NumberOfBondsPerAtom[Walker->nr];i--;) 2424 Walker->ComponentNr[i] = -1; 2425 } 2426 2426 }; 2427 2427 … … 2432 2432 bond * molecule::FindNextUnused(atom *vertex) 2433 2433 { 2434 2435 2436 2437 2434 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++) 2435 if (ListOfBondsPerAtom[vertex->nr][i]->IsUsed() == white) 2436 return(ListOfBondsPerAtom[vertex->nr][i]); 2437 return NULL; 2438 2438 }; 2439 2439 … … 2443 2443 void molecule::ResetAllBondsToUnused() 2444 2444 { 2445 2446 2447 2448 2449 2445 bond *Binder = first; 2446 while (Binder->next != last) { 2447 Binder = Binder->next; 2448 Binder->ResetUsed(); 2449 } 2450 2450 }; 2451 2451 … … 2454 2454 void molecule::ResetAllAtomNumbers() 2455 2455 { 2456 2457 2458 2459 Walker->GraphNr= -1;2460 2456 atom *Walker = start; 2457 while (Walker->next != end) { 2458 Walker = Walker->next; 2459 Walker->GraphNr = -1; 2460 } 2461 2461 }; 2462 2462 … … 2467 2467 void OutputAlreadyVisited(ofstream *out, int *list) 2468 2468 { 2469 2470 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << "";2471 2469 *out << Verbose(4) << "Already Visited Bonds:\t"; 2470 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << " "; 2471 *out << endl; 2472 2472 }; 2473 2473 … … 2475 2475 * The upper limit is 2476 2476 * \f[ 2477 * 2477 * n = N \cdot C^k 2478 2478 * \f] 2479 2479 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms. … … 2484 2484 int molecule::GuesstimateFragmentCount(ofstream *out, int order) 2485 2485 { 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2486 int c = 0; 2487 int FragmentCount; 2488 // get maximum bond degree 2489 atom *Walker = start; 2490 while (Walker->next != end) { 2491 Walker = Walker->next; 2492 c = (NumberOfBondsPerAtom[Walker->nr] > c) ? NumberOfBondsPerAtom[Walker->nr] : c; 2493 } 2494 FragmentCount = NoNonHydrogen*(1 << (c*order)); 2495 *out << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl; 2496 return FragmentCount; 2497 2497 }; 2498 2498 … … 2505 2505 bool molecule::ScanBufferIntoKeySet(ofstream *out, char *buffer, KeySet &CurrentSet) 2506 2506 { 2507 2508 2509 2510 2511 2512 2513 2514 2515 CurrentSet.insert(AtomNr);// insert at end, hence in same order as in file!2516 2517 2518 2519 2520 2521 2522 2523 2524 2507 stringstream line; 2508 int AtomNr; 2509 int status = 0; 2510 2511 line.str(buffer); 2512 while (!line.eof()) { 2513 line >> AtomNr; 2514 if ((AtomNr >= 0) && (AtomNr < AtomCount)) { 2515 CurrentSet.insert(AtomNr); // insert at end, hence in same order as in file! 2516 status++; 2517 } // else it's "-1" or else and thus must not be added 2518 } 2519 *out << Verbose(1) << "The scanned KeySet is "; 2520 for(KeySet::iterator runner = CurrentSet.begin(); runner != CurrentSet.end(); runner++) { 2521 *out << (*runner) << "\t"; 2522 } 2523 *out << endl; 2524 return (status != 0); 2525 2525 }; 2526 2526 … … 2537 2537 bool molecule::ParseKeySetFile(ofstream *out, char *path, Graph *&FragmentList) 2538 2538 { 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 if ((strlen(buffer) > 0) && (ScanBufferIntoKeySet(out, buffer, CurrentSet))) {// if at least one valid atom was added, write config2563 testGraphInsert = FragmentList->insert(GraphPair (CurrentSet,pair<int,double>(NumberOfFragments++,1)));// store fragment number and current factor2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2539 bool status = true; 2540 ifstream InputFile; 2541 stringstream line; 2542 GraphTestPair testGraphInsert; 2543 int NumberOfFragments = 0; 2544 double TEFactor; 2545 char *filename = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - filename"); 2546 2547 if (FragmentList == NULL) { // check list pointer 2548 FragmentList = new Graph; 2549 } 2550 2551 // 1st pass: open file and read 2552 *out << Verbose(1) << "Parsing the KeySet file ... " << endl; 2553 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, KEYSETFILE); 2554 InputFile.open(filename); 2555 if (InputFile != NULL) { 2556 // each line represents a new fragment 2557 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - *buffer"); 2558 // 1. parse keysets and insert into temp. graph 2559 while (!InputFile.eof()) { 2560 InputFile.getline(buffer, MAXSTRINGSIZE); 2561 KeySet CurrentSet; 2562 if ((strlen(buffer) > 0) && (ScanBufferIntoKeySet(out, buffer, CurrentSet))) { // if at least one valid atom was added, write config 2563 testGraphInsert = FragmentList->insert(GraphPair (CurrentSet,pair<int,double>(NumberOfFragments++,1))); // store fragment number and current factor 2564 if (!testGraphInsert.second) { 2565 cerr << "KeySet file must be corrupt as there are two equal key sets therein!" << endl; 2566 } 2567 } 2568 } 2569 // 2. Free and done 2570 InputFile.close(); 2571 InputFile.clear(); 2572 Free((void **)&buffer, "molecule::ParseKeySetFile - *buffer"); 2573 *out << Verbose(1) << "done." << endl; 2574 } else { 2575 *out << Verbose(1) << "File " << filename << " not found." << endl; 2576 status = false; 2577 } 2578 2579 // 2nd pass: open TEFactors file and read 2580 *out << Verbose(1) << "Parsing the TEFactors file ... " << endl; 2581 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, TEFACTORSFILE); 2582 InputFile.open(filename); 2583 if (InputFile != NULL) { 2584 // 3. add found TEFactors to each keyset 2585 NumberOfFragments = 0; 2586 for(Graph::iterator runner = FragmentList->begin();runner != FragmentList->end(); runner++) { 2587 if (!InputFile.eof()) { 2588 InputFile >> TEFactor; 2589 (*runner).second.second = TEFactor; 2590 *out << Verbose(2) << "Setting " << ++NumberOfFragments << " fragment's TEFactor to " << (*runner).second.second << "." << endl; 2591 } else { 2592 status = false; 2593 break; 2594 } 2595 } 2596 // 4. Free and done 2597 InputFile.close(); 2598 *out << Verbose(1) << "done." << endl; 2599 } else { 2600 *out << Verbose(1) << "File " << filename << " not found." << endl; 2601 status = false; 2602 } 2603 2604 // free memory 2605 Free((void **)&filename, "molecule::ParseKeySetFile - filename"); 2606 2607 return status; 2608 2608 }; 2609 2609 … … 2616 2616 bool molecule::StoreKeySetFile(ofstream *out, Graph &KeySetList, char *path) 2617 2617 { 2618 2619 bool status =true;2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2618 ofstream output; 2619 bool status = true; 2620 string line; 2621 2622 // open KeySet file 2623 line = path; 2624 line.append("/"); 2625 line += FRAGMENTPREFIX; 2626 line += KEYSETFILE; 2627 output.open(line.c_str(), ios::out); 2628 *out << Verbose(1) << "Saving key sets of the total graph ... "; 2629 if(output != NULL) { 2630 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) { 2631 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) { 2632 if (sprinter != (*runner).first.begin()) 2633 output << "\t"; 2634 output << *sprinter; 2635 } 2636 output << endl; 2637 } 2638 *out << "done." << endl; 2639 } else { 2640 cerr << "Unable to open " << line << " for writing keysets!" << endl; 2641 status = false; 2642 } 2643 output.close(); 2644 output.clear(); 2645 2646 // open TEFactors file 2647 line = path; 2648 line.append("/"); 2649 line += FRAGMENTPREFIX; 2650 line += TEFACTORSFILE; 2651 output.open(line.c_str(), ios::out); 2652 *out << Verbose(1) << "Saving TEFactors of the total graph ... "; 2653 if(output != NULL) { 2654 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) 2655 output << (*runner).second.second << endl; 2656 *out << Verbose(1) << "done." << endl; 2657 } else { 2658 *out << Verbose(1) << "failed to open " << line << "." << endl; 2659 status = false; 2660 } 2661 output.close(); 2662 2663 return status; 2664 2664 }; 2665 2665 … … 2672 2672 bool molecule::StoreAdjacencyToFile(ofstream *out, char *path) 2673 2673 { 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2674 ofstream AdjacencyFile; 2675 atom *Walker = NULL; 2676 stringstream line; 2677 bool status = true; 2678 2679 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE; 2680 AdjacencyFile.open(line.str().c_str(), ios::out); 2681 *out << Verbose(1) << "Saving adjacency list ... "; 2682 if (AdjacencyFile != NULL) { 2683 Walker = start; 2684 while(Walker->next != end) { 2685 Walker = Walker->next; 2686 AdjacencyFile << Walker->nr << "\t"; 2687 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) 2688 AdjacencyFile << ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker)->nr << "\t"; 2689 AdjacencyFile << endl; 2690 } 2691 AdjacencyFile.close(); 2692 *out << Verbose(1) << "done." << endl; 2693 } else { 2694 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl; 2695 status = false; 2696 } 2697 2698 return status; 2699 2699 }; 2700 2700 … … 2707 2707 bool molecule::CheckAdjacencyFileAgainstMolecule(ofstream *out, char *path, atom **ListOfAtoms) 2708 2708 { 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 int NonMatchNumber = 0;// will number of atoms with differing bond structure2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2709 ifstream File; 2710 stringstream filename; 2711 bool status = true; 2712 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer"); 2713 2714 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE; 2715 File.open(filename.str().c_str(), ios::out); 2716 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... "; 2717 if (File != NULL) { 2718 // allocate storage structure 2719 int NonMatchNumber = 0; // will number of atoms with differing bond structure 2720 int *CurrentBonds = (int *) Malloc(sizeof(int)*8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom 2721 int CurrentBondsOfAtom; 2722 2723 // Parse the file line by line and count the bonds 2724 while (!File.eof()) { 2725 File.getline(buffer, MAXSTRINGSIZE); 2726 stringstream line; 2727 line.str(buffer); 2728 int AtomNr = -1; 2729 line >> AtomNr; 2730 CurrentBondsOfAtom = -1; // we count one too far due to line end 2731 // parse into structure 2732 if ((AtomNr >= 0) && (AtomNr < AtomCount)) { 2733 while (!line.eof()) 2734 line >> CurrentBonds[ ++CurrentBondsOfAtom ]; 2735 // compare against present bonds 2736 //cout << Verbose(2) << "Walker is " << *Walker << ", bond partners: "; 2737 if (CurrentBondsOfAtom == NumberOfBondsPerAtom[AtomNr]) { 2738 for(int i=0;i<NumberOfBondsPerAtom[AtomNr];i++) { 2739 int id = ListOfBondsPerAtom[AtomNr][i]->GetOtherAtom(ListOfAtoms[AtomNr])->nr; 2740 int j = 0; 2741 for (;(j<CurrentBondsOfAtom) && (CurrentBonds[j++] != id);); // check against all parsed bonds 2742 if (CurrentBonds[j-1] != id) { // no match ? Then mark in ListOfAtoms 2743 ListOfAtoms[AtomNr] = NULL; 2744 NonMatchNumber++; 2745 status = false; 2746 //out << "[" << id << "]\t"; 2747 } else { 2748 //out << id << "\t"; 2749 } 2750 } 2751 //out << endl; 2752 } else { 2753 *out << "Number of bonds for Atom " << *ListOfAtoms[AtomNr] << " does not match, parsed " << CurrentBondsOfAtom << " against " << NumberOfBondsPerAtom[AtomNr] << "." << endl; 2754 status = false; 2755 } 2756 } 2757 } 2758 File.close(); 2759 File.clear(); 2760 if (status) { // if equal we parse the KeySetFile 2761 *out << Verbose(1) << "done: Equal." << endl; 2762 status = true; 2763 } else 2764 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl; 2765 Free((void **)&CurrentBonds, "molecule::CheckAdjacencyFileAgainstMolecule - **CurrentBonds"); 2766 } else { 2767 *out << Verbose(1) << "Adjacency file not found." << endl; 2768 status = false; 2769 } 2770 *out << endl; 2771 Free((void **)&buffer, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer"); 2772 2773 return status; 2774 2774 }; 2775 2775 … … 2785 2785 bool molecule::CheckOrderAtSite(ofstream *out, bool *AtomMask, Graph *GlobalKeySetList, int Order, int *MinimumRingSize, char *path) 2786 2786 { 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 if (AtomMask[AtomCount] == true)// break after one step2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 //*out << Verbose(2) << "Scanned " << lines-1 << " lines." << endl;// one endline too much2817 2818 2819 map<int, pair<double,int> > AdaptiveCriteriaList;// (Root No., (Value, Order)) !2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 No -= 1;// indices start at 1 in file, not 02835 2836 2837 2838 map<int,KeySet>::iterator marker = IndexKeySetList.find(No);// find keyset to Frag No.2839 if (marker != IndexKeySetList.end()) {// if found2840 Value *= 1 + MYEPSILON*(*((*marker).second.begin()));// in case of equal energies this makes em not equal without changing anything actually2841 2842 2843 2844 2845 if ((*PresentItem).second.second < FragOrder)// if order there is lower, update entry with higher-order term2846 //if ((*PresentItem).second.first < (*runner).first)// as higher-order terms are not always better, we skip this part (which would always include this site into adaptive increase)2847 {// if value is smaller, update value and order2848 2849 2850 *out << Verbose(2) << "Updated element (" <<(*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;2851 2852 *out << Verbose(2) << "Did not update element " <<(*PresentItem).first << " as " << FragOrder << " is less than or equal to " << (*PresentItem).second.second << "." << endl;2853 2854 2855 *out << Verbose(2) << "Inserted element (" <<(*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 AtomMask[Walker->nr] = true;// include all (non-hydrogen) atoms2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 AtomMask[Walker->nr] = true;// include all (non-hydrogen) atoms2916 2917 2918 2919 2920 if ((Order == 0) && (AtomMask[AtomCount] == false))// single stepping, just check2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 *out << "";2933 2934 2935 2936 2937 2938 2939 2940 2787 atom *Walker = start; 2788 bool status = false; 2789 ifstream InputFile; 2790 2791 // initialize mask list 2792 for(int i=AtomCount;i--;) 2793 AtomMask[i] = false; 2794 2795 if (Order < 0) { // adaptive increase of BondOrder per site 2796 if (AtomMask[AtomCount] == true) // break after one step 2797 return false; 2798 // parse the EnergyPerFragment file 2799 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckOrderAtSite: *buffer"); 2800 sprintf(buffer, "%s/%s%s.dat", path, FRAGMENTPREFIX, ENERGYPERFRAGMENT); 2801 InputFile.open(buffer, ios::in); 2802 if ((InputFile != NULL) && (GlobalKeySetList != NULL)) { 2803 // transmorph graph keyset list into indexed KeySetList 2804 map<int,KeySet> IndexKeySetList; 2805 for(Graph::iterator runner = GlobalKeySetList->begin(); runner != GlobalKeySetList->end(); runner++) { 2806 IndexKeySetList.insert( pair<int,KeySet>(runner->second.first,runner->first) ); 2807 } 2808 int lines = 0; 2809 // count the number of lines, i.e. the number of fragments 2810 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines 2811 InputFile.getline(buffer, MAXSTRINGSIZE); 2812 while(!InputFile.eof()) { 2813 InputFile.getline(buffer, MAXSTRINGSIZE); 2814 lines++; 2815 } 2816 //*out << Verbose(2) << "Scanned " << lines-1 << " lines." << endl; // one endline too much 2817 InputFile.clear(); 2818 InputFile.seekg(ios::beg); 2819 map<int, pair<double,int> > AdaptiveCriteriaList; // (Root No., (Value, Order)) ! 2820 int No, FragOrder; 2821 double Value; 2822 // each line represents a fragment root (Atom::nr) id and its energy contribution 2823 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines 2824 InputFile.getline(buffer, MAXSTRINGSIZE); 2825 while(!InputFile.eof()) { 2826 InputFile.getline(buffer, MAXSTRINGSIZE); 2827 if (strlen(buffer) > 2) { 2828 //*out << Verbose(2) << "Scanning: " << buffer << endl; 2829 stringstream line(buffer); 2830 line >> FragOrder; 2831 line >> ws >> No; 2832 line >> ws >> Value; // skip time entry 2833 line >> ws >> Value; 2834 No -= 1; // indices start at 1 in file, not 0 2835 //*out << Verbose(2) << " - yields (" << No << "," << Value << ", " << FragOrder << ")" << endl; 2836 2837 // clean the list of those entries that have been superceded by higher order terms already 2838 map<int,KeySet>::iterator marker = IndexKeySetList.find(No); // find keyset to Frag No. 2839 if (marker != IndexKeySetList.end()) { // if found 2840 Value *= 1 + MYEPSILON*(*((*marker).second.begin())); // in case of equal energies this makes em not equal without changing anything actually 2841 // as the smallest number in each set has always been the root (we use global id to keep the doubles away), seek smallest and insert into AtomMask 2842 pair <map<int, pair<double,int> >::iterator, bool> InsertedElement = AdaptiveCriteriaList.insert( make_pair(*((*marker).second.begin()), pair<double,int>( fabs(Value), FragOrder) )); 2843 map<int, pair<double,int> >::iterator PresentItem = InsertedElement.first; 2844 if (!InsertedElement.second) { // this root is already present 2845 if ((*PresentItem).second.second < FragOrder) // if order there is lower, update entry with higher-order term 2846 //if ((*PresentItem).second.first < (*runner).first) // as higher-order terms are not always better, we skip this part (which would always include this site into adaptive increase) 2847 { // if value is smaller, update value and order 2848 (*PresentItem).second.first = fabs(Value); 2849 (*PresentItem).second.second = FragOrder; 2850 *out << Verbose(2) << "Updated element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl; 2851 } else { 2852 *out << Verbose(2) << "Did not update element " << (*PresentItem).first << " as " << FragOrder << " is less than or equal to " << (*PresentItem).second.second << "." << endl; 2853 } 2854 } else { 2855 *out << Verbose(2) << "Inserted element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl; 2856 } 2857 } else { 2858 *out << Verbose(1) << "No Fragment under No. " << No << "found." << endl; 2859 } 2860 } 2861 } 2862 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones) 2863 map<double, pair<int,int> > FinalRootCandidates; 2864 *out << Verbose(1) << "Root candidate list is: " << endl; 2865 for(map<int, pair<double,int> >::iterator runner = AdaptiveCriteriaList.begin(); runner != AdaptiveCriteriaList.end(); runner++) { 2866 Walker = FindAtom((*runner).first); 2867 if (Walker != NULL) { 2868 //if ((*runner).second.second >= Walker->AdaptiveOrder) { // only insert if this is an "active" root site for the current order 2869 if (!Walker->MaxOrder) { 2870 *out << Verbose(2) << "(" << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "])" << endl; 2871 FinalRootCandidates.insert( make_pair( (*runner).second.first, pair<int,int>((*runner).first, (*runner).second.second) ) ); 2872 } else { 2873 *out << Verbose(2) << "Excluding (" << *Walker << ", " << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "]), as it has reached its maximum order." << endl; 2874 } 2875 } else { 2876 cerr << "Atom No. " << (*runner).second.first << " was not found in this molecule." << endl; 2877 } 2878 } 2879 // pick the ones still below threshold and mark as to be adaptively updated 2880 for(map<double, pair<int,int> >::iterator runner = FinalRootCandidates.upper_bound(pow(10.,Order)); runner != FinalRootCandidates.end(); runner++) { 2881 No = (*runner).second.first; 2882 Walker = FindAtom(No); 2883 //if (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr]) { 2884 *out << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", setting entry " << No << " of Atom mask to true." << endl; 2885 AtomMask[No] = true; 2886 status = true; 2887 //} else 2888 //*out << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", however MinimumRingSize of " << MinimumRingSize[Walker->nr] << " does not allow further adaptive increase." << endl; 2889 } 2890 // close and done 2891 InputFile.close(); 2892 InputFile.clear(); 2893 } else { 2894 cerr << "Unable to parse " << buffer << " file, incrementing all." << endl; 2895 while (Walker->next != end) { 2896 Walker = Walker->next; 2897 #ifdef ADDHYDROGEN 2898 if (Walker->type->Z != 1) // skip hydrogen 2899 #endif 2900 { 2901 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms 2902 status = true; 2903 } 2904 } 2905 } 2906 Free((void **)&buffer, "molecule::CheckOrderAtSite: *buffer"); 2907 // pick a given number of highest values and set AtomMask 2908 } else { // global increase of Bond Order 2909 while (Walker->next != end) { 2910 Walker = Walker->next; 2911 #ifdef ADDHYDROGEN 2912 if (Walker->type->Z != 1) // skip hydrogen 2913 #endif 2914 { 2915 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms 2916 if ((Order != 0) && (Walker->AdaptiveOrder < Order)) // && (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr])) 2917 status = true; 2918 } 2919 } 2920 if ((Order == 0) && (AtomMask[AtomCount] == false)) // single stepping, just check 2921 status = true; 2922 2923 if (!status) { 2924 if (Order == 0) 2925 *out << Verbose(1) << "Single stepping done." << endl; 2926 else 2927 *out << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl; 2928 } 2929 } 2930 2931 // print atom mask for debugging 2932 *out << " "; 2933 for(int i=0;i<AtomCount;i++) 2934 *out << (i % 10); 2935 *out << endl << "Atom mask is: "; 2936 for(int i=0;i<AtomCount;i++) 2937 *out << (AtomMask[i] ? "t" : "f"); 2938 *out << endl; 2939 2940 return status; 2941 2941 }; 2942 2942 … … 2948 2948 bool molecule::CreateMappingLabelsToConfigSequence(ofstream *out, int *&SortIndex) 2949 2949 { 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2950 element *runner = elemente->start; 2951 int AtomNo = 0; 2952 atom *Walker = NULL; 2953 2954 if (SortIndex != NULL) { 2955 *out << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl; 2956 return false; 2957 } 2958 SortIndex = (int *) Malloc(sizeof(int)*AtomCount, "molecule::FragmentMolecule: *SortIndex"); 2959 for(int i=AtomCount;i--;) 2960 SortIndex[i] = -1; 2961 while (runner->next != elemente->end) { // go through every element 2962 runner = runner->next; 2963 if (ElementsInMolecule[runner->Z]) { // if this element got atoms 2964 Walker = start; 2965 while (Walker->next != end) { // go through every atom of this element 2966 Walker = Walker->next; 2967 if (Walker->type->Z == runner->Z) // if this atom fits to element 2968 SortIndex[Walker->nr] = AtomNo++; 2969 } 2970 } 2971 } 2972 return true; 2973 2973 }; 2974 2974 … … 2979 2979 y contribution", and that's why this consciously not done in the following loop) 2980 2980 * -# in a loop over all subgraphs 2981 * 2982 * 2981 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure 2982 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet) 2983 2983 * -# combines the generated molecule lists from all subgraphs 2984 2984 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files … … 2993 2993 int molecule::FragmentMolecule(ofstream *out, int Order, config *configuration) 2994 2994 { 2995 2996 2997 2998 2999 3000 MoleculeLeafClass *Subgraphs = NULL;// list of subgraphs from DFS analysis3001 3002 3003 3004 3005 3006 3007 Graph TotalGraph;// graph with all keysets however local numbers3008 3009 3010 3011 3012 3013 2995 MoleculeListClass *BondFragments = NULL; 2996 int *SortIndex = NULL; 2997 int *MinimumRingSize = new int[AtomCount]; 2998 int FragmentCounter; 2999 MoleculeLeafClass *MolecularWalker = NULL; 3000 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis 3001 fstream File; 3002 bool FragmentationToDo = true; 3003 class StackClass<bond *> *BackEdgeStack = NULL, *LocalBackEdgeStack = NULL; 3004 bool CheckOrder = false; 3005 Graph **FragmentList = NULL; 3006 Graph *ParsedFragmentList = NULL; 3007 Graph TotalGraph; // graph with all keysets however local numbers 3008 int TotalNumberOfKeySets = 0; 3009 atom **ListOfAtoms = NULL; 3010 atom ***ListOfLocalAtoms = NULL; 3011 bool *AtomMask = NULL; 3012 3013 *out << endl; 3014 3014 #ifdef ADDHYDROGEN 3015 3015 *out << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl; 3016 3016 #else 3017 3017 *out << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl; 3018 3018 #endif 3019 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 Subgraphs->next->FillBondStructureFromReference(out, this, (FragmentCounter = 0), ListOfLocalAtoms, false);// we want to keep the created ListOfLocalAtoms3038 3039 3040 3041 3042 3043 3044 3045 3046 // 3047 // 3048 // 3049 // 3050 // 3051 // 3052 // 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 FragmentationToDo = false;// if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards3076 3077 3078 AtomMask[AtomCount] = true;// last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 //MolecularWalker->Leaf->OutputListOfBonds(out);// output ListOfBondsPerAtom for debugging3089 3090 3091 3092 3093 3094 3095 3096 FragmentCounter++;// next fragment list3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 //if (FragmentationToDo) {// we should always store the fragments again as coordination might have changed slightly without changing bond structure3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 //*out << Verbose(1) << "No fragments to store." << endl;3172 3173 3174 return ((int)(!FragmentationToDo)+1);// 1 - continue, 2 - stop (no fragmentation occured)3020 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++ 3021 3022 // ===== 1. Check whether bond structure is same as stored in files ==== 3023 3024 // fill the adjacency list 3025 CreateListOfBondsPerAtom(out); 3026 3027 // create lookup table for Atom::nr 3028 FragmentationToDo = FragmentationToDo && CreateFatherLookupTable(out, start, end, ListOfAtoms, AtomCount); 3029 3030 // === compare it with adjacency file === 3031 FragmentationToDo = FragmentationToDo && CheckAdjacencyFileAgainstMolecule(out, configuration->configpath, ListOfAtoms); 3032 Free((void **)&ListOfAtoms, "molecule::FragmentMolecule - **ListOfAtoms"); 3033 3034 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs ===== 3035 Subgraphs = DepthFirstSearchAnalysis(out, BackEdgeStack); 3036 // fill the bond structure of the individually stored subgraphs 3037 Subgraphs->next->FillBondStructureFromReference(out, this, (FragmentCounter = 0), ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms 3038 // analysis of the cycles (print rings, get minimum cycle length) for each subgraph 3039 for(int i=AtomCount;i--;) 3040 MinimumRingSize[i] = AtomCount; 3041 MolecularWalker = Subgraphs; 3042 FragmentCounter = 0; 3043 while (MolecularWalker->next != NULL) { 3044 MolecularWalker = MolecularWalker->next; 3045 LocalBackEdgeStack = new StackClass<bond *> (MolecularWalker->Leaf->BondCount); 3046 // // check the list of local atoms for debugging 3047 // *out << Verbose(0) << "ListOfLocalAtoms for this subgraph is:" << endl; 3048 // for (int i=0;i<AtomCount;i++) 3049 // if (ListOfLocalAtoms[FragmentCounter][i] == NULL) 3050 // *out << "\tNULL"; 3051 // else 3052 // *out << "\t" << ListOfLocalAtoms[FragmentCounter][i]->Name; 3053 *out << Verbose(0) << "Gathering local back edges for subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl; 3054 MolecularWalker->Leaf->PickLocalBackEdges(out, ListOfLocalAtoms[FragmentCounter++], BackEdgeStack, LocalBackEdgeStack); 3055 *out << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl; 3056 MolecularWalker->Leaf->CyclicStructureAnalysis(out, LocalBackEdgeStack, MinimumRingSize); 3057 *out << Verbose(0) << "Done with Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl; 3058 delete(LocalBackEdgeStack); 3059 } 3060 3061 // ===== 3. if structure still valid, parse key set file and others ===== 3062 FragmentationToDo = FragmentationToDo && ParseKeySetFile(out, configuration->configpath, ParsedFragmentList); 3063 3064 // ===== 4. check globally whether there's something to do actually (first adaptivity check) 3065 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(out, configuration->configpath); 3066 3067 // =================================== Begin of FRAGMENTATION =============================== 3068 // ===== 6a. assign each keyset to its respective subgraph ===== 3069 Subgraphs->next->AssignKeySetsToFragment(out, this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, (FragmentCounter = 0), true); 3070 3071 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle 3072 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()]; 3073 AtomMask = new bool[AtomCount+1]; 3074 AtomMask[AtomCount] = false; 3075 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards 3076 while ((CheckOrder = CheckOrderAtSite(out, AtomMask, ParsedFragmentList, Order, MinimumRingSize, configuration->configpath))) { 3077 FragmentationToDo = FragmentationToDo || CheckOrder; 3078 AtomMask[AtomCount] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite() 3079 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) ===== 3080 Subgraphs->next->FillRootStackForSubgraphs(out, RootStack, AtomMask, (FragmentCounter = 0)); 3081 3082 // ===== 7. fill the bond fragment list ===== 3083 FragmentCounter = 0; 3084 MolecularWalker = Subgraphs; 3085 while (MolecularWalker->next != NULL) { 3086 MolecularWalker = MolecularWalker->next; 3087 *out << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl; 3088 //MolecularWalker->Leaf->OutputListOfBonds(out); // output ListOfBondsPerAtom for debugging 3089 if (MolecularWalker->Leaf->first->next != MolecularWalker->Leaf->last) { 3090 // call BOSSANOVA method 3091 *out << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl; 3092 MolecularWalker->Leaf->FragmentBOSSANOVA(out, FragmentList[FragmentCounter], RootStack[FragmentCounter], MinimumRingSize); 3093 } else { 3094 cerr << "Subgraph " << MolecularWalker << " has no atoms!" << endl; 3095 } 3096 FragmentCounter++; // next fragment list 3097 } 3098 } 3099 delete[](RootStack); 3100 delete[](AtomMask); 3101 delete(ParsedFragmentList); 3102 delete[](MinimumRingSize); 3103 3104 3105 // ==================================== End of FRAGMENTATION ============================================ 3106 3107 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf) 3108 Subgraphs->next->TranslateIndicesToGlobalIDs(out, FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph); 3109 3110 // free subgraph memory again 3111 FragmentCounter = 0; 3112 if (Subgraphs != NULL) { 3113 while (Subgraphs->next != NULL) { 3114 Subgraphs = Subgraphs->next; 3115 delete(FragmentList[FragmentCounter++]); 3116 delete(Subgraphs->previous); 3117 } 3118 delete(Subgraphs); 3119 } 3120 Free((void **)&FragmentList, "molecule::FragmentMolecule - **FragmentList"); 3121 3122 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass ===== 3123 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure 3124 // allocate memory for the pointer array and transmorph graphs into full molecular fragments 3125 BondFragments = new MoleculeListClass(); 3126 int k=0; 3127 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) { 3128 KeySet test = (*runner).first; 3129 *out << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl; 3130 BondFragments->insert(StoreFragmentFromKeySet(out, test, configuration)); 3131 k++; 3132 } 3133 *out << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl; 3134 3135 // ===== 9. Save fragments' configuration and keyset files et al to disk === 3136 if (BondFragments->ListOfMolecules.size() != 0) { 3137 // create the SortIndex from BFS labels to order in the config file 3138 CreateMappingLabelsToConfigSequence(out, SortIndex); 3139 3140 *out << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl; 3141 if (BondFragments->OutputConfigForListOfFragments(out, configuration, SortIndex)) 3142 *out << Verbose(1) << "All configs written." << endl; 3143 else 3144 *out << Verbose(1) << "Some config writing failed." << endl; 3145 3146 // store force index reference file 3147 BondFragments->StoreForcesFile(out, configuration->configpath, SortIndex); 3148 3149 // store keysets file 3150 StoreKeySetFile(out, TotalGraph, configuration->configpath); 3151 3152 // store Adjacency file 3153 StoreAdjacencyToFile(out, configuration->configpath); 3154 3155 // store Hydrogen saturation correction file 3156 BondFragments->AddHydrogenCorrection(out, configuration->configpath); 3157 3158 // store adaptive orders into file 3159 StoreOrderAtSiteFile(out, configuration->configpath); 3160 3161 // restore orbital and Stop values 3162 CalculateOrbitals(*configuration); 3163 3164 // free memory for bond part 3165 *out << Verbose(1) << "Freeing bond memory" << endl; 3166 delete(FragmentList); // remove bond molecule from memory 3167 Free((void **)&SortIndex, "molecule::FragmentMolecule: *SortIndex"); 3168 } else 3169 *out << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl; 3170 //} else 3171 // *out << Verbose(1) << "No fragments to store." << endl; 3172 *out << Verbose(0) << "End of bond fragmentation." << endl; 3173 3174 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured) 3175 3175 }; 3176 3176 … … 3185 3185 bool molecule::PickLocalBackEdges(ofstream *out, atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack) 3186 3186 { 3187 3188 3189 3190 3191 3192 3193 bond *FirstBond = Binder;// mark the first bond, so that we don't loop through the stack indefinitely3194 3195 3196 3197 do {// go through all bonds and push local ones3198 Walker = ListOfLocalAtoms[Binder->leftatom->nr];// get one atom in the reference molecule3199 3200 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {// go through the local list of bonds3201 3202 3203 3204 3205 3206 3207 3208 Binder = ReferenceStack->PopFirst();// loop the stack for next item3209 3210 3211 3212 3213 3187 bool status = true; 3188 if (ReferenceStack->IsEmpty()) { 3189 cerr << "ReferenceStack is empty!" << endl; 3190 return false; 3191 } 3192 bond *Binder = ReferenceStack->PopFirst(); 3193 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely 3194 atom *Walker = NULL, *OtherAtom = NULL; 3195 ReferenceStack->Push(Binder); 3196 3197 do { // go through all bonds and push local ones 3198 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule 3199 if (Walker != NULL) // if this Walker exists in the subgraph ... 3200 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through the local list of bonds 3201 OtherAtom = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker); 3202 if (OtherAtom == ListOfLocalAtoms[Binder->rightatom->nr]) { // found the bond 3203 LocalStack->Push(ListOfBondsPerAtom[Walker->nr][i]); 3204 *out << Verbose(3) << "Found local edge " << *(ListOfBondsPerAtom[Walker->nr][i]) << "." << endl; 3205 break; 3206 } 3207 } 3208 Binder = ReferenceStack->PopFirst(); // loop the stack for next item 3209 *out << Verbose(3) << "Current candidate edge " << Binder << "." << endl; 3210 ReferenceStack->Push(Binder); 3211 } while (FirstBond != Binder); 3212 3213 return status; 3214 3214 }; 3215 3215 … … 3222 3222 bool molecule::StoreOrderAtSiteFile(ofstream *out, char *path) 3223 3223 { 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3224 stringstream line; 3225 ofstream file; 3226 3227 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE; 3228 file.open(line.str().c_str()); 3229 *out << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl; 3230 if (file != NULL) { 3231 atom *Walker = start; 3232 while (Walker->next != end) { 3233 Walker = Walker->next; 3234 file << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << endl; 3235 *out << Verbose(2) << "Storing: " << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << "." << endl; 3236 } 3237 file.close(); 3238 *out << Verbose(1) << "done." << endl; 3239 return true; 3240 } else { 3241 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl; 3242 return false; 3243 } 3244 3244 }; 3245 3245 … … 3253 3253 bool molecule::ParseOrderAtSiteFromFile(ofstream *out, char *path) 3254 3254 { 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 if (AtomNr != -1) {// test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3255 unsigned char *OrderArray = (unsigned char *) Malloc(sizeof(unsigned char)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *OrderArray"); 3256 bool *MaxArray = (bool *) Malloc(sizeof(bool)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *MaxArray"); 3257 bool status; 3258 int AtomNr, value; 3259 stringstream line; 3260 ifstream file; 3261 3262 *out << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl; 3263 for(int i=AtomCount;i--;) 3264 OrderArray[i] = 0; 3265 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE; 3266 file.open(line.str().c_str()); 3267 if (file != NULL) { 3268 for (int i=AtomCount;i--;) { // initialise with 0 3269 OrderArray[i] = 0; 3270 MaxArray[i] = 0; 3271 } 3272 while (!file.eof()) { // parse from file 3273 AtomNr = -1; 3274 file >> AtomNr; 3275 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time) 3276 file >> value; 3277 OrderArray[AtomNr] = value; 3278 file >> value; 3279 MaxArray[AtomNr] = value; 3280 //*out << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl; 3281 } 3282 } 3283 atom *Walker = start; 3284 while (Walker->next != end) { // fill into atom classes 3285 Walker = Walker->next; 3286 Walker->AdaptiveOrder = OrderArray[Walker->nr]; 3287 Walker->MaxOrder = MaxArray[Walker->nr]; 3288 *out << Verbose(2) << *Walker << " gets order " << (int)Walker->AdaptiveOrder << " and is " << (!Walker->MaxOrder ? "not " : " ") << "maxed." << endl; 3289 } 3290 file.close(); 3291 *out << Verbose(1) << "done." << endl; 3292 status = true; 3293 } else { 3294 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl; 3295 status = false; 3296 } 3297 Free((void **)&OrderArray, "molecule::ParseOrderAtSiteFromFile - *OrderArray"); 3298 Free((void **)&MaxArray, "molecule::ParseOrderAtSiteFromFile - *MaxArray"); 3299 3300 *out << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl; 3301 return status; 3302 3302 }; 3303 3303 … … 3310 3310 void molecule::CreateListOfBondsPerAtom(ofstream *out) 3311 3311 { 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3312 bond *Binder = NULL; 3313 atom *Walker = NULL; 3314 int TotalDegree; 3315 *out << Verbose(1) << "Begin of Creating ListOfBondsPerAtom: AtomCount = " << AtomCount << "\tBondCount = " << BondCount << "\tNoNonBonds = " << NoNonBonds << "." << endl; 3316 3317 // re-allocate memory 3318 *out << Verbose(2) << "(Re-)Allocating memory." << endl; 3319 if (ListOfBondsPerAtom != NULL) { 3320 for(int i=AtomCount;i--;) 3321 Free((void **)&ListOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom[i]"); 3322 Free((void **)&ListOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom"); 3323 } 3324 if (NumberOfBondsPerAtom != NULL) 3325 Free((void **)&NumberOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: NumberOfBondsPerAtom"); 3326 ListOfBondsPerAtom = (bond ***) Malloc(sizeof(bond **)*AtomCount, "molecule::CreateListOfBondsPerAtom: ***ListOfBondsPerAtom"); 3327 NumberOfBondsPerAtom = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfBondsPerAtom: *NumberOfBondsPerAtom"); 3328 3329 // reset bond counts per atom 3330 for(int i=AtomCount;i--;) 3331 NumberOfBondsPerAtom[i] = 0; 3332 // count bonds per atom 3333 Binder = first; 3334 while (Binder->next != last) { 3335 Binder = Binder->next; 3336 NumberOfBondsPerAtom[Binder->leftatom->nr]++; 3337 NumberOfBondsPerAtom[Binder->rightatom->nr]++; 3338 } 3339 for(int i=AtomCount;i--;) { 3340 // allocate list of bonds per atom 3341 ListOfBondsPerAtom[i] = (bond **) Malloc(sizeof(bond *)*NumberOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: **ListOfBondsPerAtom[]"); 3342 // clear the list again, now each NumberOfBondsPerAtom marks current free field 3343 NumberOfBondsPerAtom[i] = 0; 3344 } 3345 // fill the list 3346 Binder = first; 3347 while (Binder->next != last) { 3348 Binder = Binder->next; 3349 ListOfBondsPerAtom[Binder->leftatom->nr][NumberOfBondsPerAtom[Binder->leftatom->nr]++] = Binder; 3350 ListOfBondsPerAtom[Binder->rightatom->nr][NumberOfBondsPerAtom[Binder->rightatom->nr]++] = Binder; 3351 } 3352 3353 // output list for debugging 3354 *out << Verbose(3) << "ListOfBondsPerAtom for each atom:" << endl; 3355 Walker = start; 3356 while (Walker->next != end) { 3357 Walker = Walker->next; 3358 *out << Verbose(4) << "Atom " << Walker->Name << "/" << Walker->nr << " with " << NumberOfBondsPerAtom[Walker->nr] << " bonds: "; 3359 TotalDegree = 0; 3360 for (int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) { 3361 *out << *ListOfBondsPerAtom[Walker->nr][j] << "\t"; 3362 TotalDegree += ListOfBondsPerAtom[Walker->nr][j]->BondDegree; 3363 } 3364 *out << " -- TotalDegree: " << TotalDegree << endl; 3365 } 3366 *out << Verbose(1) << "End of Creating ListOfBondsPerAtom." << endl << endl; 3367 3367 }; 3368 3368 … … 3381 3381 void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem) 3382 3382 { 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 if (AddedAtomList[Root->nr] == NULL)// add Root if not yet present3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 PredecessorList[OtherAtom->nr] = Walker;// Walker is the predecessor3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 } else {// this code should actually never come into play (all white atoms are not yet present in BondMolecule, that's why they are white in the first place)3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3383 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList"); 3384 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList"); 3385 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList"); 3386 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount); 3387 atom *Walker = NULL, *OtherAtom = NULL; 3388 bond *Binder = NULL; 3389 3390 // add Root if not done yet 3391 AtomStack->ClearStack(); 3392 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present 3393 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root); 3394 AtomStack->Push(Root); 3395 3396 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray 3397 for (int i=AtomCount;i--;) { 3398 PredecessorList[i] = NULL; 3399 ShortestPathList[i] = -1; 3400 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited 3401 ColorList[i] = lightgray; 3402 else 3403 ColorList[i] = white; 3404 } 3405 ShortestPathList[Root->nr] = 0; 3406 3407 // and go on ... Queue always contains all lightgray vertices 3408 while (!AtomStack->IsEmpty()) { 3409 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance. 3410 // e.g. if current atom is 2, push to end of stack are of length 3, but first all of length 2 would be popped. They again 3411 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and 3412 // followed by n+1 till top of stack. 3413 Walker = AtomStack->PopFirst(); // pop oldest added 3414 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << NumberOfBondsPerAtom[Walker->nr] << " bonds." << endl; 3415 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { 3416 Binder = ListOfBondsPerAtom[Walker->nr][i]; 3417 if (Binder != NULL) { // don't look at bond equal NULL 3418 OtherAtom = Binder->GetOtherAtom(Walker); 3419 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl; 3420 if (ColorList[OtherAtom->nr] == white) { 3421 if (Binder != Bond) // let other atom white if it's via Root bond. In case it's cyclic it has to be reached again (yet Root is from OtherAtom already black, thus no problem) 3422 ColorList[OtherAtom->nr] = lightgray; 3423 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor 3424 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1; 3425 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " " << ((ColorList[OtherAtom->nr] == white) ? "white" : "lightgray") << ", its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl; 3426 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && (Binder != Bond))) ) { // Check for maximum distance 3427 *out << Verbose(3); 3428 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far 3429 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom); 3430 *out << "Added OtherAtom " << OtherAtom->Name; 3431 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree); 3432 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic; 3433 AddedBondList[Binder->nr]->Type = Binder->Type; 3434 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", "; 3435 } else { // this code should actually never come into play (all white atoms are not yet present in BondMolecule, that's why they are white in the first place) 3436 *out << "Not adding OtherAtom " << OtherAtom->Name; 3437 if (AddedBondList[Binder->nr] == NULL) { 3438 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree); 3439 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic; 3440 AddedBondList[Binder->nr]->Type = Binder->Type; 3441 *out << ", added Bond " << *(AddedBondList[Binder->nr]); 3442 } else 3443 *out << ", not added Bond "; 3444 } 3445 *out << ", putting OtherAtom into queue." << endl; 3446 AtomStack->Push(OtherAtom); 3447 } else { // out of bond order, then replace 3448 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic)) 3449 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic) 3450 if (Binder == Bond) 3451 *out << Verbose(3) << "Not Queueing, is the Root bond"; 3452 else if (ShortestPathList[OtherAtom->nr] >= BondOrder) 3453 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder; 3454 if (!Binder->Cyclic) 3455 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl; 3456 if (AddedBondList[Binder->nr] == NULL) { 3457 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate 3458 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree); 3459 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic; 3460 AddedBondList[Binder->nr]->Type = Binder->Type; 3461 } else { 3462 3462 #ifdef ADDHYDROGEN 3463 3464 3463 if (!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem)) 3464 exit(1); 3465 3465 #endif 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3466 } 3467 } 3468 } 3469 } else { 3470 *out << Verbose(3) << "Not Adding, has already been visited." << endl; 3471 // This has to be a cyclic bond, check whether it's present ... 3472 if (AddedBondList[Binder->nr] == NULL) { 3473 if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) { 3474 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree); 3475 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic; 3476 AddedBondList[Binder->nr]->Type = Binder->Type; 3477 } else { // if it's root bond it has to broken (otherwise we would not create the fragments) 3478 3478 #ifdef ADDHYDROGEN 3479 3480 3479 if(!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem)) 3480 exit(1); 3481 3481 #endif 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3482 } 3483 } 3484 } 3485 } 3486 } 3487 ColorList[Walker->nr] = black; 3488 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl; 3489 } 3490 Free((void **)&PredecessorList, "molecule::BreadthFirstSearchAdd: **PredecessorList"); 3491 Free((void **)&ShortestPathList, "molecule::BreadthFirstSearchAdd: **ShortestPathList"); 3492 Free((void **)&ColorList, "molecule::BreadthFirstSearchAdd: **ColorList"); 3493 delete(AtomStack); 3494 3494 }; 3495 3495 … … 3505 3505 bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father) 3506 3506 { 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father <<" is " << ParentList[Walker->father->nr] << "." << endl;3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3507 atom *Walker = NULL, *OtherAtom = NULL; 3508 bool status = true; 3509 atom **ParentList = (atom **) Malloc(sizeof(atom *)*Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList"); 3510 3511 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl; 3512 3513 // reset parent list 3514 *out << Verbose(3) << "Resetting ParentList." << endl; 3515 for (int i=Father->AtomCount;i--;) 3516 ParentList[i] = NULL; 3517 3518 // fill parent list with sons 3519 *out << Verbose(3) << "Filling Parent List." << endl; 3520 Walker = start; 3521 while (Walker->next != end) { 3522 Walker = Walker->next; 3523 ParentList[Walker->father->nr] = Walker; 3524 // Outputting List for debugging 3525 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl; 3526 } 3527 3528 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds 3529 *out << Verbose(3) << "Creating bonds." << endl; 3530 Walker = Father->start; 3531 while (Walker->next != Father->end) { 3532 Walker = Walker->next; 3533 if (ParentList[Walker->nr] != NULL) { 3534 if (ParentList[Walker->nr]->father != Walker) { 3535 status = false; 3536 } else { 3537 for (int i=0;i<Father->NumberOfBondsPerAtom[Walker->nr];i++) { 3538 OtherAtom = Father->ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker); 3539 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond 3540 *out << Verbose(4) << "Endpoints of Bond " << Father->ListOfBondsPerAtom[Walker->nr][i] << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl; 3541 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], Father->ListOfBondsPerAtom[Walker->nr][i]->BondDegree); 3542 } 3543 } 3544 } 3545 } 3546 } 3547 3548 Free((void **)&ParentList, "molecule::BuildInducedSubgraph: **ParentList"); 3549 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl; 3550 return status; 3551 3551 }; 3552 3552 … … 3560 3560 int molecule::LookForRemovalCandidate(ofstream *&out, KeySet *&Leaf, int *&ShortestPathList) 3561 3561 { 3562 3563 3564 3565 3566 SP = -1; //0;// not -1, so that Root is never removed3567 3568 3569 3570 3571 if (ShortestPathList[(*runner)] > SP) {// remove the oldest one with longest shortest path3572 3573 3574 3575 3576 3577 3562 atom *Runner = NULL; 3563 int SP, Removal; 3564 3565 *out << Verbose(2) << "Looking for removal candidate." << endl; 3566 SP = -1; //0; // not -1, so that Root is never removed 3567 Removal = -1; 3568 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) { 3569 Runner = FindAtom((*runner)); 3570 if (Runner->type->Z != 1) { // skip all those added hydrogens when re-filling snake stack 3571 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path 3572 SP = ShortestPathList[(*runner)]; 3573 Removal = (*runner); 3574 } 3575 } 3576 } 3577 return Removal; 3578 3578 }; 3579 3579 … … 3588 3588 molecule * molecule::StoreFragmentFromKeySet(ofstream *out, KeySet &Leaflet, bool IsAngstroem) 3589 3589 { 3590 3591 3592 3593 3594 3595 3596 // 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 FatherOfRunner = FindAtom((*runner));// find the id3610 3611 3612 3613 3614 3615 // 3616 3617 3618 3619 3620 3621 if (SonList[FatherOfRunner->nr] != NULL) {// check if this, our father, is present in list3622 3623 3624 3625 // 3626 3627 // 3628 3629 // 3630 // 3631 3632 // 3633 3634 3635 // 3636 3637 3638 3639 // 3590 atom *Runner = NULL, *FatherOfRunner = NULL, *OtherFather = NULL; 3591 atom **SonList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::StoreFragmentFromStack: **SonList"); 3592 molecule *Leaf = new molecule(elemente); 3593 bool LonelyFlag = false; 3594 int size; 3595 3596 // *out << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl; 3597 3598 Leaf->BondDistance = BondDistance; 3599 for(int i=NDIM*2;i--;) 3600 Leaf->cell_size[i] = cell_size[i]; 3601 3602 // initialise SonList (indicates when we need to replace a bond with hydrogen instead) 3603 for(int i=AtomCount;i--;) 3604 SonList[i] = NULL; 3605 3606 // first create the minimal set of atoms from the KeySet 3607 size = 0; 3608 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) { 3609 FatherOfRunner = FindAtom((*runner)); // find the id 3610 SonList[FatherOfRunner->nr] = Leaf->AddCopyAtom(FatherOfRunner); 3611 size++; 3612 } 3613 3614 // create the bonds between all: Make it an induced subgraph and add hydrogen 3615 // *out << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl; 3616 Runner = Leaf->start; 3617 while (Runner->next != Leaf->end) { 3618 Runner = Runner->next; 3619 LonelyFlag = true; 3620 FatherOfRunner = Runner->father; 3621 if (SonList[FatherOfRunner->nr] != NULL) { // check if this, our father, is present in list 3622 // create all bonds 3623 for (int i=0;i<NumberOfBondsPerAtom[FatherOfRunner->nr];i++) { // go through every bond of father 3624 OtherFather = ListOfBondsPerAtom[FatherOfRunner->nr][i]->GetOtherAtom(FatherOfRunner); 3625 // *out << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather; 3626 if (SonList[OtherFather->nr] != NULL) { 3627 // *out << ", whose son is " << *SonList[OtherFather->nr] << "." << endl; 3628 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba) 3629 // *out << Verbose(3) << "Adding Bond: "; 3630 // *out << 3631 Leaf->AddBond(Runner, SonList[OtherFather->nr], ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree); 3632 // *out << "." << endl; 3633 //NumBonds[Runner->nr]++; 3634 } else { 3635 // *out << Verbose(3) << "Not adding bond, labels in wrong order." << endl; 3636 } 3637 LonelyFlag = false; 3638 } else { 3639 // *out << ", who has no son in this fragment molecule." << endl; 3640 3640 #ifdef ADDHYDROGEN 3641 3642 3643 3641 //*out << Verbose(3) << "Adding Hydrogen to " << Runner->Name << " and a bond in between." << endl; 3642 if(!Leaf->AddHydrogenReplacementAtom(out, ListOfBondsPerAtom[FatherOfRunner->nr][i], Runner, FatherOfRunner, OtherFather, ListOfBondsPerAtom[FatherOfRunner->nr],NumberOfBondsPerAtom[FatherOfRunner->nr], IsAngstroem)) 3643 exit(1); 3644 3644 #endif 3645 3646 3647 3648 3649 3650 3651 3652 3653 3645 //NumBonds[Runner->nr] += ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree; 3646 } 3647 } 3648 } else { 3649 *out << Verbose(0) << "ERROR: Son " << Runner->Name << " has father " << FatherOfRunner->Name << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl; 3650 } 3651 if ((LonelyFlag) && (size > 1)) { 3652 *out << Verbose(0) << *Runner << "has got bonds only to hydrogens!" << endl; 3653 } 3654 3654 #ifdef ADDHYDROGEN 3655 3656 3655 while ((Runner->next != Leaf->end) && (Runner->next->type->Z == 1)) // skip added hydrogen 3656 Runner = Runner->next; 3657 3657 #endif 3658 3659 3660 3661 3662 // 3663 3658 } 3659 Leaf->CreateListOfBondsPerAtom(out); 3660 //Leaflet->Leaf->ScanForPeriodicCorrection(out); 3661 Free((void **)&SonList, "molecule::StoreFragmentFromStack: **SonList"); 3662 // *out << Verbose(1) << "End of StoreFragmentFromKeyset." << endl; 3663 return Leaf; 3664 3664 }; 3665 3665 … … 3667 3667 */ 3668 3668 struct UniqueFragments { 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3669 config *configuration; 3670 atom *Root; 3671 Graph *Leaflet; 3672 KeySet *FragmentSet; 3673 int ANOVAOrder; 3674 int FragmentCounter; 3675 int CurrentIndex; 3676 double TEFactor; 3677 int *ShortestPathList; 3678 bool **UsedList; 3679 bond **BondsPerSPList; 3680 int *BondsPerSPCount; 3681 3681 }; 3682 3682 3683 3683 /** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension. 3684 3684 * -# loops over every possible combination (2^dimension of edge set) 3685 * 3686 * 3685 * -# inserts current set, if there's still space left 3686 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist 3687 3687 ance+1 3688 * 3689 * 3688 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph 3689 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root 3690 3690 distance) and current set 3691 3691 * \param *out output stream for debugging … … 3697 3697 void molecule::SPFragmentGenerator(ofstream *out, struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder) 3698 3698 { 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 *out << Verbose(1+verbosity) << "We are " << RootDistance << " away from Root, which is " << *FragmentSearch->Root << ", SubOrder is " << SubOrder << ", SetDimension is " << SetDimension << " and this means " <<NumCombinations-1 << " combination(s)." << endl;3719 3720 3721 3722 for (TouchedIndex=SubOrder+1;TouchedIndex--;)// empty touched list3723 3724 3725 3726 3727 3728 for (int i=1;i<NumCombinations;i++) {// sweep through all power set combinations (skip empty set!)3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 for (int j=0;j<SetDimension;j++) {// pull out every bit by shifting3739 bit = ((i & (1 << j)) != 0);// mask the bit for the j-th bond3740 if (bit) {// if bit is set, we add this bond partner3741 OtherWalker = BondsSet[j]->rightatom;// rightatom is always the one more distant, i.e. the one to add3742 3743 3744 3745 3746 TouchedList[TouchedIndex++] = OtherWalker->nr;// note as added3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 if (SubOrder > 1) {// Due to Added above we have to check extra whether we're not already reaching beyond the desired Order3762 3763 SP = RootDistance+1;// this is the next level3764 3765 3766 Binder = FragmentSearch->BondsPerSPList[2*SP];// start node for this level3767 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) {// compare to end node of this level3768 3769 3770 if (Binder->Contains(TouchedList[k]))// if we added this very endpiece3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 if (Binder->leftatom->nr == TouchedList[k])// leftatom is always the close one3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3699 atom *OtherWalker = NULL; 3700 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder; 3701 int NumCombinations; 3702 bool bit; 3703 int bits, TouchedIndex, SubSetDimension, SP, Added; 3704 int Removal; 3705 int SpaceLeft; 3706 int *TouchedList = (int *) Malloc(sizeof(int)*(SubOrder+1), "molecule::SPFragmentGenerator: *TouchedList"); 3707 bond *Binder = NULL; 3708 bond **BondsList = NULL; 3709 KeySetTestPair TestKeySetInsert; 3710 3711 NumCombinations = 1 << SetDimension; 3712 3713 // Hier muessen von 1 bis NumberOfBondsPerAtom[Walker->nr] alle Kombinationen 3714 // von Endstuecken (aus den Bonds) hinzugefᅵᅵgt werden und fᅵᅵr verbleibende ANOVAOrder 3715 // rekursiv GraphCrawler in der nᅵᅵchsten Ebene aufgerufen werden 3716 3717 *out << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl; 3718 *out << Verbose(1+verbosity) << "We are " << RootDistance << " away from Root, which is " << *FragmentSearch->Root << ", SubOrder is " << SubOrder << ", SetDimension is " << SetDimension << " and this means " << NumCombinations-1 << " combination(s)." << endl; 3719 3720 // initialised touched list (stores added atoms on this level) 3721 *out << Verbose(1+verbosity) << "Clearing touched list." << endl; 3722 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list 3723 TouchedList[TouchedIndex] = -1; 3724 TouchedIndex = 0; 3725 3726 // create every possible combination of the endpieces 3727 *out << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl; 3728 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!) 3729 // count the set bit of i 3730 bits = 0; 3731 for (int j=SetDimension;j--;) 3732 bits += (i & (1 << j)) >> j; 3733 3734 *out << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl; 3735 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue 3736 // --1-- add this set of the power set of bond partners to the snake stack 3737 Added = 0; 3738 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting 3739 bit = ((i & (1 << j)) != 0); // mask the bit for the j-th bond 3740 if (bit) { // if bit is set, we add this bond partner 3741 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add 3742 //*out << Verbose(1+verbosity) << "Current Bond is " << ListOfBondsPerAtom[Walker->nr][i] << ", checking on " << *OtherWalker << "." << endl; 3743 *out << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl; 3744 TestKeySetInsert = FragmentSearch->FragmentSet->insert(OtherWalker->nr); 3745 if (TestKeySetInsert.second) { 3746 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added 3747 Added++; 3748 } else { 3749 *out << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl; 3750 } 3751 //FragmentSearch->UsedList[OtherWalker->nr][i] = true; 3752 //} 3753 } else { 3754 *out << Verbose(2+verbosity) << "Not adding." << endl; 3755 } 3756 } 3757 3758 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore 3759 if (SpaceLeft > 0) { 3760 *out << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl; 3761 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order 3762 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion 3763 SP = RootDistance+1; // this is the next level 3764 // first count the members in the subset 3765 SubSetDimension = 0; 3766 Binder = FragmentSearch->BondsPerSPList[2*SP]; // start node for this level 3767 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) { // compare to end node of this level 3768 Binder = Binder->next; 3769 for (int k=TouchedIndex;k--;) { 3770 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece 3771 SubSetDimension++; 3772 } 3773 } 3774 // then allocate and fill the list 3775 BondsList = (bond **) Malloc(sizeof(bond *)*SubSetDimension, "molecule::SPFragmentGenerator: **BondsList"); 3776 SubSetDimension = 0; 3777 Binder = FragmentSearch->BondsPerSPList[2*SP]; 3778 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) { 3779 Binder = Binder->next; 3780 for (int k=0;k<TouchedIndex;k++) { 3781 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one 3782 BondsList[SubSetDimension++] = Binder; 3783 } 3784 } 3785 *out << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl; 3786 SPFragmentGenerator(out, FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits); 3787 Free((void **)&BondsList, "molecule::SPFragmentGenerator: **BondsList"); 3788 } 3789 } else { 3790 // --2-- otherwise store the complete fragment 3791 *out << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl; 3792 // store fragment as a KeySet 3793 *out << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: "; 3794 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++) 3795 *out << (*runner) << " "; 3796 *out << endl; 3797 //if (!CheckForConnectedSubgraph(out, FragmentSearch->FragmentSet)) 3798 //*out << Verbose(0) << "ERROR: The found fragment is not a connected subgraph!" << endl; 3799 InsertFragmentIntoGraph(out, FragmentSearch); 3800 //Removal = LookForRemovalCandidate(out, FragmentSearch->FragmentSet, FragmentSearch->ShortestPathList); 3801 //Removal = StoreFragmentFromStack(out, FragmentSearch->Root, FragmentSearch->Leaflet, FragmentSearch->FragmentStack, FragmentSearch->ShortestPathList, &FragmentSearch->FragmentCounter, FragmentSearch->configuration); 3802 } 3803 3804 // --3-- remove all added items in this level from snake stack 3805 *out << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl; 3806 for(int j=0;j<TouchedIndex;j++) { 3807 Removal = TouchedList[j]; 3808 *out << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl; 3809 FragmentSearch->FragmentSet->erase(Removal); 3810 TouchedList[j] = -1; 3811 } 3812 *out << Verbose(2) << "Remaining local nr.s on snake stack are: "; 3813 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++) 3814 *out << (*runner) << " "; 3815 *out << endl; 3816 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level 3817 } else { 3818 *out << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl; 3819 } 3820 } 3821 Free((void **)&TouchedList, "molecule::SPFragmentGenerator: *TouchedList"); 3822 *out << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl; 3823 3823 }; 3824 3824 … … 3831 3831 bool molecule::CheckForConnectedSubgraph(ofstream *out, KeySet *Fragment) 3832 3832 { 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3833 atom *Walker = NULL, *Walker2 = NULL; 3834 bool BondStatus = false; 3835 int size; 3836 3837 *out << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl; 3838 *out << Verbose(2) << "Disconnected atom: "; 3839 3840 // count number of atoms in graph 3841 size = 0; 3842 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) 3843 size++; 3844 if (size > 1) 3845 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) { 3846 Walker = FindAtom(*runner); 3847 BondStatus = false; 3848 for(KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) { 3849 Walker2 = FindAtom(*runners); 3850 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) { 3851 if (ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker) == Walker2) { 3852 BondStatus = true; 3853 break; 3854 } 3855 if (BondStatus) 3856 break; 3857 } 3858 } 3859 if (!BondStatus) { 3860 *out << (*Walker) << endl; 3861 return false; 3862 } 3863 } 3864 else { 3865 *out << "none." << endl; 3866 return true; 3867 } 3868 *out << "none." << endl; 3869 3870 *out << Verbose(1) << "End of CheckForConnectedSubgraph" << endl; 3871 3872 return true; 3873 3873 } 3874 3874 … … 3890 3890 int molecule::PowerSetGenerator(ofstream *out, int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet) 3891 3891 { 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 CurrentEdge = FragmentSearch.BondsPerSPList[2*SP];/// start of this SP level's list3933 while (CurrentEdge->next != FragmentSearch.BondsPerSPList[2*SP+1]) {/// end of this SP level's list3934 3935 3936 Walker = CurrentEdge->rightatom;// rightatom is always the one more distant3937 Predecessor = CurrentEdge->leftatom;// ... and leftatom is predecessor3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 ) {// skip hydrogens and restrict to fragment3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 for(int i=1;i<Order;i++) {// skip the root edge in the printing3975 3976 3977 3978 3979 3980 3981 3982 3983 // creating fragments with the found edge sets(may be done in reverse order, faster)3984 SP = -1;// the Root <-> Root edge must be subtracted!3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next;// on SP level 0 there's only the root bond4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 3892 int SP, AtomKeyNr; 3893 atom *Walker = NULL, *OtherWalker = NULL, *Predecessor = NULL; 3894 bond *Binder = NULL; 3895 bond *CurrentEdge = NULL; 3896 bond **BondsList = NULL; 3897 int RootKeyNr = FragmentSearch.Root->GetTrueFather()->nr; 3898 int Counter = FragmentSearch.FragmentCounter; 3899 int RemainingWalkers; 3900 3901 *out << endl; 3902 *out << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.Root << "." << endl; 3903 3904 // prepare Label and SP arrays of the BFS search 3905 FragmentSearch.ShortestPathList[FragmentSearch.Root->nr] = 0; 3906 3907 // prepare root level (SP = 0) and a loop bond denoting Root 3908 for (int i=1;i<Order;i++) 3909 FragmentSearch.BondsPerSPCount[i] = 0; 3910 FragmentSearch.BondsPerSPCount[0] = 1; 3911 Binder = new bond(FragmentSearch.Root, FragmentSearch.Root); 3912 add(Binder, FragmentSearch.BondsPerSPList[1]); 3913 3914 // do a BFS search to fill the SP lists and label the found vertices 3915 // Actually, we should construct a spanning tree vom the root atom and select all edges therefrom and put them into 3916 // according shortest path lists. However, we don't. Rather we fill these lists right away, as they do form a spanning 3917 // tree already sorted into various SP levels. That's why we just do loops over the depth (CurrentSP) and breadth 3918 // (EdgeinSPLevel) of this tree ... 3919 // In another picture, the bonds always contain a direction by rightatom being the one more distant from root and hence 3920 // naturally leftatom forming its predecessor, preventing the BFS"seeker" from continuing in the wrong direction. 3921 *out << endl; 3922 *out << Verbose(0) << "Starting BFS analysis ..." << endl; 3923 for (SP = 0; SP < (Order-1); SP++) { 3924 *out << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)"; 3925 if (SP > 0) { 3926 *out << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl; 3927 FragmentSearch.BondsPerSPCount[SP] = 0; 3928 } else 3929 *out << "." << endl; 3930 3931 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP]; 3932 CurrentEdge = FragmentSearch.BondsPerSPList[2*SP]; /// start of this SP level's list 3933 while (CurrentEdge->next != FragmentSearch.BondsPerSPList[2*SP+1]) { /// end of this SP level's list 3934 CurrentEdge = CurrentEdge->next; 3935 RemainingWalkers--; 3936 Walker = CurrentEdge->rightatom; // rightatom is always the one more distant 3937 Predecessor = CurrentEdge->leftatom; // ... and leftatom is predecessor 3938 AtomKeyNr = Walker->nr; 3939 *out << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->nr << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl; 3940 // check for new sp level 3941 // go through all its bonds 3942 *out << Verbose(1) << "Going through all bonds of Walker." << endl; 3943 for (int i=0;i<NumberOfBondsPerAtom[AtomKeyNr];i++) { 3944 Binder = ListOfBondsPerAtom[AtomKeyNr][i]; 3945 OtherWalker = Binder->GetOtherAtom(Walker); 3946 if ((RestrictedKeySet.find(OtherWalker->nr) != RestrictedKeySet.end()) 3947 #ifdef ADDHYDROGEN 3948 && (OtherWalker->type->Z != 1) 3949 #endif 3950 ) { // skip hydrogens and restrict to fragment 3951 *out << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->nr << " in bond " << *Binder << "." << endl; 3952 // set the label if not set (and push on root stack as well) 3953 if ((OtherWalker != Predecessor) && (OtherWalker->GetTrueFather()->nr > RootKeyNr)) { // only pass through those with label bigger than Root's 3954 FragmentSearch.ShortestPathList[OtherWalker->nr] = SP+1; 3955 *out << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->nr] << "." << endl; 3956 // add the bond in between to the SP list 3957 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant 3958 add(Binder, FragmentSearch.BondsPerSPList[2*(SP+1)+1]); 3959 FragmentSearch.BondsPerSPCount[SP+1]++; 3960 *out << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl; 3961 } else { 3962 if (OtherWalker != Predecessor) 3963 *out << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->GetTrueFather()->nr << " is smaller than that of Root " << RootKeyNr << "." << endl; 3964 else 3965 *out << Verbose(3) << "This is my predecessor " << *Predecessor << "." << endl; 3966 } 3967 } else *out << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl; 3968 } 3969 } 3970 } 3971 3972 // outputting all list for debugging 3973 *out << Verbose(0) << "Printing all found lists." << endl; 3974 for(int i=1;i<Order;i++) { // skip the root edge in the printing 3975 Binder = FragmentSearch.BondsPerSPList[2*i]; 3976 *out << Verbose(1) << "Current SP level is " << i << "." << endl; 3977 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) { 3978 Binder = Binder->next; 3979 *out << Verbose(2) << *Binder << endl; 3980 } 3981 } 3982 3983 // creating fragments with the found edge sets (may be done in reverse order, faster) 3984 SP = -1; // the Root <-> Root edge must be subtracted! 3985 for(int i=Order;i--;) { // sum up all found edges 3986 Binder = FragmentSearch.BondsPerSPList[2*i]; 3987 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) { 3988 Binder = Binder->next; 3989 SP ++; 3990 } 3991 } 3992 *out << Verbose(0) << "Total number of edges is " << SP << "." << endl; 3993 if (SP >= (Order-1)) { 3994 // start with root (push on fragment stack) 3995 *out << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.Root << ", local nr is " << FragmentSearch.Root->nr << "." << endl; 3996 FragmentSearch.FragmentSet->clear(); 3997 *out << Verbose(0) << "Preparing subset for this root and calling generator." << endl; 3998 // prepare the subset and call the generator 3999 BondsList = (bond **) Malloc(sizeof(bond *)*FragmentSearch.BondsPerSPCount[0], "molecule::PowerSetGenerator: **BondsList"); 4000 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next; // on SP level 0 there's only the root bond 4001 4002 SPFragmentGenerator(out, &FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order); 4003 4004 Free((void **)&BondsList, "molecule::PowerSetGenerator: **BondsList"); 4005 } else { 4006 *out << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl; 4007 } 4008 4009 // as FragmentSearch structure is used only once, we don't have to clean it anymore 4010 // remove root from stack 4011 *out << Verbose(0) << "Removing root again from stack." << endl; 4012 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->nr); 4013 4014 // free'ing the bonds lists 4015 *out << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl; 4016 for(int i=Order;i--;) { 4017 *out << Verbose(1) << "Current SP level is " << i << ": "; 4018 Binder = FragmentSearch.BondsPerSPList[2*i]; 4019 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) { 4020 Binder = Binder->next; 4021 // *out << "Removing atom " << Binder->leftatom->nr << " and " << Binder->rightatom->nr << "." << endl; // make sure numbers are local 4022 FragmentSearch.ShortestPathList[Binder->leftatom->nr] = -1; 4023 FragmentSearch.ShortestPathList[Binder->rightatom->nr] = -1; 4024 } 4025 // delete added bonds 4026 cleanup(FragmentSearch.BondsPerSPList[2*i], FragmentSearch.BondsPerSPList[2*i+1]); 4027 // also start and end node 4028 *out << "cleaned." << endl; 4029 } 4030 4031 // return list 4032 *out << Verbose(0) << "End of PowerSetGenerator." << endl; 4033 return (FragmentSearch.FragmentCounter - Counter); 4034 4034 }; 4035 4035 … … 4042 4042 void molecule::ScanForPeriodicCorrection(ofstream *out) 4043 4043 { 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 unlink(Binder);// unlink bond4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 ColorList[Walker->nr] = black;// mark as explored4099 4100 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {// go through all binding partners4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4044 bond *Binder = NULL; 4045 bond *OtherBinder = NULL; 4046 atom *Walker = NULL; 4047 atom *OtherWalker = NULL; 4048 double *matrix = ReturnFullMatrixforSymmetric(cell_size); 4049 enum Shading *ColorList = NULL; 4050 double tmp; 4051 Vector Translationvector; 4052 //class StackClass<atom *> *CompStack = NULL; 4053 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount); 4054 bool flag = true; 4055 4056 *out << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl; 4057 4058 ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::ScanForPeriodicCorrection: *ColorList"); 4059 while (flag) { 4060 // remove bonds that are beyond bonddistance 4061 for(int i=NDIM;i--;) 4062 Translationvector.x[i] = 0.; 4063 // scan all bonds 4064 Binder = first; 4065 flag = false; 4066 while ((!flag) && (Binder->next != last)) { 4067 Binder = Binder->next; 4068 for (int i=NDIM;i--;) { 4069 tmp = fabs(Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i]); 4070 //*out << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl; 4071 if (tmp > BondDistance) { 4072 OtherBinder = Binder->next; // note down binding partner for later re-insertion 4073 unlink(Binder); // unlink bond 4074 *out << Verbose(2) << "Correcting at bond " << *Binder << "." << endl; 4075 flag = true; 4076 break; 4077 } 4078 } 4079 } 4080 if (flag) { 4081 // create translation vector from their periodically modified distance 4082 for (int i=NDIM;i--;) { 4083 tmp = Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i]; 4084 if (fabs(tmp) > BondDistance) 4085 Translationvector.x[i] = (tmp < 0) ? +1. : -1.; 4086 } 4087 Translationvector.MatrixMultiplication(matrix); 4088 //*out << Verbose(3) << "Translation vector is "; 4089 Translationvector.Output(out); 4090 *out << endl; 4091 // apply to all atoms of first component via BFS 4092 for (int i=AtomCount;i--;) 4093 ColorList[i] = white; 4094 AtomStack->Push(Binder->leftatom); 4095 while (!AtomStack->IsEmpty()) { 4096 Walker = AtomStack->PopFirst(); 4097 //*out << Verbose (3) << "Current Walker is: " << *Walker << "." << endl; 4098 ColorList[Walker->nr] = black; // mark as explored 4099 Walker->x.AddVector(&Translationvector); // translate 4100 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through all binding partners 4101 if (ListOfBondsPerAtom[Walker->nr][i] != Binder) { 4102 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker); 4103 if (ColorList[OtherWalker->nr] == white) { 4104 AtomStack->Push(OtherWalker); // push if yet unexplored 4105 } 4106 } 4107 } 4108 } 4109 // re-add bond 4110 link(Binder, OtherBinder); 4111 } else { 4112 *out << Verbose(3) << "No corrections for this fragment." << endl; 4113 } 4114 //delete(CompStack); 4115 } 4116 4117 // free allocated space from ReturnFullMatrixforSymmetric() 4118 delete(AtomStack); 4119 Free((void **)&ColorList, "molecule::ScanForPeriodicCorrection: *ColorList"); 4120 Free((void **)&matrix, "molecule::ScanForPeriodicCorrection: *matrix"); 4121 *out << Verbose(2) << "End of ScanForPeriodicCorrection." << endl; 4122 4122 }; 4123 4123 … … 4128 4128 double * molecule::ReturnFullMatrixforSymmetric(double *symm) 4129 4129 { 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4130 double *matrix = (double *) Malloc(sizeof(double)*NDIM*NDIM, "molecule::ReturnFullMatrixforSymmetric: *matrix"); 4131 matrix[0] = symm[0]; 4132 matrix[1] = symm[1]; 4133 matrix[2] = symm[3]; 4134 matrix[3] = symm[1]; 4135 matrix[4] = symm[2]; 4136 matrix[5] = symm[4]; 4137 matrix[6] = symm[3]; 4138 matrix[7] = symm[4]; 4139 matrix[8] = symm[5]; 4140 return matrix; 4141 4141 }; 4142 4142 4143 4143 bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const 4144 4144 { 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 if ((*IteratorA) <(*IteratorB))4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4145 //cout << "my check is used." << endl; 4146 if (SubgraphA.size() < SubgraphB.size()) { 4147 return true; 4148 } else { 4149 if (SubgraphA.size() > SubgraphB.size()) { 4150 return false; 4151 } else { 4152 KeySet::iterator IteratorA = SubgraphA.begin(); 4153 KeySet::iterator IteratorB = SubgraphB.begin(); 4154 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) { 4155 if ((*IteratorA) < (*IteratorB)) 4156 return true; 4157 else if ((*IteratorA) > (*IteratorB)) { 4158 return false; 4159 } // else, go on to next index 4160 IteratorA++; 4161 IteratorB++; 4162 } // end of while loop 4163 }// end of check in case of equal sizes 4164 } 4165 return false; // if we reach this point, they are equal 4166 4166 }; 4167 4167 4168 4168 //bool operator < (KeySet SubgraphA, KeySet SubgraphB) 4169 4169 //{ 4170 // 4170 // return KeyCompare(SubgraphA, SubgraphB); 4171 4171 //}; 4172 4172 … … 4180 4180 inline void InsertFragmentIntoGraph(ofstream *out, struct UniqueFragments *Fragment) 4181 4181 { 4182 4183 4184 testGraphInsert = Fragment->Leaflet->insert(GraphPair (*Fragment->FragmentSet,pair<int,double>(Fragment->FragmentCounter,Fragment->TEFactor)));// store fragment number and current factor4185 4186 4187 4188 4189 4190 ((*(testGraphInsert.first)).second).second += Fragment->TEFactor;// increase the "created" counter4191 4192 4182 GraphTestPair testGraphInsert; 4183 4184 testGraphInsert = Fragment->Leaflet->insert(GraphPair (*Fragment->FragmentSet,pair<int,double>(Fragment->FragmentCounter,Fragment->TEFactor))); // store fragment number and current factor 4185 if (testGraphInsert.second) { 4186 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " successfully inserted." << endl; 4187 Fragment->FragmentCounter++; 4188 } else { 4189 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl; 4190 ((*(testGraphInsert.first)).second).second += Fragment->TEFactor; // increase the "created" counter 4191 *out << Verbose(2) << "New factor is " << ((*(testGraphInsert.first)).second).second << "." << endl; 4192 } 4193 4193 }; 4194 4194 //void inline InsertIntoGraph(ofstream *out, KeyStack &stack, Graph &graph, int *counter, double factor) 4195 4195 //{ 4196 // 4197 // 4198 // 4199 // 4200 // 4196 // // copy stack contents to set and call overloaded function again 4197 // KeySet set; 4198 // for(KeyStack::iterator runner = stack.begin(); runner != stack.begin(); runner++) 4199 // set.insert((*runner)); 4200 // InsertIntoGraph(out, set, graph, counter, factor); 4201 4201 //}; 4202 4202 … … 4209 4209 inline void InsertGraphIntoGraph(ofstream *out, Graph &graph1, Graph &graph2, int *counter) 4210 4210 { 4211 4212 4213 4214 testGraphInsert = graph1.insert(GraphPair ((*runner).first,pair<int,double>((*counter)++,((*runner).second).second)));// store fragment number and current factor4215 4216 4217 4218 4219 4220 4221 4222 4211 GraphTestPair testGraphInsert; 4212 4213 for(Graph::iterator runner = graph2.begin(); runner != graph2.end(); runner++) { 4214 testGraphInsert = graph1.insert(GraphPair ((*runner).first,pair<int,double>((*counter)++,((*runner).second).second))); // store fragment number and current factor 4215 if (testGraphInsert.second) { 4216 *out << Verbose(2) << "KeySet " << (*counter)-1 << " successfully inserted." << endl; 4217 } else { 4218 *out << Verbose(2) << "KeySet " << (*counter)-1 << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl; 4219 ((*(testGraphInsert.first)).second).second += (*runner).second.second; 4220 *out << Verbose(2) << "New factor is " << (*(testGraphInsert.first)).second.second << "." << endl; 4221 } 4222 } 4223 4223 }; 4224 4224 … … 4227 4227 * -# constructs a complete keyset of the molecule 4228 4228 * -# In a loop over all possible roots from the given rootstack 4229 * 4230 * 4231 * 4229 * -# increases order of root site 4230 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr 4231 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset 4232 4232 as the restricted one and each site in the set as the root) 4233 * 4233 * -# these are merged into a fragment list of keysets 4234 4234 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return 4235 4235 * Important only is that we create all fragments, it is not important if we create them more than once … … 4243 4243 void molecule::FragmentBOSSANOVA(ofstream *out, Graph *&FragmentList, KeyStack &RootStack, int *MinimumRingSize) 4244 4244 { 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 RootNr = 0;// counts through the roots in RootStack4282 4283 4284 4285 4286 4287 4288 //*out << Verbose(0) << "Bond order " << Walker->GetTrueFather()->AdaptiveOrder << " of Root " << *Walker << " greater than or equal to Minimum Ring size of " << MinimumRingSize << " found is not allowed." << endl;4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 FragmentSearch.BondsPerSPList[2*i] = new bond();// start node4300 FragmentSearch.BondsPerSPList[2*i+1] = new bond();// end node4301 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1];// intertwine these two4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 FragmentLowerOrdersList[RootNr][0] =new Graph;4318 4319 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0];// set to insertion graph4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 // 4330 // 4331 // 4332 // 4333 // 4334 // 4335 // 4336 // 4337 // 4338 // 4339 // 4340 // 4341 // 4245 Graph ***FragmentLowerOrdersList = NULL; 4246 int NumLevels, NumMolecules, TotalNumMolecules = 0, *NumMoleculesOfOrder = NULL; 4247 int counter = 0, Order; 4248 int UpgradeCount = RootStack.size(); 4249 KeyStack FragmentRootStack; 4250 int RootKeyNr, RootNr; 4251 struct UniqueFragments FragmentSearch; 4252 4253 *out << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl; 4254 4255 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5) 4256 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5) 4257 NumMoleculesOfOrder = (int *) Malloc(sizeof(int)*UpgradeCount, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder"); 4258 FragmentLowerOrdersList = (Graph ***) Malloc(sizeof(Graph **)*UpgradeCount, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList"); 4259 4260 // initialise the fragments structure 4261 FragmentSearch.ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::PowerSetGenerator: *ShortestPathList"); 4262 FragmentSearch.FragmentCounter = 0; 4263 FragmentSearch.FragmentSet = new KeySet; 4264 FragmentSearch.Root = FindAtom(RootKeyNr); 4265 for (int i=AtomCount;i--;) { 4266 FragmentSearch.ShortestPathList[i] = -1; 4267 } 4268 4269 // Construct the complete KeySet which we need for topmost level only (but for all Roots) 4270 atom *Walker = start; 4271 KeySet CompleteMolecule; 4272 while (Walker->next != end) { 4273 Walker = Walker->next; 4274 CompleteMolecule.insert(Walker->GetTrueFather()->nr); 4275 } 4276 4277 // this can easily be seen: if Order is 5, then the number of levels for each lower order is the total sum of the number of levels above, as 4278 // each has to be split up. E.g. for the second level we have one from 5th, one from 4th, two from 3th (which in turn is one from 5th, one from 4th), 4279 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[]) 4280 // with the order along the cells as this: 5433222211111111 for BondOrder 5 needing 16=pow(2,5-1) cells (only we use bit-shifting which is faster) 4281 RootNr = 0; // counts through the roots in RootStack 4282 while ((RootNr < UpgradeCount) && (!RootStack.empty())) { 4283 RootKeyNr = RootStack.front(); 4284 RootStack.pop_front(); 4285 Walker = FindAtom(RootKeyNr); 4286 // check cyclic lengths 4287 //if ((MinimumRingSize[Walker->GetTrueFather()->nr] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->nr])) { 4288 // *out << Verbose(0) << "Bond order " << Walker->GetTrueFather()->AdaptiveOrder << " of Root " << *Walker << " greater than or equal to Minimum Ring size of " << MinimumRingSize << " found is not allowed." << endl; 4289 //} else 4290 { 4291 // increase adaptive order by one 4292 Walker->GetTrueFather()->AdaptiveOrder++; 4293 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder; 4294 4295 // initialise Order-dependent entries of UniqueFragments structure 4296 FragmentSearch.BondsPerSPList = (bond **) Malloc(sizeof(bond *)*Order*2, "molecule::PowerSetGenerator: ***BondsPerSPList"); 4297 FragmentSearch.BondsPerSPCount = (int *) Malloc(sizeof(int)*Order, "molecule::PowerSetGenerator: *BondsPerSPCount"); 4298 for (int i=Order;i--;) { 4299 FragmentSearch.BondsPerSPList[2*i] = new bond(); // start node 4300 FragmentSearch.BondsPerSPList[2*i+1] = new bond(); // end node 4301 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1]; // intertwine these two 4302 FragmentSearch.BondsPerSPList[2*i+1]->previous = FragmentSearch.BondsPerSPList[2*i]; 4303 FragmentSearch.BondsPerSPCount[i] = 0; 4304 } 4305 4306 // allocate memory for all lower level orders in this 1D-array of ptrs 4307 NumLevels = 1 << (Order-1); // (int)pow(2,Order); 4308 FragmentLowerOrdersList[RootNr] = (Graph **) Malloc(sizeof(Graph *)*NumLevels, "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]"); 4309 for (int i=0;i<NumLevels;i++) 4310 FragmentLowerOrdersList[RootNr][i] = NULL; 4311 4312 // create top order where nothing is reduced 4313 *out << Verbose(0) << "==============================================================================================================" << endl; 4314 *out << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl; // , NumLevels is " << NumLevels << " 4315 4316 // Create list of Graphs of current Bond Order (i.e. F_{ij}) 4317 FragmentLowerOrdersList[RootNr][0] = new Graph; 4318 FragmentSearch.TEFactor = 1.; 4319 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph 4320 FragmentSearch.Root = Walker; 4321 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(out, Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule); 4322 *out << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl; 4323 if (NumMoleculesOfOrder[RootNr] != 0) { 4324 NumMolecules = 0; 4325 4326 // we don't have to dive into suborders! These keysets are all already created on lower orders! 4327 // this was all ancient stuff, when we still depended on the TEFactors (and for those the suborders were needed) 4328 4329 // if ((NumLevels >> 1) > 0) { 4330 // // create lower order fragments 4331 // *out << Verbose(0) << "Creating list of unique fragments of lower Bond Order terms to be subtracted." << endl; 4332 // Order = Walker->AdaptiveOrder; 4333 // for (int source=0;source<(NumLevels >> 1);source++) { // 1-terms don't need any more splitting, that's why only half is gone through (shift again) 4334 // // step down to next order at (virtual) boundary of powers of 2 in array 4335 // while (source >= (1 << (Walker->AdaptiveOrder-Order))) // (int)pow(2,Walker->AdaptiveOrder-Order)) 4336 // Order--; 4337 // *out << Verbose(0) << "Current Order is: " << Order << "." << endl; 4338 // for (int SubOrder=Order-1;SubOrder>0;SubOrder--) { 4339 // int dest = source + (1 << (Walker->AdaptiveOrder-(SubOrder+1))); 4340 // *out << Verbose(0) << "--------------------------------------------------------------------------------------------------------------" << endl; 4341 // *out << Verbose(0) << "Current SubOrder is: " << SubOrder << " with source " << source << " to destination " << dest << "." << endl; 4342 4342 // 4343 // 4344 // 4345 // 4346 // 4347 // 4348 // 4349 // 4350 // 4351 // FragmentSearch.Leaflet = &TempFragmentList;// set to insertion graph4352 // 4353 // 4354 // 4355 // 4356 // 4357 // 4358 // 4359 // 4360 // 4361 // 4362 // 4363 4364 4365 // 4366 4367 4368 4369 4370 // 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4343 // // every molecule is split into a list of again (Order - 1) molecules, while counting all molecules 4344 // //*out << Verbose(1) << "Splitting the " << (*FragmentLowerOrdersList[RootNr][source]).size() << " molecules of the " << source << "th cell in the array." << endl; 4345 // //NumMolecules = 0; 4346 // FragmentLowerOrdersList[RootNr][dest] = new Graph; 4347 // for(Graph::iterator runner = (*FragmentLowerOrdersList[RootNr][source]).begin();runner != (*FragmentLowerOrdersList[RootNr][source]).end(); runner++) { 4348 // for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) { 4349 // Graph TempFragmentList; 4350 // FragmentSearch.TEFactor = -(*runner).second.second; 4351 // FragmentSearch.Leaflet = &TempFragmentList; // set to insertion graph 4352 // FragmentSearch.Root = FindAtom(*sprinter); 4353 // NumMoleculesOfOrder[RootNr] += PowerSetGenerator(out, SubOrder, FragmentSearch, (*runner).first); 4354 // // insert new keysets FragmentList into FragmentLowerOrdersList[Walker->AdaptiveOrder-1][dest] 4355 // *out << Verbose(1) << "Merging resulting key sets with those present in destination " << dest << "." << endl; 4356 // InsertGraphIntoGraph(out, *FragmentLowerOrdersList[RootNr][dest], TempFragmentList, &NumMolecules); 4357 // } 4358 // } 4359 // *out << Verbose(1) << "Number of resulting molecules for SubOrder " << SubOrder << " is: " << NumMolecules << "." << endl; 4360 // } 4361 // } 4362 // } 4363 } else { 4364 Walker->GetTrueFather()->MaxOrder = true; 4365 // *out << Verbose(1) << "Hence, we don't dive into SubOrders ... " << endl; 4366 } 4367 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder 4368 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules; 4369 TotalNumMolecules += NumMoleculesOfOrder[RootNr]; 4370 // *out << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl; 4371 RootStack.push_back(RootKeyNr); // put back on stack 4372 RootNr++; 4373 4374 // free Order-dependent entries of UniqueFragments structure for next loop cycle 4375 Free((void **)&FragmentSearch.BondsPerSPCount, "molecule::PowerSetGenerator: *BondsPerSPCount"); 4376 for (int i=Order;i--;) { 4377 delete(FragmentSearch.BondsPerSPList[2*i]); 4378 delete(FragmentSearch.BondsPerSPList[2*i+1]); 4379 } 4380 Free((void **)&FragmentSearch.BondsPerSPList, "molecule::PowerSetGenerator: ***BondsPerSPList"); 4381 } 4382 } 4383 *out << Verbose(0) << "==============================================================================================================" << endl; 4384 *out << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl; 4385 *out << Verbose(0) << "==============================================================================================================" << endl; 4386 4387 // cleanup FragmentSearch structure 4388 Free((void **)&FragmentSearch.ShortestPathList, "molecule::PowerSetGenerator: *ShortestPathList"); 4389 delete(FragmentSearch.FragmentSet); 4390 4391 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein) 4392 // 5433222211111111 4393 // 43221111 4394 // 3211 4395 // 21 4396 // 1 4397 4398 // Subsequently, we combine all into a single list (FragmentList) 4399 4400 *out << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl; 4401 if (FragmentList == NULL) { 4402 FragmentList = new Graph; 4403 counter = 0; 4404 } else { 4405 counter = FragmentList->size(); 4406 } 4407 RootNr = 0; 4408 while (!RootStack.empty()) { 4409 RootKeyNr = RootStack.front(); 4410 RootStack.pop_front(); 4411 Walker = FindAtom(RootKeyNr); 4412 NumLevels = 1 << (Walker->AdaptiveOrder - 1); 4413 for(int i=0;i<NumLevels;i++) { 4414 if (FragmentLowerOrdersList[RootNr][i] != NULL) { 4415 InsertGraphIntoGraph(out, *FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter); 4416 delete(FragmentLowerOrdersList[RootNr][i]); 4417 } 4418 } 4419 Free((void **)&FragmentLowerOrdersList[RootNr], "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]"); 4420 RootNr++; 4421 } 4422 Free((void **)&FragmentLowerOrdersList, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList"); 4423 Free((void **)&NumMoleculesOfOrder, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder"); 4424 4425 *out << Verbose(0) << "End of FragmentBOSSANOVA." << endl; 4426 4426 }; 4427 4427 … … 4433 4433 inline int CompareDoubles (const void * a, const void * b) 4434 4434 { 4435 4436 4437 4438 4439 4440 4435 if (*(double *)a > *(double *)b) 4436 return -1; 4437 else if (*(double *)a < *(double *)b) 4438 return 1; 4439 else 4440 return 0; 4441 4441 }; 4442 4442 … … 4449 4449 int * molecule::IsEqualToWithinThreshold(ofstream *out, molecule *OtherMolecule, double threshold) 4450 4450 { 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 //*out << Verbose(5) << "Element " <<flag << ": " << ElementsInMolecule[flag] << " <-> " << OtherMolecule->ElementsInMolecule[flag] << "." << endl;4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 *out << Verbose(5) << "Distances squared: |" << Distances[PermMap[i]] << " - " << OtherDistances[OtherPermMap[i]] << "| = " << fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) << " ?<? " <<threshold << endl;4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4451 int flag; 4452 double *Distances = NULL, *OtherDistances = NULL; 4453 Vector CenterOfGravity, OtherCenterOfGravity; 4454 size_t *PermMap = NULL, *OtherPermMap = NULL; 4455 int *PermutationMap = NULL; 4456 atom *Walker = NULL; 4457 bool result = true; // status of comparison 4458 4459 *out << Verbose(3) << "Begin of IsEqualToWithinThreshold." << endl; 4460 /// first count both their atoms and elements and update lists thereby ... 4461 //*out << Verbose(0) << "Counting atoms, updating list" << endl; 4462 CountAtoms(out); 4463 OtherMolecule->CountAtoms(out); 4464 CountElements(); 4465 OtherMolecule->CountElements(); 4466 4467 /// ... and compare: 4468 /// -# AtomCount 4469 if (result) { 4470 if (AtomCount != OtherMolecule->AtomCount) { 4471 *out << Verbose(4) << "AtomCounts don't match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl; 4472 result = false; 4473 } else *out << Verbose(4) << "AtomCounts match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl; 4474 } 4475 /// -# ElementCount 4476 if (result) { 4477 if (ElementCount != OtherMolecule->ElementCount) { 4478 *out << Verbose(4) << "ElementCount don't match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl; 4479 result = false; 4480 } else *out << Verbose(4) << "ElementCount match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl; 4481 } 4482 /// -# ElementsInMolecule 4483 if (result) { 4484 for (flag=MAX_ELEMENTS;flag--;) { 4485 //*out << Verbose(5) << "Element " << flag << ": " << ElementsInMolecule[flag] << " <-> " << OtherMolecule->ElementsInMolecule[flag] << "." << endl; 4486 if (ElementsInMolecule[flag] != OtherMolecule->ElementsInMolecule[flag]) 4487 break; 4488 } 4489 if (flag < MAX_ELEMENTS) { 4490 *out << Verbose(4) << "ElementsInMolecule don't match." << endl; 4491 result = false; 4492 } else *out << Verbose(4) << "ElementsInMolecule match." << endl; 4493 } 4494 /// then determine and compare center of gravity for each molecule ... 4495 if (result) { 4496 *out << Verbose(5) << "Calculating Centers of Gravity" << endl; 4497 DetermineCenter(CenterOfGravity); 4498 OtherMolecule->DetermineCenter(OtherCenterOfGravity); 4499 *out << Verbose(5) << "Center of Gravity: "; 4500 CenterOfGravity.Output(out); 4501 *out << endl << Verbose(5) << "Other Center of Gravity: "; 4502 OtherCenterOfGravity.Output(out); 4503 *out << endl; 4504 if (CenterOfGravity.DistanceSquared(&OtherCenterOfGravity) > threshold*threshold) { 4505 *out << Verbose(4) << "Centers of gravity don't match." << endl; 4506 result = false; 4507 } 4508 } 4509 4510 /// ... then make a list with the euclidian distance to this center for each atom of both molecules 4511 if (result) { 4512 *out << Verbose(5) << "Calculating distances" << endl; 4513 Distances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: Distances"); 4514 OtherDistances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: OtherDistances"); 4515 Walker = start; 4516 while (Walker->next != end) { 4517 Walker = Walker->next; 4518 Distances[Walker->nr] = CenterOfGravity.DistanceSquared(&Walker->x); 4519 } 4520 Walker = OtherMolecule->start; 4521 while (Walker->next != OtherMolecule->end) { 4522 Walker = Walker->next; 4523 OtherDistances[Walker->nr] = OtherCenterOfGravity.DistanceSquared(&Walker->x); 4524 } 4525 4526 /// ... sort each list (using heapsort (o(N log N)) from GSL) 4527 *out << Verbose(5) << "Sorting distances" << endl; 4528 PermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermMap"); 4529 OtherPermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *OtherPermMap"); 4530 gsl_heapsort_index (PermMap, Distances, AtomCount, sizeof(double), CompareDoubles); 4531 gsl_heapsort_index (OtherPermMap, OtherDistances, AtomCount, sizeof(double), CompareDoubles); 4532 PermutationMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermutationMap"); 4533 *out << Verbose(5) << "Combining Permutation Maps" << endl; 4534 for(int i=AtomCount;i--;) 4535 PermutationMap[PermMap[i]] = (int) OtherPermMap[i]; 4536 4537 /// ... and compare them step by step, whether the difference is individiually(!) below \a threshold for all 4538 *out << Verbose(4) << "Comparing distances" << endl; 4539 flag = 0; 4540 for (int i=0;i<AtomCount;i++) { 4541 *out << Verbose(5) << "Distances squared: |" << Distances[PermMap[i]] << " - " << OtherDistances[OtherPermMap[i]] << "| = " << fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) << " ?<? " << threshold << endl; 4542 if (fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) > threshold*threshold) 4543 flag = 1; 4544 } 4545 Free((void **)&PermMap, "molecule::IsEqualToWithinThreshold: *PermMap"); 4546 Free((void **)&OtherPermMap, "molecule::IsEqualToWithinThreshold: *OtherPermMap"); 4547 4548 /// free memory 4549 Free((void **)&Distances, "molecule::IsEqualToWithinThreshold: Distances"); 4550 Free((void **)&OtherDistances, "molecule::IsEqualToWithinThreshold: OtherDistances"); 4551 if (flag) { // if not equal 4552 Free((void **)&PermutationMap, "molecule::IsEqualToWithinThreshold: *PermutationMap"); 4553 result = false; 4554 } 4555 } 4556 /// return pointer to map if all distances were below \a threshold 4557 *out << Verbose(3) << "End of IsEqualToWithinThreshold." << endl; 4558 if (result) { 4559 *out << Verbose(3) << "Result: Equal." << endl; 4560 return PermutationMap; 4561 } else { 4562 *out << Verbose(3) << "Result: Not equal." << endl; 4563 return NULL; 4564 } 4565 4565 }; 4566 4566 … … 4574 4574 int * molecule::GetFatherSonAtomicMap(ofstream *out, molecule *OtherMolecule) 4575 4575 { 4576 4577 4578 int *AtomicMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::GetAtomicMap: *AtomicMap");//Calloc4579 4580 4581 if (OtherMolecule == this) {// same molecule4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4576 atom *Walker = NULL, *OtherWalker = NULL; 4577 *out << Verbose(3) << "Begin of GetFatherAtomicMap." << endl; 4578 int *AtomicMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::GetAtomicMap: *AtomicMap"); //Calloc 4579 for (int i=AtomCount;i--;) 4580 AtomicMap[i] = -1; 4581 if (OtherMolecule == this) { // same molecule 4582 for (int i=AtomCount;i--;) // no need as -1 means already that there is trivial correspondence 4583 AtomicMap[i] = i; 4584 *out << Verbose(4) << "Map is trivial." << endl; 4585 } else { 4586 *out << Verbose(4) << "Map is "; 4587 Walker = start; 4588 while (Walker->next != end) { 4589 Walker = Walker->next; 4590 if (Walker->father == NULL) { 4591 AtomicMap[Walker->nr] = -2; 4592 } else { 4593 OtherWalker = OtherMolecule->start; 4594 while (OtherWalker->next != OtherMolecule->end) { 4595 OtherWalker = OtherWalker->next; 4596 //for (int i=0;i<AtomCount;i++) { // search atom 4597 //for (int j=0;j<OtherMolecule->AtomCount;j++) { 4598 //*out << Verbose(4) << "Comparing father " << Walker->father << " with the other one " << OtherWalker->father << "." << endl; 4599 if (Walker->father == OtherWalker) 4600 AtomicMap[Walker->nr] = OtherWalker->nr; 4601 } 4602 } 4603 *out << AtomicMap[Walker->nr] << "\t"; 4604 } 4605 *out << endl; 4606 } 4607 *out << Verbose(3) << "End of GetFatherAtomicMap." << endl; 4608 return AtomicMap; 4609 4609 }; 4610 4610 … … 4620 4620 bool molecule::OutputTemperatureFromTrajectories(ofstream *out, int startstep, int endstep, ofstream *output) 4621 4621 { 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 }; 4622 double temperature; 4623 atom *Walker = NULL; 4624 // test stream 4625 if (output == NULL) 4626 return false; 4627 else 4628 *output << "# Step Temperature [K] Temperature [a.u.]" << endl; 4629 for (int step=startstep;step < endstep; step++) { // loop over all time steps 4630 temperature = 0.; 4631 Walker = start; 4632 while (Walker->next != end) { 4633 Walker = Walker->next; 4634 for (int i=NDIM;i--;) 4635 temperature += Walker->type->mass * Trajectories[Walker].U.at(step).x[i]* Trajectories[Walker].U.at(step).x[i]; 4636 } 4637 *output << step << "\t" << temperature*AtomicEnergyToKelvin << "\t" << temperature << endl; 4638 } 4639 return true; 4640 };
Note:
See TracChangeset
for help on using the changeset viewer.