Changeset 36ec71 for src/molecules.cpp
- Timestamp:
- Jul 24, 2009, 10:38:32 AM (16 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:
- d30402
- Parents:
- 042f82 (diff), 51c910 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - git-author:
- Frederik Heber <heber@…> (07/23/09 14:23:32)
- git-committer:
- Frederik Heber <heber@…> (07/24/09 10:38:32)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/molecules.cpp
r042f82 r36ec71 63 63 cell_size[1] = cell_size[3] = cell_size[4]= 0.; 64 64 strcpy(name,"none"); 65 IndexNr = -1; 66 ActiveFlag = false; 65 67 }; 66 68 … … 602 604 * \param *filename filename 603 605 */ 604 void molecule::SetNameFromFilename(c har *filename)606 void molecule::SetNameFromFilename(const char *filename) 605 607 { 606 608 int length = 0; 607 609 char *molname = strrchr(filename, '/')+sizeof(char); // search for filename without dirs 608 char *endname = str rchr(filename, '.');610 char *endname = strchr(molname, '.'); 609 611 if ((endname == NULL) || (endname < molname)) 610 612 length = strlen(molname); … … 612 614 length = strlen(molname) - strlen(endname); 613 615 strncpy(name, molname, length); 616 name[length]='\0'; 614 617 }; 615 618 … … 669 672 } 670 673 } 671 // matrix multiply672 x.MatrixMultiplication(M);673 ptr->x.CopyVector(&x);674 674 } 675 675 } … … 710 710 max->AddVector(min); 711 711 Translate(min); 712 Center.Zero(); 712 713 } 713 714 delete(min); … … 719 720 * \param *center return vector for translation vector 720 721 */ 721 void molecule::CenterOrigin(ofstream *out , Vector *center)722 void molecule::CenterOrigin(ofstream *out) 722 723 { 723 724 int Num = 0; 724 725 atom *ptr = start->next; // start at first in list 725 726 726 for(int i=NDIM;i--;) // zero center vector 727 center->x[i] = 0.; 727 Center.Zero(); 728 728 729 729 if (ptr != end) { //list not empty? … … 731 731 ptr = ptr->next; 732 732 Num++; 733 center->AddVector(&ptr->x); 734 } 735 center->Scale(-1./Num); // divide through total number (and sign for direction) 736 Translate(center); 733 Center.AddVector(&ptr->x); 734 } 735 Center.Scale(-1./Num); // divide through total number (and sign for direction) 736 Translate(&Center); 737 Center.Zero(); 737 738 } 738 739 }; … … 799 800 * \param *center return vector for translation vector 800 801 */ 801 void molecule::CenterGravity(ofstream *out, Vector *center) 802 { 803 if (center == NULL) { 804 DetermineCenter(*center); 805 Translate(center); 806 delete(center); 807 } else { 808 Translate(center); 809 } 810 }; 802 void molecule::CenterPeriodic(ofstream *out) 803 { 804 DeterminePeriodicCenter(Center); 805 }; 806 807 808 /** Centers the center of gravity of the atoms at (0,0,0). 809 * \param *out output stream for debugging 810 * \param *center return vector for translation vector 811 */ 812 void molecule::CenterAtVector(ofstream *out, Vector *newcenter) 813 { 814 Center.CopyVector(newcenter); 815 }; 816 811 817 812 818 /** Scales all atoms by \a *factor. … … 911 917 912 918 /** Determines center of molecule (yet not considering atom masses). 913 * \param Center reference to return vector914 */ 915 void molecule::Determine Center(Vector &Center)919 * \param center reference to return vector 920 */ 921 void molecule::DeterminePeriodicCenter(Vector ¢er) 916 922 { 917 923 atom *Walker = start; … … 987 993 Vector *CenterOfGravity = DetermineCenterOfGravity(out); 988 994 989 Center Gravity(out, CenterOfGravity);995 CenterPeriodic(out); 990 996 991 997 // reset inertia tensor … … 1083 1089 }; 1084 1090 1091 /** Evaluates the potential energy used for constrained molecular dynamics. 1092 * \f$V_i^{con} = c^{bond} \cdot | r_{P(i)} - R_i | + sum_{i \neq j} C^{min} \cdot \frac{1}{C_{ij}} + C^{inj} \Bigl (1 - \theta \bigl (\prod_{i \neq j} (P(i) - P(j)) \bigr ) \Bigr )\f$ 1093 * where the first term points to the target in minimum distance, the second is a penalty for trajectories lying too close to each other (\f$C_{ij}$ is minimum distance between 1094 * trajectories i and j) and the third term is a penalty for two atoms trying to each the same target point. 1095 * Note that for the second term we have to solve the following linear system: 1096 * \f$-c_1 \cdot n_1 + c_2 \cdot n_2 + C \cdot n_3 = - p_2 + p_1\f$, where \f$c_1\f$, \f$c_2\f$ and \f$C\f$ are constants, 1097 * offset vector \f$p_1\f$ in direction \f$n_1\f$, offset vector \f$p_2\f$ in direction \f$n_2\f$, 1098 * \f$n_3\f$ is the normal vector to both directions. \f$C\f$ would be the minimum distance between the two lines. 1099 * \sa molecule::MinimiseConstrainedPotential(), molecule::VerletForceIntegration() 1100 * \param *out output stream for debugging 1101 * \param *PermutationMap gives target ptr for each atom, array of size molecule::AtomCount (this is "x" in \f$ V^{con}(x) \f$ ) 1102 * \param startstep start configuration (MDStep in molecule::trajectories) 1103 * \param endstep end configuration (MDStep in molecule::trajectories) 1104 * \param *constants constant in front of each term 1105 * \param IsAngstroem whether coordinates are in angstroem (true) or bohrradius (false) 1106 * \return potential energy 1107 * \note This routine is scaling quadratically which is not optimal. 1108 * \todo There's a bit double counting going on for the first time, bu nothing to worry really about. 1109 */ 1110 double molecule::ConstrainedPotential(ofstream *out, atom **PermutationMap, int startstep, int endstep, double *constants, bool IsAngstroem) 1111 { 1112 double result = 0., tmp, Norm1, Norm2; 1113 atom *Walker = NULL, *Runner = NULL, *Sprinter = NULL; 1114 Vector trajectory1, trajectory2, normal, TestVector; 1115 gsl_matrix *A = gsl_matrix_alloc(NDIM,NDIM); 1116 gsl_vector *x = gsl_vector_alloc(NDIM); 1117 1118 // go through every atom 1119 Walker = start; 1120 while (Walker->next != end) { 1121 Walker = Walker->next; 1122 // first term: distance to target 1123 Runner = PermutationMap[Walker->nr]; // find target point 1124 tmp = (Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(endstep))); 1125 tmp *= IsAngstroem ? 1. : 1./AtomicLengthToAngstroem; 1126 result += constants[0] * tmp; 1127 //*out << Verbose(4) << "Adding " << tmp*constants[0] << "." << endl; 1128 1129 // second term: sum of distances to other trajectories 1130 Runner = start; 1131 while (Runner->next != end) { 1132 Runner = Runner->next; 1133 if (Runner == Walker) // hence, we only go up to the Walker, not beyond (similar to i=0; i<j; i++) 1134 break; 1135 // determine normalized trajectories direction vector (n1, n2) 1136 Sprinter = PermutationMap[Walker->nr]; // find first target point 1137 trajectory1.CopyVector(&Trajectories[Sprinter].R.at(endstep)); 1138 trajectory1.SubtractVector(&Trajectories[Walker].R.at(startstep)); 1139 trajectory1.Normalize(); 1140 Norm1 = trajectory1.Norm(); 1141 Sprinter = PermutationMap[Runner->nr]; // find second target point 1142 trajectory2.CopyVector(&Trajectories[Sprinter].R.at(endstep)); 1143 trajectory2.SubtractVector(&Trajectories[Runner].R.at(startstep)); 1144 trajectory2.Normalize(); 1145 Norm2 = trajectory1.Norm(); 1146 // check whether either is zero() 1147 if ((Norm1 < MYEPSILON) && (Norm2 < MYEPSILON)) { 1148 tmp = Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(startstep)); 1149 } else if (Norm1 < MYEPSILON) { 1150 Sprinter = PermutationMap[Walker->nr]; // find first target point 1151 trajectory1.CopyVector(&Trajectories[Sprinter].R.at(endstep)); // copy first offset 1152 trajectory1.SubtractVector(&Trajectories[Runner].R.at(startstep)); // subtract second offset 1153 trajectory2.Scale( trajectory1.ScalarProduct(&trajectory2) ); // trajectory2 is scaled to unity, hence we don't need to divide by anything 1154 trajectory1.SubtractVector(&trajectory2); // project the part in norm direction away 1155 tmp = trajectory1.Norm(); // remaining norm is distance 1156 } else if (Norm2 < MYEPSILON) { 1157 Sprinter = PermutationMap[Runner->nr]; // find second target point 1158 trajectory2.CopyVector(&Trajectories[Sprinter].R.at(endstep)); // copy second offset 1159 trajectory2.SubtractVector(&Trajectories[Walker].R.at(startstep)); // subtract first offset 1160 trajectory1.Scale( trajectory2.ScalarProduct(&trajectory1) ); // trajectory1 is scaled to unity, hence we don't need to divide by anything 1161 trajectory2.SubtractVector(&trajectory1); // project the part in norm direction away 1162 tmp = trajectory2.Norm(); // remaining norm is distance 1163 } else if ((fabs(trajectory1.ScalarProduct(&trajectory2)/Norm1/Norm2) - 1.) < MYEPSILON) { // check whether they're linear dependent 1164 // *out << Verbose(3) << "Both trajectories of " << *Walker << " and " << *Runner << " are linear dependent: "; 1165 // *out << trajectory1; 1166 // *out << " and "; 1167 // *out << trajectory2; 1168 tmp = Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(startstep)); 1169 // *out << " with distance " << tmp << "." << endl; 1170 } else { // determine distance by finding minimum distance 1171 // *out << Verbose(3) << "Both trajectories of " << *Walker << " and " << *Runner << " are linear independent "; 1172 // *out << endl; 1173 // *out << "First Trajectory: "; 1174 // *out << trajectory1 << endl; 1175 // *out << "Second Trajectory: "; 1176 // *out << trajectory2 << endl; 1177 // determine normal vector for both 1178 normal.MakeNormalVector(&trajectory1, &trajectory2); 1179 // print all vectors for debugging 1180 // *out << "Normal vector in between: "; 1181 // *out << normal << endl; 1182 // setup matrix 1183 for (int i=NDIM;i--;) { 1184 gsl_matrix_set(A, 0, i, trajectory1.x[i]); 1185 gsl_matrix_set(A, 1, i, trajectory2.x[i]); 1186 gsl_matrix_set(A, 2, i, normal.x[i]); 1187 gsl_vector_set(x,i, (Trajectories[Walker].R.at(startstep).x[i] - Trajectories[Runner].R.at(startstep).x[i])); 1188 } 1189 // solve the linear system by Householder transformations 1190 gsl_linalg_HH_svx(A, x); 1191 // distance from last component 1192 tmp = gsl_vector_get(x,2); 1193 // *out << " with distance " << tmp << "." << endl; 1194 // test whether we really have the intersection (by checking on c_1 and c_2) 1195 TestVector.CopyVector(&Trajectories[Runner].R.at(startstep)); 1196 trajectory2.Scale(gsl_vector_get(x,1)); 1197 TestVector.AddVector(&trajectory2); 1198 normal.Scale(gsl_vector_get(x,2)); 1199 TestVector.AddVector(&normal); 1200 TestVector.SubtractVector(&Trajectories[Walker].R.at(startstep)); 1201 trajectory1.Scale(gsl_vector_get(x,0)); 1202 TestVector.SubtractVector(&trajectory1); 1203 if (TestVector.Norm() < MYEPSILON) { 1204 // *out << Verbose(2) << "Test: ok.\tDistance of " << tmp << " is correct." << endl; 1205 } else { 1206 // *out << Verbose(2) << "Test: failed.\tIntersection is off by "; 1207 // *out << TestVector; 1208 // *out << "." << endl; 1209 } 1210 } 1211 // add up 1212 tmp *= IsAngstroem ? 1. : 1./AtomicLengthToAngstroem; 1213 if (fabs(tmp) > MYEPSILON) { 1214 result += constants[1] * 1./tmp; 1215 //*out << Verbose(4) << "Adding " << 1./tmp*constants[1] << "." << endl; 1216 } 1217 } 1218 1219 // third term: penalty for equal targets 1220 Runner = start; 1221 while (Runner->next != end) { 1222 Runner = Runner->next; 1223 if ((PermutationMap[Walker->nr] == PermutationMap[Runner->nr]) && (Walker->nr < Runner->nr)) { 1224 Sprinter = PermutationMap[Walker->nr]; 1225 // *out << *Walker << " and " << *Runner << " are heading to the same target at "; 1226 // *out << Trajectories[Sprinter].R.at(endstep); 1227 // *out << ", penalting." << endl; 1228 result += constants[2]; 1229 //*out << Verbose(4) << "Adding " << constants[2] << "." << endl; 1230 } 1231 } 1232 } 1233 1234 return result; 1235 }; 1236 1237 void PrintPermutationMap(ofstream *out, atom **PermutationMap, int Nr) 1238 { 1239 stringstream zeile1, zeile2; 1240 int *DoubleList = (int *) Malloc(Nr*sizeof(int), "PrintPermutationMap: *DoubleList"); 1241 int doubles = 0; 1242 for (int i=0;i<Nr;i++) 1243 DoubleList[i] = 0; 1244 zeile1 << "PermutationMap: "; 1245 zeile2 << " "; 1246 for (int i=0;i<Nr;i++) { 1247 DoubleList[PermutationMap[i]->nr]++; 1248 zeile1 << i << " "; 1249 zeile2 << PermutationMap[i]->nr << " "; 1250 } 1251 for (int i=0;i<Nr;i++) 1252 if (DoubleList[i] > 1) 1253 doubles++; 1254 // *out << "Found " << doubles << " Doubles." << endl; 1255 Free((void **)&DoubleList, "PrintPermutationMap: *DoubleList"); 1256 // *out << zeile1.str() << endl << zeile2.str() << endl; 1257 }; 1258 1259 /** Minimises the extra potential for constrained molecular dynamics and gives forces and the constrained potential energy. 1260 * We do the following: 1261 * -# Generate a distance list from all source to all target points 1262 * -# Sort this per source point 1263 * -# Take for each source point the target point with minimum distance, use this as initial permutation 1264 * -# check whether molecule::ConstrainedPotential() is greater than injective penalty 1265 * -# If so, we go through each source point, stepping down in the sorted target point distance list and re-checking potential. 1266 * -# Next, we only apply transformations that keep the injectivity of the permutations list. 1267 * -# Hence, for one source point we step down the ladder and seek the corresponding owner of this new target 1268 * point and try to change it for one with lesser distance, or for the next one with greater distance, but only 1269 * if this decreases the conditional potential. 1270 * -# finished. 1271 * -# Then, we calculate the forces by taking the spatial derivative, where we scale the potential to such a degree, 1272 * that the total force is always pointing in direction of the constraint force (ensuring that we move in the 1273 * right direction). 1274 * -# Finally, we calculate the potential energy and return. 1275 * \param *out output stream for debugging 1276 * \param **PermutationMap on return: mapping between the atom label of the initial and the final configuration 1277 * \param startstep current MD step giving initial position between which and \a endstep we perform the constrained MD (as further steps are always concatenated) 1278 * \param endstep step giving final position in constrained MD 1279 * \param IsAngstroem whether coordinates are in angstroem (true) or bohrradius (false) 1280 * \sa molecule::VerletForceIntegration() 1281 * \return potential energy (and allocated **PermutationMap (array of molecule::AtomCount ^2) 1282 * \todo The constrained potential's constants are set to fixed values right now, but they should scale based on checks of the system in order 1283 * to ensure they're properties (e.g. constants[2] always greater than the energy of the system). 1284 * \bug this all is not O(N log N) but O(N^2) 1285 */ 1286 double molecule::MinimiseConstrainedPotential(ofstream *out, atom **&PermutationMap, int startstep, int endstep, bool IsAngstroem) 1287 { 1288 double Potential, OldPotential, OlderPotential; 1289 PermutationMap = (atom **) Malloc(AtomCount*sizeof(atom *), "molecule::MinimiseConstrainedPotential: **PermutationMap"); 1290 DistanceMap **DistanceList = (DistanceMap **) Malloc(AtomCount*sizeof(DistanceMap *), "molecule::MinimiseConstrainedPotential: **DistanceList"); 1291 DistanceMap::iterator *DistanceIterators = (DistanceMap::iterator *) Malloc(AtomCount*sizeof(DistanceMap::iterator), "molecule::MinimiseConstrainedPotential: *DistanceIterators"); 1292 int *DoubleList = (int *) Malloc(AtomCount*sizeof(int), "molecule::MinimiseConstrainedPotential: *DoubleList"); 1293 DistanceMap::iterator *StepList = (DistanceMap::iterator *) Malloc(AtomCount*sizeof(DistanceMap::iterator), "molecule::MinimiseConstrainedPotential: *StepList"); 1294 double constants[3]; 1295 int round; 1296 atom *Walker = NULL, *Runner = NULL, *Sprinter = NULL; 1297 DistanceMap::iterator Rider, Strider; 1298 1299 /// Minimise the potential 1300 // set Lagrange multiplier constants 1301 constants[0] = 10.; 1302 constants[1] = 1.; 1303 constants[2] = 1e+7; // just a huge penalty 1304 // generate the distance list 1305 *out << Verbose(1) << "Creating the distance list ... " << endl; 1306 for (int i=AtomCount; i--;) { 1307 DoubleList[i] = 0; // stores for how many atoms in startstep this atom is a target in endstep 1308 DistanceList[i] = new DistanceMap; // is the distance sorted target list per atom 1309 DistanceList[i]->clear(); 1310 } 1311 *out << Verbose(1) << "Filling the distance list ... " << endl; 1312 Walker = start; 1313 while (Walker->next != end) { 1314 Walker = Walker->next; 1315 Runner = start; 1316 while(Runner->next != end) { 1317 Runner = Runner->next; 1318 DistanceList[Walker->nr]->insert( DistancePair(Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(endstep)), Runner) ); 1319 } 1320 } 1321 // create the initial PermutationMap (source -> target) 1322 Walker = start; 1323 while (Walker->next != end) { 1324 Walker = Walker->next; 1325 StepList[Walker->nr] = DistanceList[Walker->nr]->begin(); // stores the step to the next iterator that could be a possible next target 1326 PermutationMap[Walker->nr] = DistanceList[Walker->nr]->begin()->second; // always pick target with the smallest distance 1327 DoubleList[DistanceList[Walker->nr]->begin()->second->nr]++; // increase this target's source count (>1? not injective) 1328 DistanceIterators[Walker->nr] = DistanceList[Walker->nr]->begin(); // and remember which one we picked 1329 *out << *Walker << " starts with distance " << DistanceList[Walker->nr]->begin()->first << "." << endl; 1330 } 1331 *out << Verbose(1) << "done." << endl; 1332 // make the PermutationMap injective by checking whether we have a non-zero constants[2] term in it 1333 *out << Verbose(1) << "Making the PermutationMap injective ... " << endl; 1334 Walker = start; 1335 DistanceMap::iterator NewBase; 1336 OldPotential = fabs(ConstrainedPotential(out, PermutationMap, startstep, endstep, constants, IsAngstroem)); 1337 while ((OldPotential) > constants[2]) { 1338 PrintPermutationMap(out, PermutationMap, AtomCount); 1339 Walker = Walker->next; 1340 if (Walker == end) // round-robin at the end 1341 Walker = start->next; 1342 if (DoubleList[DistanceIterators[Walker->nr]->second->nr] <= 1) // no need to make those injective that aren't 1343 continue; 1344 // now, try finding a new one 1345 NewBase = DistanceIterators[Walker->nr]; // store old base 1346 do { 1347 NewBase++; // take next further distance in distance to targets list that's a target of no one 1348 } while ((DoubleList[NewBase->second->nr] != 0) && (NewBase != DistanceList[Walker->nr]->end())); 1349 if (NewBase != DistanceList[Walker->nr]->end()) { 1350 PermutationMap[Walker->nr] = NewBase->second; 1351 Potential = fabs(ConstrainedPotential(out, PermutationMap, startstep, endstep, constants, IsAngstroem)); 1352 if (Potential > OldPotential) { // undo 1353 PermutationMap[Walker->nr] = DistanceIterators[Walker->nr]->second; 1354 } else { // do 1355 DoubleList[DistanceIterators[Walker->nr]->second->nr]--; // decrease the old entry in the doubles list 1356 DoubleList[NewBase->second->nr]++; // increase the old entry in the doubles list 1357 DistanceIterators[Walker->nr] = NewBase; 1358 OldPotential = Potential; 1359 *out << Verbose(3) << "Found a new permutation, new potential is " << OldPotential << "." << endl; 1360 } 1361 } 1362 } 1363 for (int i=AtomCount; i--;) // now each single entry in the DoubleList should be <=1 1364 if (DoubleList[i] > 1) { 1365 cerr << "Failed to create an injective PermutationMap!" << endl; 1366 exit(1); 1367 } 1368 *out << Verbose(1) << "done." << endl; 1369 Free((void **)&DoubleList, "molecule::MinimiseConstrainedPotential: *DoubleList"); 1370 // argument minimise the constrained potential in this injective PermutationMap 1371 *out << Verbose(1) << "Argument minimising the PermutationMap, at current potential " << OldPotential << " ... " << endl; 1372 OldPotential = 1e+10; 1373 round = 0; 1374 do { 1375 *out << "Starting round " << ++round << " ... " << endl; 1376 OlderPotential = OldPotential; 1377 do { 1378 Walker = start; 1379 while (Walker->next != end) { // pick one 1380 Walker = Walker->next; 1381 PrintPermutationMap(out, PermutationMap, AtomCount); 1382 Sprinter = DistanceIterators[Walker->nr]->second; // store initial partner 1383 Strider = DistanceIterators[Walker->nr]; //remember old iterator 1384 DistanceIterators[Walker->nr] = StepList[Walker->nr]; 1385 if (DistanceIterators[Walker->nr] == DistanceList[Walker->nr]->end()) {// stop, before we run through the list and still on 1386 DistanceIterators[Walker->nr] == DistanceList[Walker->nr]->begin(); 1387 break; 1388 } 1389 //*out << Verbose(2) << "Current Walker: " << *Walker << " with old/next candidate " << *Sprinter << "/" << *DistanceIterators[Walker->nr]->second << "." << endl; 1390 // find source of the new target 1391 Runner = start->next; 1392 while(Runner != end) { // find the source whose toes we might be stepping on (Walker's new target should be in use by another already) 1393 if (PermutationMap[Runner->nr] == DistanceIterators[Walker->nr]->second) { 1394 //*out << Verbose(2) << "Found the corresponding owner " << *Runner << " to " << *PermutationMap[Runner->nr] << "." << endl; 1395 break; 1396 } 1397 Runner = Runner->next; 1398 } 1399 if (Runner != end) { // we found the other source 1400 // then look in its distance list for Sprinter 1401 Rider = DistanceList[Runner->nr]->begin(); 1402 for (; Rider != DistanceList[Runner->nr]->end(); Rider++) 1403 if (Rider->second == Sprinter) 1404 break; 1405 if (Rider != DistanceList[Runner->nr]->end()) { // if we have found one 1406 //*out << Verbose(2) << "Current Other: " << *Runner << " with old/next candidate " << *PermutationMap[Runner->nr] << "/" << *Rider->second << "." << endl; 1407 // exchange both 1408 PermutationMap[Walker->nr] = DistanceIterators[Walker->nr]->second; // put next farther distance into PermutationMap 1409 PermutationMap[Runner->nr] = Sprinter; // and hand the old target to its respective owner 1410 PrintPermutationMap(out, PermutationMap, AtomCount); 1411 // calculate the new potential 1412 //*out << Verbose(2) << "Checking new potential ..." << endl; 1413 Potential = ConstrainedPotential(out, PermutationMap, startstep, endstep, constants, IsAngstroem); 1414 if (Potential > OldPotential) { // we made everything worse! Undo ... 1415 //*out << Verbose(3) << "Nay, made the potential worse: " << Potential << " vs. " << OldPotential << "!" << endl; 1416 //*out << Verbose(3) << "Setting " << *Runner << "'s source to " << *DistanceIterators[Runner->nr]->second << "." << endl; 1417 // Undo for Runner (note, we haven't moved the iteration yet, we may use this) 1418 PermutationMap[Runner->nr] = DistanceIterators[Runner->nr]->second; 1419 // Undo for Walker 1420 DistanceIterators[Walker->nr] = Strider; // take next farther distance target 1421 //*out << Verbose(3) << "Setting " << *Walker << "'s source to " << *DistanceIterators[Walker->nr]->second << "." << endl; 1422 PermutationMap[Walker->nr] = DistanceIterators[Walker->nr]->second; 1423 } else { 1424 DistanceIterators[Runner->nr] = Rider; // if successful also move the pointer in the iterator list 1425 *out << Verbose(3) << "Found a better permutation, new potential is " << Potential << " vs." << OldPotential << "." << endl; 1426 OldPotential = Potential; 1427 } 1428 if (Potential > constants[2]) { 1429 cerr << "ERROR: The two-step permutation procedure did not maintain injectivity!" << endl; 1430 exit(255); 1431 } 1432 //*out << endl; 1433 } else { 1434 cerr << "ERROR: " << *Runner << " was not the owner of " << *Sprinter << "!" << endl; 1435 exit(255); 1436 } 1437 } else { 1438 PermutationMap[Walker->nr] = DistanceIterators[Walker->nr]->second; // new target has no source! 1439 } 1440 StepList[Walker->nr]++; // take next farther distance target 1441 } 1442 } while (Walker->next != end); 1443 } while ((OlderPotential - OldPotential) > 1e-3); 1444 *out << Verbose(1) << "done." << endl; 1445 1446 1447 /// free memory and return with evaluated potential 1448 for (int i=AtomCount; i--;) 1449 DistanceList[i]->clear(); 1450 Free((void **)&DistanceList, "molecule::MinimiseConstrainedPotential: **DistanceList"); 1451 Free((void **)&DistanceIterators, "molecule::MinimiseConstrainedPotential: *DistanceIterators"); 1452 return ConstrainedPotential(out, PermutationMap, startstep, endstep, constants, IsAngstroem); 1453 }; 1454 1455 /** Evaluates the (distance-related part) of the constrained potential for the constrained forces. 1456 * \param *out output stream for debugging 1457 * \param startstep current MD step giving initial position between which and \a endstep we perform the constrained MD (as further steps are always concatenated) 1458 * \param endstep step giving final position in constrained MD 1459 * \param **PermutationMap mapping between the atom label of the initial and the final configuration 1460 * \param *Force ForceMatrix containing force vectors from the external energy functional minimisation. 1461 * \todo the constant for the constrained potential distance part is hard-coded independently of the hard-coded value in MinimiseConstrainedPotential() 1462 */ 1463 void molecule::EvaluateConstrainedForces(ofstream *out, int startstep, int endstep, atom **PermutationMap, ForceMatrix *Force) 1464 { 1465 double constant = 10.; 1466 atom *Walker = NULL, *Sprinter = NULL; 1467 1468 /// evaluate forces (only the distance to target dependent part) with the final PermutationMap 1469 *out << Verbose(1) << "Calculating forces and adding onto ForceMatrix ... " << endl; 1470 Walker = start; 1471 while (Walker->next != NULL) { 1472 Walker = Walker->next; 1473 Sprinter = PermutationMap[Walker->nr]; 1474 // set forces 1475 for (int i=NDIM;i++;) 1476 Force->Matrix[0][Walker->nr][5+i] += 2.*constant*sqrt(Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Sprinter].R.at(endstep))); 1477 } 1478 *out << Verbose(1) << "done." << endl; 1479 }; 1480 1481 /** Performs a linear interpolation between two desired atomic configurations with a given number of steps. 1482 * Note, step number is config::MaxOuterStep 1483 * \param *out output stream for debugging 1484 * \param startstep stating initial configuration in molecule::Trajectories 1485 * \param endstep stating final configuration in molecule::Trajectories 1486 * \param &config configuration structure 1487 * \return true - success in writing step files, false - error writing files or only one step in molecule::Trajectories 1488 */ 1489 bool molecule::LinearInterpolationBetweenConfiguration(ofstream *out, int startstep, int endstep, const char *prefix, config &configuration) 1490 { 1491 molecule *mol = NULL; 1492 bool status = true; 1493 int MaxSteps = configuration.MaxOuterStep; 1494 MoleculeListClass *MoleculePerStep = new MoleculeListClass(); 1495 // Get the Permutation Map by MinimiseConstrainedPotential 1496 atom **PermutationMap = NULL; 1497 atom *Walker = NULL, *Sprinter = NULL; 1498 MinimiseConstrainedPotential(out, PermutationMap, startstep, endstep, configuration.GetIsAngstroem()); 1499 1500 // check whether we have sufficient space in Trajectories for each atom 1501 Walker = start; 1502 while (Walker->next != end) { 1503 Walker = Walker->next; 1504 if (Trajectories[Walker].R.size() <= (unsigned int)(MaxSteps)) { 1505 //cout << "Increasing size for trajectory array of " << keyword << " to " << (MaxSteps+1) << "." << endl; 1506 Trajectories[Walker].R.resize(MaxSteps+1); 1507 Trajectories[Walker].U.resize(MaxSteps+1); 1508 Trajectories[Walker].F.resize(MaxSteps+1); 1509 } 1510 } 1511 // push endstep to last one 1512 Walker = start; 1513 while (Walker->next != end) { // remove the endstep (is now the very last one) 1514 Walker = Walker->next; 1515 for (int n=NDIM;n--;) { 1516 Trajectories[Walker].R.at(MaxSteps).x[n] = Trajectories[Walker].R.at(endstep).x[n]; 1517 Trajectories[Walker].U.at(MaxSteps).x[n] = Trajectories[Walker].U.at(endstep).x[n]; 1518 Trajectories[Walker].F.at(MaxSteps).x[n] = Trajectories[Walker].F.at(endstep).x[n]; 1519 } 1520 } 1521 endstep = MaxSteps; 1522 1523 // go through all steps and add the molecular configuration to the list and to the Trajectories of \a this molecule 1524 *out << Verbose(1) << "Filling intermediate " << MaxSteps << " steps with MDSteps of " << MDSteps << "." << endl; 1525 for (int step = 0; step <= MaxSteps; step++) { 1526 mol = new molecule(elemente); 1527 MoleculePerStep->insert(mol); 1528 Walker = start; 1529 while (Walker->next != end) { 1530 Walker = Walker->next; 1531 // add to molecule list 1532 Sprinter = mol->AddCopyAtom(Walker); 1533 for (int n=NDIM;n--;) { 1534 Sprinter->x.x[n] = Trajectories[Walker].R.at(startstep).x[n] + (Trajectories[PermutationMap[Walker->nr]].R.at(endstep).x[n] - Trajectories[Walker].R.at(startstep).x[n])*((double)step/(double)MaxSteps); 1535 // add to Trajectories 1536 //*out << Verbose(3) << step << ">=" << MDSteps-1 << endl; 1537 if (step < MaxSteps) { 1538 Trajectories[Walker].R.at(step).x[n] = Trajectories[Walker].R.at(startstep).x[n] + (Trajectories[PermutationMap[Walker->nr]].R.at(endstep).x[n] - Trajectories[Walker].R.at(startstep).x[n])*((double)step/(double)MaxSteps); 1539 Trajectories[Walker].U.at(step).x[n] = 0.; 1540 Trajectories[Walker].F.at(step).x[n] = 0.; 1541 } 1542 } 1543 } 1544 } 1545 MDSteps = MaxSteps+1; // otherwise new Trajectories' points aren't stored on save&exit 1546 1547 // store the list to single step files 1548 int *SortIndex = (int *) Malloc(AtomCount*sizeof(int), "molecule::LinearInterpolationBetweenConfiguration: *SortIndex"); 1549 for (int i=AtomCount; i--; ) 1550 SortIndex[i] = i; 1551 status = MoleculePerStep->OutputConfigForListOfFragments(out, &configuration, SortIndex); 1552 1553 // free and return 1554 Free((void **)&PermutationMap, "molecule::MinimiseConstrainedPotential: *PermutationMap"); 1555 delete(MoleculePerStep); 1556 return status; 1557 }; 1558 1085 1559 /** Parses nuclear forces from file and performs Verlet integration. 1086 1560 * Note that we assume the parsed forces to be in atomic units (hence, if coordinates are in angstroem, we 1087 1561 * have to transform them). 1088 1562 * This adds a new MD step to the config file. 1563 * \param *out output stream for debugging 1089 1564 * \param *file filename 1565 * \param config structure with config::Deltat, config::IsAngstroem, config::DoConstrained 1090 1566 * \param delta_t time step width in atomic units 1091 1567 * \param IsAngstroem whether coordinates are in angstroem (true) or bohrradius (false) 1568 * \param DoConstrained whether we perform a constrained (>0, target step in molecule::trajectories) or unconstrained (0) molecular dynamics, \sa molecule::MinimiseConstrainedPotential() 1092 1569 * \return true - file found and parsed, false - file not found or imparsable 1093 * /1094 bool molecule::VerletForceIntegration(char *file, double delta_t, bool IsAngstroem) 1095 { 1096 element *runner = elemente->start; 1570 * \todo This is not yet checked if it is correctly working with DoConstrained set to true. 1571 */ 1572 bool molecule::VerletForceIntegration(ofstream *out, char *file, config &configuration) 1573 { 1097 1574 atom *walker = NULL; 1098 int AtomNo;1099 1575 ifstream input(file); 1100 1576 string token; 1101 1577 stringstream item; 1102 double a, IonMass;1578 double IonMass, Vector[NDIM], ConstrainedPotentialEnergy, ActualTemp; 1103 1579 ForceMatrix Force; 1104 Vector tmpvector;1105 1580 1106 1581 CountElements(); // make sure ElementsInMolecule is up to date … … 1120 1595 } 1121 1596 // correct Forces 1122 // for(int d=0;d<NDIM;d++) 1123 // tmpvector.x[d] = 0.; 1124 // for(int i=0;i<AtomCount;i++) 1125 // for(int d=0;d<NDIM;d++) { 1126 // tmpvector.x[d] += Force.Matrix[0][i][d+5]; 1127 // } 1128 // for(int i=0;i<AtomCount;i++) 1129 // for(int d=0;d<NDIM;d++) { 1130 // Force.Matrix[0][i][d+5] -= tmpvector.x[d]/(double)AtomCount; 1131 // } 1597 for(int d=0;d<NDIM;d++) 1598 Vector[d] = 0.; 1599 for(int i=0;i<AtomCount;i++) 1600 for(int d=0;d<NDIM;d++) { 1601 Vector[d] += Force.Matrix[0][i][d+5]; 1602 } 1603 for(int i=0;i<AtomCount;i++) 1604 for(int d=0;d<NDIM;d++) { 1605 Force.Matrix[0][i][d+5] -= Vector[d]/(double)AtomCount; 1606 } 1607 // solve a constrained potential if we are meant to 1608 if (configuration.DoConstrainedMD) { 1609 // calculate forces and potential 1610 atom **PermutationMap = NULL; 1611 ConstrainedPotentialEnergy = MinimiseConstrainedPotential(out, PermutationMap,configuration.DoConstrainedMD, 0, configuration.GetIsAngstroem()); 1612 EvaluateConstrainedForces(out, configuration.DoConstrainedMD, 0, PermutationMap, &Force); 1613 Free((void **)&PermutationMap, "molecule::MinimiseConstrainedPotential: *PermutationMap"); 1614 } 1615 1132 1616 // and perform Verlet integration for each atom with position, velocity and force vector 1133 runner = elemente->start; 1134 while (runner->next != elemente->end) { // go through every element 1135 runner = runner->next; 1136 IonMass = runner->mass; 1137 a = delta_t*0.5/IonMass; // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a 1138 if (ElementsInMolecule[runner->Z]) { // if this element got atoms 1139 AtomNo = 0; 1617 walker = start; 1618 while (walker->next != end) { // go through every atom of this element 1619 walker = walker->next; 1620 //a = configuration.Deltat*0.5/walker->type->mass; // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a 1621 // check size of vectors 1622 if (Trajectories[walker].R.size() <= (unsigned int)(MDSteps)) { 1623 //out << "Increasing size for trajectory array of " << *walker << " to " << (size+10) << "." << endl; 1624 Trajectories[walker].R.resize(MDSteps+10); 1625 Trajectories[walker].U.resize(MDSteps+10); 1626 Trajectories[walker].F.resize(MDSteps+10); 1627 } 1628 1629 // Update R (and F) 1630 for (int d=0; d<NDIM; d++) { 1631 Trajectories[walker].F.at(MDSteps).x[d] = -Force.Matrix[0][walker->nr][d+5]*(configuration.GetIsAngstroem() ? AtomicLengthToAngstroem : 1.); 1632 Trajectories[walker].R.at(MDSteps).x[d] = Trajectories[walker].R.at(MDSteps-1).x[d]; 1633 Trajectories[walker].R.at(MDSteps).x[d] += configuration.Deltat*(Trajectories[walker].U.at(MDSteps-1).x[d]); // s(t) = s(0) + v * deltat + 1/2 a * deltat^2 1634 Trajectories[walker].R.at(MDSteps).x[d] += 0.5*configuration.Deltat*configuration.Deltat*(Trajectories[walker].F.at(MDSteps).x[d]/walker->type->mass); // F = m * a and s = 0.5 * F/m * t^2 = F * a * t 1635 } 1636 // Update U 1637 for (int d=0; d<NDIM; d++) { 1638 Trajectories[walker].U.at(MDSteps).x[d] = Trajectories[walker].U.at(MDSteps-1).x[d]; 1639 Trajectories[walker].U.at(MDSteps).x[d] += configuration.Deltat * (Trajectories[walker].F.at(MDSteps).x[d]+Trajectories[walker].F.at(MDSteps-1).x[d]/walker->type->mass); // v = F/m * t 1640 } 1641 // out << "Integrated position&velocity of step " << (MDSteps) << ": ("; 1642 // for (int d=0;d<NDIM;d++) 1643 // out << Trajectories[walker].R.at(MDSteps).x[d] << " "; // next step 1644 // out << ")\t("; 1645 // for (int d=0;d<NDIM;d++) 1646 // cout << Trajectories[walker].U.at(MDSteps).x[d] << " "; // next step 1647 // out << ")" << endl; 1648 // next atom 1649 } 1650 } 1651 // correct velocities (rather momenta) so that center of mass remains motionless 1652 for(int d=0;d<NDIM;d++) 1653 Vector[d] = 0.; 1654 IonMass = 0.; 1655 walker = start; 1656 while (walker->next != end) { // go through every atom 1657 walker = walker->next; 1658 IonMass += walker->type->mass; // sum up total mass 1659 for(int d=0;d<NDIM;d++) { 1660 Vector[d] += Trajectories[walker].U.at(MDSteps).x[d]*walker->type->mass; 1661 } 1662 } 1663 // correct velocities (rather momenta) so that center of mass remains motionless 1664 for(int d=0;d<NDIM;d++) 1665 Vector[d] /= IonMass; 1666 ActualTemp = 0.; 1667 walker = start; 1668 while (walker->next != end) { // go through every atom of this element 1669 walker = walker->next; 1670 for(int d=0;d<NDIM;d++) { 1671 Trajectories[walker].U.at(MDSteps).x[d] -= Vector[d]; 1672 ActualTemp += 0.5 * walker->type->mass * Trajectories[walker].U.at(MDSteps).x[d] * Trajectories[walker].U.at(MDSteps).x[d]; 1673 } 1674 } 1675 Thermostats(configuration, ActualTemp, Berendsen); 1676 MDSteps++; 1677 1678 1679 // exit 1680 return true; 1681 }; 1682 1683 /** Implementation of various thermostats. 1684 * All these thermostats apply an additional force which has the following forms: 1685 * -# Woodcock 1686 * \f$p_i \rightarrow \sqrt{\frac{T_0}{T}} \cdot p_i\f$ 1687 * -# Gaussian 1688 * \f$ \frac{ \sum_i \frac{p_i}{m_i} \frac{\partial V}{\partial q_i}} {\sum_i \frac{p^2_i}{m_i}} \cdot p_i\f$ 1689 * -# Langevin 1690 * \f$p_{i,n} \rightarrow \sqrt{1-\alpha^2} p_{i,0} + \alpha p_r\f$ 1691 * -# Berendsen 1692 * \f$p_i \rightarrow \left [ 1+ \frac{\delta t}{\tau_T} \left ( \frac{T_0}{T} \right ) \right ]^{\frac{1}{2}} \cdot p_i\f$ 1693 * -# Nose-Hoover 1694 * \f$\zeta p_i \f$ with \f$\frac{\partial \zeta}{\partial t} = \frac{1}{M_s} \left ( \sum^N_{i=1} \frac{p_i^2}{m_i} - g k_B T \right )\f$ 1695 * These Thermostats either simply rescale the velocities, thus this function should be called after ion velocities have been updated, and/or 1696 * have a constraint force acting additionally on the ions. In the latter case, the ion speeds have to be modified 1697 * belatedly and the constraint force set. 1698 * \param *P Problem at hand 1699 * \param i which of the thermostats to take: 0 - none, 1 - Woodcock, 2 - Gaussian, 3 - Langevin, 4 - Berendsen, 5 - Nose-Hoover 1700 * \sa InitThermostat() 1701 */ 1702 void molecule::Thermostats(config &configuration, double ActualTemp, int Thermostat) 1703 { 1704 double ekin = 0.; 1705 double E = 0., G = 0.; 1706 double delta_alpha = 0.; 1707 double ScaleTempFactor; 1708 double sigma; 1709 double IonMass; 1710 int d; 1711 gsl_rng * r; 1712 const gsl_rng_type * T; 1713 double *U = NULL, *F = NULL, FConstraint[NDIM]; 1714 atom *walker = NULL; 1715 1716 // calculate scale configuration 1717 ScaleTempFactor = configuration.TargetTemp/ActualTemp; 1718 1719 // differentating between the various thermostats 1720 switch(Thermostat) { 1721 case None: 1722 cout << Verbose(2) << "Applying no thermostat..." << endl; 1723 break; 1724 case Woodcock: 1725 if ((configuration.ScaleTempStep > 0) && ((MDSteps-1) % configuration.ScaleTempStep == 0)) { 1726 cout << Verbose(2) << "Applying Woodcock thermostat..." << endl; 1140 1727 walker = start; 1141 1728 while (walker->next != end) { // go through every atom of this element 1142 1729 walker = walker->next; 1143 if (walker->type == runner) { // if this atom fits to element 1144 // check size of vectors 1145 if (Trajectories[walker].R.size() <= (unsigned int)(MDSteps)) { 1146 //cout << "Increasing size for trajectory array of " << *walker << " to " << (size+10) << "." << endl; 1147 Trajectories[walker].R.resize(MDSteps+10); 1148 Trajectories[walker].U.resize(MDSteps+10); 1149 Trajectories[walker].F.resize(MDSteps+10); 1730 IonMass = walker->type->mass; 1731 U = Trajectories[walker].U.at(MDSteps).x; 1732 if (walker->FixedIon == 0) // even FixedIon moves, only not by other's forces 1733 for (d=0; d<NDIM; d++) { 1734 U[d] *= sqrt(ScaleTempFactor); 1735 ekin += 0.5*IonMass * U[d]*U[d]; 1150 1736 } 1151 // 1. calculate x(t+\delta t) 1152 for (int d=0; d<NDIM; d++) { 1153 Trajectories[walker].F.at(MDSteps).x[d] = -Force.Matrix[0][AtomNo][d+5]; 1154 Trajectories[walker].R.at(MDSteps).x[d] = Trajectories[walker].R.at(MDSteps-1).x[d]; 1155 Trajectories[walker].R.at(MDSteps).x[d] += delta_t*(Trajectories[walker].U.at(MDSteps-1).x[d]); 1156 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 1737 } 1738 } 1739 break; 1740 case Gaussian: 1741 cout << Verbose(2) << "Applying Gaussian thermostat..." << endl; 1742 walker = start; 1743 while (walker->next != end) { // go through every atom of this element 1744 walker = walker->next; 1745 IonMass = walker->type->mass; 1746 U = Trajectories[walker].U.at(MDSteps).x; 1747 F = Trajectories[walker].F.at(MDSteps).x; 1748 if (walker->FixedIon == 0) // even FixedIon moves, only not by other's forces 1749 for (d=0; d<NDIM; d++) { 1750 G += U[d] * F[d]; 1751 E += U[d]*U[d]*IonMass; 1752 } 1753 } 1754 cout << Verbose(1) << "Gaussian Least Constraint constant is " << G/E << "." << endl; 1755 walker = start; 1756 while (walker->next != end) { // go through every atom of this element 1757 walker = walker->next; 1758 IonMass = walker->type->mass; 1759 U = Trajectories[walker].U.at(MDSteps).x; 1760 F = Trajectories[walker].F.at(MDSteps).x; 1761 if (walker->FixedIon == 0) // even FixedIon moves, only not by other's forces 1762 for (d=0; d<NDIM; d++) { 1763 FConstraint[d] = (G/E) * (U[d]*IonMass); 1764 U[d] += configuration.Deltat/IonMass * (FConstraint[d]); 1765 ekin += IonMass * U[d]*U[d]; 1766 } 1767 } 1768 break; 1769 case Langevin: 1770 cout << Verbose(2) << "Applying Langevin thermostat..." << endl; 1771 // init random number generator 1772 gsl_rng_env_setup(); 1773 T = gsl_rng_default; 1774 r = gsl_rng_alloc (T); 1775 // Go through each ion 1776 walker = start; 1777 while (walker->next != end) { // go through every atom of this element 1778 walker = walker->next; 1779 IonMass = walker->type->mass; 1780 sigma = sqrt(configuration.TargetTemp/IonMass); // sigma = (k_b T)/m (Hartree/atomicmass = atomiclength/atomictime) 1781 U = Trajectories[walker].U.at(MDSteps).x; 1782 F = Trajectories[walker].F.at(MDSteps).x; 1783 if (walker->FixedIon == 0) { // even FixedIon moves, only not by other's forces 1784 // throw a dice to determine whether it gets hit by a heat bath particle 1785 if (((((rand()/(double)RAND_MAX))*configuration.TempFrequency) < 1.)) { 1786 cout << Verbose(3) << "Particle " << *walker << " was hit (sigma " << sigma << "): " << sqrt(U[0]*U[0]+U[1]*U[1]+U[2]*U[2]) << " -> "; 1787 // pick three random numbers from a Boltzmann distribution around the desired temperature T for each momenta axis 1788 for (d=0; d<NDIM; d++) { 1789 U[d] = gsl_ran_gaussian (r, sigma); 1157 1790 } 1158 // 2. Calculate v(t+\delta t) 1159 for (int d=0; d<NDIM; d++) { 1160 Trajectories[walker].U.at(MDSteps).x[d] = Trajectories[walker].U.at(MDSteps-1).x[d]; 1161 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; 1162 } 1163 // cout << "Integrated position&velocity of step " << (MDSteps) << ": ("; 1164 // for (int d=0;d<NDIM;d++) 1165 // cout << Trajectories[walker].R.at(MDSteps).x[d] << " "; // next step 1166 // cout << ")\t("; 1167 // for (int d=0;d<NDIM;d++) 1168 // cout << Trajectories[walker].U.at(MDSteps).x[d] << " "; // next step 1169 // cout << ")" << endl; 1170 // next atom 1171 AtomNo++; 1791 cout << sqrt(U[0]*U[0]+U[1]*U[1]+U[2]*U[2]) << endl; 1792 } 1793 for (d=0; d<NDIM; d++) 1794 ekin += 0.5*IonMass * U[d]*U[d]; 1795 } 1796 } 1797 break; 1798 case Berendsen: 1799 cout << Verbose(2) << "Applying Berendsen-VanGunsteren thermostat..." << endl; 1800 walker = start; 1801 while (walker->next != end) { // go through every atom of this element 1802 walker = walker->next; 1803 IonMass = walker->type->mass; 1804 U = Trajectories[walker].U.at(MDSteps).x; 1805 F = Trajectories[walker].F.at(MDSteps).x; 1806 if (walker->FixedIon == 0) { // even FixedIon moves, only not by other's forces 1807 for (d=0; d<NDIM; d++) { 1808 U[d] *= sqrt(1+(configuration.Deltat/configuration.TempFrequency)*(ScaleTempFactor-1)); 1809 ekin += 0.5*IonMass * U[d]*U[d]; 1172 1810 } 1173 1811 } 1174 1812 } 1175 } 1176 } 1177 // // correct velocities (rather momenta) so that center of mass remains motionless 1178 // tmpvector.zero() 1179 // IonMass = 0.; 1180 // walker = start; 1181 // while (walker->next != end) { // go through every atom 1182 // walker = walker->next; 1183 // IonMass += walker->type->mass; // sum up total mass 1184 // for(int d=0;d<NDIM;d++) { 1185 // tmpvector.x[d] += Trajectories[walker].U.at(MDSteps).x[d]*walker->type->mass; 1186 // } 1187 // } 1188 // walker = start; 1189 // while (walker->next != end) { // go through every atom of this element 1190 // walker = walker->next; 1191 // for(int d=0;d<NDIM;d++) { 1192 // Trajectories[walker].U.at(MDSteps).x[d] -= tmpvector.x[d]*walker->type->mass/IonMass; 1193 // } 1194 // } 1195 MDSteps++; 1196 1197 1198 // exit 1199 return true; 1200 }; 1201 1202 /** Align all atoms in such a manner that given vector \a *n is along z axis. 1813 break; 1814 case NoseHoover: 1815 cout << Verbose(2) << "Applying Nose-Hoover thermostat..." << endl; 1816 // dynamically evolve alpha (the additional degree of freedom) 1817 delta_alpha = 0.; 1818 walker = start; 1819 while (walker->next != end) { // go through every atom of this element 1820 walker = walker->next; 1821 IonMass = walker->type->mass; 1822 U = Trajectories[walker].U.at(MDSteps).x; 1823 if (walker->FixedIon == 0) { // even FixedIon moves, only not by other's forces 1824 for (d=0; d<NDIM; d++) { 1825 delta_alpha += U[d]*U[d]*IonMass; 1826 } 1827 } 1828 } 1829 delta_alpha = (delta_alpha - (3.*AtomCount+1.) * configuration.TargetTemp)/(configuration.HooverMass*Units2Electronmass); 1830 configuration.alpha += delta_alpha*configuration.Deltat; 1831 cout << Verbose(3) << "alpha = " << delta_alpha << " * " << configuration.Deltat << " = " << configuration.alpha << "." << endl; 1832 // apply updated alpha as additional force 1833 walker = start; 1834 while (walker->next != end) { // go through every atom of this element 1835 walker = walker->next; 1836 IonMass = walker->type->mass; 1837 U = Trajectories[walker].U.at(MDSteps).x; 1838 if (walker->FixedIon == 0) { // even FixedIon moves, only not by other's forces 1839 for (d=0; d<NDIM; d++) { 1840 FConstraint[d] = - configuration.alpha * (U[d] * IonMass); 1841 U[d] += configuration.Deltat/IonMass * (FConstraint[d]); 1842 ekin += (0.5*IonMass) * U[d]*U[d]; 1843 } 1844 } 1845 } 1846 break; 1847 } 1848 cout << Verbose(1) << "Kinetic energy is " << ekin << "." << endl; 1849 }; 1850 1851 /** Align all atoms in such a manner that given vector \a *n is along z axis. 1203 1852 * \param n[] alignment vector. 1204 1853 */ … … 1267 1916 bool molecule::RemoveAtom(atom *pointer) 1268 1917 { 1269 if (ElementsInMolecule[pointer->type->Z] != 0) // this would indicate an error1918 if (ElementsInMolecule[pointer->type->Z] != 0) { // this would indicate an error 1270 1919 ElementsInMolecule[pointer->type->Z]--; // decrease number of atom of this element 1271 else 1920 AtomCount--; 1921 } else 1272 1922 cerr << "ERROR: Atom " << pointer->Name << " is of element " << pointer->type->Z << " but the entry in the table of the molecule is 0!" << endl; 1273 1923 if (ElementsInMolecule[pointer->type->Z] == 0) // was last atom of this element? … … 3093 3743 while (MolecularWalker->next != NULL) { 3094 3744 MolecularWalker = MolecularWalker->next; 3745 *out << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl; 3095 3746 LocalBackEdgeStack = new StackClass<bond *> (MolecularWalker->Leaf->BondCount); 3096 3747 // // check the list of local atoms for debugging … … 3108 3759 delete(LocalBackEdgeStack); 3109 3760 } 3110 3761 3111 3762 // ===== 3. if structure still valid, parse key set file and others ===== 3112 3763 FragmentationToDo = FragmentationToDo && ParseKeySetFile(out, configuration->configpath, ParsedFragmentList); … … 3114 3765 // ===== 4. check globally whether there's something to do actually (first adaptivity check) 3115 3766 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(out, configuration->configpath); 3116 3117 // =================================== Begin of FRAGMENTATION =============================== 3118 // ===== 6a. assign each keyset to its respective subgraph ===== 3767 3768 // =================================== Begin of FRAGMENTATION =============================== 3769 // ===== 6a. assign each keyset to its respective subgraph ===== 3119 3770 Subgraphs->next->AssignKeySetsToFragment(out, this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, (FragmentCounter = 0), true); 3120 3771 … … 3151 3802 delete(ParsedFragmentList); 3152 3803 delete[](MinimumRingSize); 3153 3804 3154 3805 3155 3806 // ==================================== End of FRAGMENTATION ============================================ … … 3244 3895 atom *Walker = NULL, *OtherAtom = NULL; 3245 3896 ReferenceStack->Push(Binder); 3246 3897 3247 3898 do { // go through all bonds and push local ones 3248 3899 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule … … 3714 4365 }; 3715 4366 4367 /** Creates \a MoleculeListClass of all unique fragments of the \a molecule containing \a Order atoms or vertices. 4368 * The picture to have in mind is that of a DFS "snake" of a certain length \a Order, i.e. as in the infamous 4369 * computer game, that winds through the connected graph representing the molecule. Color (white, 4370 * lightgray, darkgray, black) indicates whether a vertex has been discovered so far or not. Labels will help in 4371 * creating only unique fragments and not additional ones with vertices simply in different sequence. 4372 * The Predecessor is always the one that came before in discovering, needed on backstepping. And 4373 * finally, the ShortestPath is needed for removing vertices from the snake stack during the back- 4374 * stepping. 4375 * \param *out output stream for debugging 4376 * \param Order number of atoms in each fragment 4377 * \param *configuration configuration for writing config files for each fragment 4378 * \return List of all unique fragments with \a Order atoms 4379 */ 4380 /* 4381 MoleculeListClass * molecule::CreateListOfUniqueFragmentsOfOrder(ofstream *out, int Order, config *configuration) 4382 { 4383 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList"); 4384 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList"); 4385 int *Labels = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels"); 4386 enum Shading *ColorVertexList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList"); 4387 enum Shading *ColorEdgeList = (enum Shading *) Malloc(sizeof(enum Shading)*BondCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorBondList"); 4388 StackClass<atom *> *RootStack = new StackClass<atom *>(AtomCount); 4389 StackClass<atom *> *TouchedStack = new StackClass<atom *>((int)pow(4,Order)+2); // number of atoms reached from one with maximal 4 bonds plus Root itself 4390 StackClass<atom *> *SnakeStack = new StackClass<atom *>(Order+1); // equal to Order is not possible, as then the StackClass<atom *> cannot discern between full and empty stack! 4391 MoleculeLeafClass *Leaflet = NULL, *TempLeaf = NULL; 4392 MoleculeListClass *FragmentList = NULL; 4393 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL, *Removal = NULL; 4394 bond *Binder = NULL; 4395 int RunningIndex = 0, FragmentCounter = 0; 4396 4397 *out << Verbose(1) << "Begin of CreateListOfUniqueFragmentsOfOrder." << endl; 4398 4399 // reset parent list 4400 *out << Verbose(3) << "Resetting labels, parent, predecessor, color and shortest path lists." << endl; 4401 for (int i=0;i<AtomCount;i++) { // reset all atom labels 4402 // initialise each vertex as white with no predecessor, empty queue, color lightgray, not labelled, no sons 4403 Labels[i] = -1; 4404 SonList[i] = NULL; 4405 PredecessorList[i] = NULL; 4406 ColorVertexList[i] = white; 4407 ShortestPathList[i] = -1; 4408 } 4409 for (int i=0;i<BondCount;i++) 4410 ColorEdgeList[i] = white; 4411 RootStack->ClearStack(); // clearstack and push first atom if exists 4412 TouchedStack->ClearStack(); 4413 Walker = start->next; 4414 while ((Walker != end) 4415 #ifdef ADDHYDROGEN 4416 && (Walker->type->Z == 1) 4417 } 4418 } 4419 *out << ", SP of " << ShortestPathList[Walker->nr] << " and its color is " << GetColor(ColorVertexList[Walker->nr]) << "." << endl; 4420 4421 // then check the stack for a newly stumbled upon fragment 4422 if (SnakeStack->ItemCount() == Order) { // is stack full? 4423 // store the fragment if it is one and get a removal candidate 4424 Removal = StoreFragmentFromStack(out, Root, Walker, Leaflet, SnakeStack, ShortestPathList, SonList, Labels, &FragmentCounter, configuration); 4425 // remove the candidate if one was found 4426 if (Removal != NULL) { 4427 *out << Verbose(2) << "Removing item " << Removal->Name << " with SP of " << ShortestPathList[Removal->nr] << " from snake stack." << endl; 4428 SnakeStack->RemoveItem(Removal); 4429 ColorVertexList[Removal->nr] = lightgray; // return back to not on snake stack but explored marking 4430 if (Walker == Removal) { // if the current atom is to be removed, we also have to take a step back 4431 Walker = PredecessorList[Removal->nr]; 4432 *out << Verbose(2) << "Stepping back to " << Walker->Name << "." << endl; 4433 } 4434 } 4435 } else 4436 Removal = NULL; 4437 4438 // finally, look for a white neighbour as the next Walker 4439 Binder = NULL; 4440 if ((Removal == NULL) || (Walker != PredecessorList[Removal->nr])) { // don't look, if a new walker has been set above 4441 *out << Verbose(2) << "Snake has currently " << SnakeStack->ItemCount() << " item(s)." << endl; 4442 OtherAtom = NULL; // this is actually not needed, every atom has at least one neighbour 4443 if (ShortestPathList[Walker->nr] < Order) { 4444 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { 4445 Binder = ListOfBondsPerAtom[Walker->nr][i]; 4446 *out << Verbose(2) << "Current bond is " << *Binder << ": "; 4447 OtherAtom = Binder->GetOtherAtom(Walker); 4448 if ((Labels[OtherAtom->nr] != -1) && (Labels[OtherAtom->nr] < Labels[Root->nr])) { // we don't step up to labels bigger than us 4449 *out << "Label " << Labels[OtherAtom->nr] << " is smaller than Root's " << Labels[Root->nr] << "." << endl; 4450 //ColorVertexList[OtherAtom->nr] = lightgray; // mark as explored 4451 } else { // otherwise check its colour and element 4452 if ( 4453 (OtherAtom->type->Z != 1) && 4454 #endif 4455 (ColorEdgeList[Binder->nr] == white)) { // skip hydrogen, look for unexplored vertices 4456 *out << "Moving along " << GetColor(ColorEdgeList[Binder->nr]) << " bond " << Binder << " to " << ((ColorVertexList[OtherAtom->nr] == white) ? "unexplored" : "explored") << " item: " << OtherAtom->Name << "." << endl; 4457 // i find it currently rather sensible to always set the predecessor in order to find one's way back 4458 //if (PredecessorList[OtherAtom->nr] == NULL) { 4459 PredecessorList[OtherAtom->nr] = Walker; 4460 *out << Verbose(3) << "Setting Predecessor of " << OtherAtom->Name << " to " << PredecessorList[OtherAtom->nr]->Name << "." << endl; 4461 //} else { 4462 // *out << Verbose(3) << "Predecessor of " << OtherAtom->Name << " is " << PredecessorList[OtherAtom->nr]->Name << "." << endl; 4463 //} 4464 Walker = OtherAtom; 4465 break; 4466 } else { 4467 if (OtherAtom->type->Z == 1) 4468 *out << "Links to a hydrogen atom." << endl; 4469 else 4470 *out << "Bond has not white but " << GetColor(ColorEdgeList[Binder->nr]) << " color." << endl; 4471 } 4472 } 4473 } 4474 } else { // means we have stepped beyond the horizon: Return! 4475 Walker = PredecessorList[Walker->nr]; 4476 OtherAtom = Walker; 4477 *out << Verbose(3) << "We have gone too far, stepping back to " << Walker->Name << "." << endl; 4478 } 4479 if (Walker != OtherAtom) { // if no white neighbours anymore, color it black 4480 *out << Verbose(2) << "Coloring " << Walker->Name << " black." << endl; 4481 ColorVertexList[Walker->nr] = black; 4482 Walker = PredecessorList[Walker->nr]; 4483 } 4484 } 4485 } while ((Walker != Root) || (ColorVertexList[Root->nr] != black)); 4486 *out << Verbose(2) << "Inner Looping is finished." << endl; 4487 4488 // if we reset all AtomCount atoms, we have again technically O(N^2) ... 4489 *out << Verbose(2) << "Resetting lists." << endl; 4490 Walker = NULL; 4491 Binder = NULL; 4492 while (!TouchedStack->IsEmpty()) { 4493 Walker = TouchedStack->PopLast(); 4494 *out << Verbose(3) << "Re-initialising entries of " << *Walker << "." << endl; 4495 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) 4496 ColorEdgeList[ListOfBondsPerAtom[Walker->nr][i]->nr] = white; 4497 PredecessorList[Walker->nr] = NULL; 4498 ColorVertexList[Walker->nr] = white; 4499 ShortestPathList[Walker->nr] = -1; 4500 } 4501 } 4502 *out << Verbose(1) << "Outer Looping over all vertices is done." << endl; 4503 4504 // copy together 4505 *out << Verbose(1) << "Copying all fragments into MoleculeList structure." << endl; 4506 FragmentList = new MoleculeListClass(FragmentCounter, AtomCount); 4507 RunningIndex = 0; 4508 while ((Leaflet != NULL) && (RunningIndex < FragmentCounter)) { 4509 FragmentList->ListOfMolecules[RunningIndex++] = Leaflet->Leaf; 4510 Leaflet->Leaf = NULL; // prevent molecule from being removed 4511 TempLeaf = Leaflet; 4512 Leaflet = Leaflet->previous; 4513 delete(TempLeaf); 4514 }; 4515 4516 // free memory and exit 4517 Free((void **)&PredecessorList, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList"); 4518 Free((void **)&ShortestPathList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList"); 4519 Free((void **)&Labels, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels"); 4520 Free((void **)&ColorVertexList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList"); 4521 delete(RootStack); 4522 delete(TouchedStack); 4523 delete(SnakeStack); 4524 4525 *out << Verbose(1) << "End of CreateListOfUniqueFragmentsOfOrder." << endl; 4526 return FragmentList; 4527 }; 4528 */ 4529 3716 4530 /** Structure containing all values in power set combination generation. 3717 4531 */ … … 4545 5359 if (result) { 4546 5360 *out << Verbose(5) << "Calculating Centers of Gravity" << endl; 4547 Determine Center(CenterOfGravity);4548 OtherMolecule->Determine Center(OtherCenterOfGravity);5361 DeterminePeriodicCenter(CenterOfGravity); 5362 OtherMolecule->DeterminePeriodicCenter(OtherCenterOfGravity); 4549 5363 *out << Verbose(5) << "Center of Gravity: "; 4550 5364 CenterOfGravity.Output(out);
Note:
See TracChangeset
for help on using the changeset viewer.