Changeset f433ec for src/Dynamics
- Timestamp:
- Apr 10, 2018, 6:43:30 AM (7 years ago)
- Branches:
- AutomationFragmentation_failures, Candidate_v1.6.1, ChemicalSpaceEvaluator, Exclude_Hydrogens_annealWithBondGraph, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_contraction-expansion, Gui_displays_atomic_force_velocity, PythonUI_with_named_parameters, StoppableMakroAction, TremoloParser_IncreasedPrecision
- Children:
- 07d4b1
- Parents:
- 7b4e67
- git-author:
- Frederik Heber <frederik.heber@…> (07/18/17 22:24:12)
- git-committer:
- Frederik Heber <frederik.heber@…> (04/10/18 06:43:30)
- Location:
- src/Dynamics
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Dynamics/BondVectors.cpp
r7b4e67 rf433ec 45 45 #include "CodePatterns/Assert.hpp" 46 46 #include "CodePatterns/Log.hpp" 47 48 #include <levmar.h> 47 49 48 50 #include "Atom/atom.hpp" … … 111 113 } 112 114 115 struct WeightsMinimization { 116 117 static void evaluate(double *p, double *x, int m, int n, void *data) 118 { 119 // current weights in p, output to x 120 double *matrix = static_cast<double*>(data); 121 for(size_t i=0;i<(size_t)n;++i) { 122 x[i] = 0.; 123 for(size_t j=0;j<(size_t)n;++j) 124 x[i] += p[j]*matrix[i*n+j]; 125 // x[i] = .5*x[i]*x[i]; 126 } 127 } 128 129 static void evaluate_derivative(double *p, double *jac, int m, int n, void *data) 130 { 131 // current weights in p, output to x 132 double *matrix = static_cast<double*>(data); 133 // // tmp = (Bx - 1) 134 // double *tmp = new double[n]; 135 // for(size_t i=0;i<(size_t)n;++i) { 136 // tmp[i] = -1.; 137 // for(size_t j=0;j<(size_t)n;++j) 138 // tmp[i] += p[j]*matrix[i*n+j]; 139 // } 140 // // tmp(i) * B_(ij) 141 // for(size_t i=0;i<(size_t)n;++i) 142 // for(size_t j=0;j<(size_t)n;++j) 143 // jac[i*n+j] = tmp[i]*matrix[i*n+j]; 144 // delete[] tmp ; 145 for(size_t i=0;i<(size_t)n;++i) 146 for(size_t j=0;j<(size_t)n;++j) 147 jac[i*n+j] = matrix[i*n+j]; 148 } 149 150 static double* getMatrixFromBondVectors( 151 const std::vector<Vector> &_bondvectors 152 ) 153 { 154 const size_t n = _bondvectors.size(); 155 double *matrix = new double[n*n]; 156 size_t i=0; 157 for (std::vector<Vector>::const_iterator iter = _bondvectors.begin(); 158 iter != _bondvectors.end(); ++iter, ++i) { 159 size_t j=0; 160 for (std::vector<Vector>::const_iterator otheriter = _bondvectors.begin(); 161 otheriter != _bondvectors.end(); ++otheriter, ++j) { 162 // only magnitude is important not the sign 163 matrix[i*n+j] = fabs((*iter).ScalarProduct(*otheriter)); 164 } 165 } 166 167 return matrix; 168 } 169 }; 170 171 172 BondVectors::weights_t BondVectors::getWeightsForAtomAtStep( 173 const atom &_walker, 174 const std::vector<Vector> &_bondvectors, 175 const size_t &_step) const 176 { 177 // let levmar optimize 178 register int i, j; 179 int ret; 180 double *p; 181 double *x; 182 int n=_bondvectors.size(); 183 double opts[LM_OPTS_SZ], info[LM_INFO_SZ]; 184 185 double *matrix = WeightsMinimization::getMatrixFromBondVectors(_bondvectors); 186 187 weights_t weights(n, 0.); 188 189 // minim. options [\tau, \epsilon1, \epsilon2, \epsilon3]. Respectively the scale factor for initial \mu, 190 // * stopping thresholds for ||J^T e||_inf, ||Dp||_2 and ||e||_2. 191 opts[0]=LM_INIT_MU; opts[1]=1E-15; opts[2]=1E-15; opts[3]=1E-20; 192 opts[4]= LM_DIFF_DELTA; // relevant only if the Jacobian is approximated using finite differences; specifies forward differencing 193 //opts[4]=-LM_DIFF_DELTA; // specifies central differencing to approximate Jacobian; more accurate but more expensive to compute! 194 195 // prepare initial values for weights 196 p = new double[n]; 197 for (i=0;i<n;++i) 198 p[i] = 1.; 199 // prepare output value, i.e. the row sums 200 x = new double[n]; 201 for (i=0;i<n;++i) 202 x[i] = 1.; 203 204 { 205 double *work, *covar; 206 work=(double *)malloc((LM_DIF_WORKSZ(n, n)+n*n)*sizeof(double)); 207 if(!work){ 208 ELOG(0, "BondVectors::getWeightsForAtomAtStep() - memory allocation request failed."); 209 return weights; 210 } 211 covar=work+LM_DIF_WORKSZ(n, n); 212 213 // give this pointer as additional data to construct function pointer in 214 // LevMarCallback and call 215 double *lb = new double[n]; 216 double *ub = new double[n]; 217 for (i=0;i<n;++i) { 218 lb[i] = 1./(double)n; 219 ub[i] = 1.; 220 } 221 ret=dlevmar_bc_der( 222 &WeightsMinimization::evaluate, 223 &WeightsMinimization::evaluate_derivative, 224 p, x, n, n, lb, ub, NULL, 1000, opts, info, work, covar, matrix); // no Jacobian, caller allocates work memory, covariance estimated 225 delete[] lb; 226 delete[] ub; 227 228 if (0) 229 { 230 std::stringstream covar_msg; 231 covar_msg << "Covariance of the fit:\n"; 232 for(i=0; i<n; ++i){ 233 for(j=0; j<n; ++j) 234 covar_msg << covar[i*n+j] << " "; 235 covar_msg << std::endl; 236 } 237 covar_msg << std::endl; 238 LOG(1, "INFO: " << covar_msg.str()); 239 } 240 241 free(work); 242 } 243 244 if (DoLog(4)) { 245 std::stringstream result_msg; 246 result_msg << "Levenberg-Marquardt returned " << ret << " in " << info[5] << " iter, reason " << info[6] << "\nSolution: "; 247 for(i=0; i<n; ++i) 248 result_msg << p[i] << " "; 249 result_msg << "\n\nMinimization info:\n"; 250 std::vector<std::string> infonames(LM_INFO_SZ); 251 infonames[0] = std::string("||e||_2 at initial p"); 252 infonames[1] = std::string("||e||_2"); 253 infonames[2] = std::string("||J^T e||_inf"); 254 infonames[3] = std::string("||Dp||_2"); 255 infonames[4] = std::string("mu/max[J^T J]_ii"); 256 infonames[5] = std::string("# iterations"); 257 infonames[6] = std::string("reason for termination"); 258 infonames[7] = std::string(" # function evaluations"); 259 infonames[8] = std::string(" # Jacobian evaluations"); 260 infonames[9] = std::string(" # linear systems solved"); 261 for(i=0; i<LM_INFO_SZ; ++i) 262 result_msg << infonames[i] << ": " << info[i] << " "; 263 result_msg << std::endl; 264 LOG(4, "DEBUG: " << result_msg.str()); 265 } 266 267 std::copy(p, p+n, weights.begin()); 268 LOG(4, "DEBUG: Weights for atom #" << _walker.getId() << ": " << weights); 269 270 delete[] p; 271 delete[] x; 272 delete[] matrix; 273 274 return weights; 275 } 276 113 277 BondVectors::weights_t BondVectors::getWeightsForAtomAtStep( 114 278 const atom &_walker, … … 118 282 getAtomsBondVectorsAtStep(_walker, _step); 119 283 120 weights_t weights; 121 for (std::vector<Vector>::const_iterator iter = BondVectors.begin(); 122 iter != BondVectors.end(); ++iter) { 284 return getWeightsForAtomAtStep(_walker, BondVectors, _step); 285 } 286 287 Vector BondVectors::getRemnantGradientForAtomAtStep( 288 const atom &_walker, 289 const std::vector<Vector> _BondVectors, 290 const BondVectors::weights_t &_weights, 291 const size_t &_step, 292 forcestore_t _forcestore) const 293 { 294 const Vector &walkerGradient = _walker.getAtomicForceAtStep(_step); 295 BondVectors::weights_t::const_iterator weightiter = _weights.begin(); 296 std::vector<Vector>::const_iterator vectoriter = _BondVectors.begin(); 297 const BondList& ListOfBonds = _walker.getListOfBonds(); 298 299 Vector forcesum; 300 for(BondList::const_iterator bonditer = ListOfBonds.begin(); 301 bonditer != ListOfBonds.end(); ++bonditer, ++weightiter, ++vectoriter) { 302 const bond::ptr ¤t_bond = *bonditer; 303 const Vector &BondVector = *vectoriter; 304 305 const double temp = (*weightiter)*walkerGradient.ScalarProduct(BondVector); 306 _forcestore(_walker, current_bond, _step, temp); 307 LOG(4, "DEBUG: BondVector " << BondVector << " receives projected force of " 308 << temp); 309 forcesum += temp * BondVector; 310 } 311 ASSERT( weightiter == _weights.end(), 312 "BondVectors::getRemnantGradientForAtomAtStep() - weightiter is not at end when it should be."); 313 ASSERT( vectoriter == _BondVectors.end(), 314 "BondVectors::getRemnantGradientForAtomAtStep() - vectoriter is not at end when it should be."); 315 316 return walkerGradient-forcesum; 317 } 318 319 bool BondVectors::getCheckWeightSumForAtomAtStep( 320 const atom &_walker, 321 const std::vector<Vector> _BondVectors, 322 const BondVectors::weights_t &_weights, 323 const size_t &_step) const 324 { 325 bool status = true; 326 for (std::vector<Vector>::const_iterator iter = _BondVectors.begin(); 327 iter != _BondVectors.end(); ++iter) { 123 328 std::vector<double> scps; 124 scps.reserve( BondVectors.size());329 scps.reserve(_BondVectors.size()); 125 330 std::transform( 126 BondVectors.begin(), BondVectors.end(), 127 std::back_inserter(scps), 128 boost::bind(static_cast< double (*)(double) >(&fabs), 129 boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1)) 130 ); 131 const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.); 132 ASSERT( (scp_sum-1.) > -MYEPSILON, 133 "ForceAnnealing() - sum of weights must be equal or larger one but is " 134 +toString(scp_sum)); 135 weights.push_back( 1./scp_sum ); 136 } 137 LOG(4, "DEBUG: Weights for atom #" << _walker.getId() << ": " << weights); 138 139 // for testing we check whether all weighted scalar products now come out as 1. 140 #ifndef NDEBUG 141 for (std::vector<Vector>::const_iterator iter = BondVectors.begin(); 142 iter != BondVectors.end(); ++iter) { 143 std::vector<double> scps; 144 scps.reserve(BondVectors.size()); 145 std::transform( 146 BondVectors.begin(), BondVectors.end(), 147 weights.begin(), 331 _BondVectors.begin(), _BondVectors.end(), 332 _weights.begin(), 148 333 std::back_inserter(scps), 149 334 boost::bind(static_cast< double (*)(double) >(&fabs), … … 153 338 ); 154 339 const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.); 155 ASSERT( fabs(scp_sum - 1.) < MYEPSILON, 156 "ForceAnnealing::operator() - for BondVector "+toString(*iter) 157 +" we have weighted scalar product of "+toString(scp_sum)+" != 1."); 158 } 159 #endif 160 return weights; 161 } 340 if (fabs(scp_sum -1.) > MYEPSILON) 341 status = false; 342 } 343 344 return status; 345 } -
src/Dynamics/BondVectors.hpp
r7b4e67 rf433ec 17 17 #include <map> 18 18 #include <vector> 19 20 #include <boost/function.hpp> 19 21 20 22 #include "CodePatterns/Assert.hpp" … … 93 95 * 94 96 * \param _walker atom to get BondVectors for 97 * \param _bondvectors precalculated bond vectors for given \a _walker 98 * \param _step time step for which the bond vector is request 99 */ 100 weights_t getWeightsForAtomAtStep( 101 const atom &_walker, 102 const std::vector<Vector> &_bondvectors, 103 const size_t &_step) const; 104 105 /** Calculates the weights for a frame where each Bondvector of the 106 * given atom is a vector of the frame. 107 * 108 * The idea is that we can represent any vector by appropriate weights such 109 * that is still sums up to one. 110 * 111 * \param _walker atom to get BondVectors for 95 112 * \param _step time step for which the bond vector is request 96 113 */ … … 98 115 const atom &_walker, 99 116 const size_t &_step) const; 117 118 /** Function typedef to store the bond gradient into a specific container 119 * depending on the atom, its current bond and the time step. 120 */ 121 typedef boost::function<void ( 122 const atom &, 123 const bond::ptr &, 124 const size_t &, 125 const double)> forcestore_t; 126 127 /** Function calculates the remaining part of the atomic gradient that is 128 * not captured by the sum of the force along the Bond Vectors. 129 * 130 * \param _walker atom to get BondVectors for 131 * \param _BondVectors precalculated bond vectors for given \a _walker 132 * \param _weights weight per bond vector (as it is a frame, not a basis) 133 * \param _step time step for which the bond vector is request 134 * \param _forcestore additional function which may be used to store each 135 * calculated bond force in a bound container 136 */ 137 Vector getRemnantGradientForAtomAtStep( 138 const atom &_walker, 139 const std::vector<Vector> _BondVectors, 140 const BondVectors::weights_t &_weights, 141 const size_t &_step, 142 forcestore_t _forcestore) const; 100 143 101 144 private: … … 105 148 */ 106 149 void recalculateBondVectorsAtStep(const size_t &_step) const; 150 151 /** Helper function to check whether weights sum up to one for each 152 * Bond Vector. 153 * 154 * \param _walker atom to get BondVectors for 155 * \param _BondVectors precalculated bond vectors for given \a _walker 156 * \param _weights weight per bond vector (as it is a frame, not a basis) 157 * \param _step time step for which the bond vector is request 158 */ 159 bool getCheckWeightSumForAtomAtStep( 160 const atom &_walker, 161 const std::vector<Vector> _BondVectors, 162 const BondVectors::weights_t &_weights, 163 const size_t &_step) const; 107 164 108 165 private: -
src/Dynamics/ForceAnnealing.hpp
r7b4e67 rf433ec 119 119 LOG(2, "DEBUG: current step is #" << currentStep); 120 120 121 // bond graph annealing is always followed by a normal annealing 121 122 if (_UseBondgraph) 122 123 annealWithBondGraph(_CurrentTimeStep, _offset, maxComponents); 123 else 124 anneal(_CurrentTimeStep, _offset, maxComponents); 124 anneal(_CurrentTimeStep, _offset, maxComponents); 125 125 } 126 126 … … 217 217 } 218 218 219 // knowing the number of bonds in total, we can setup the storage for the 220 // projected forces 221 enum whichatom_t { 222 leftside=0, 223 rightside=1, 224 MAX_sides 225 }; 226 227 /** Helper function to put bond force into a container. 228 * 229 * \param _walker atom 230 * \param _current_bond current bond of \a _walker 231 * \param _timestep time step 232 * \param _force calculated bond force 233 * \param _bv bondvectors for obtaining the correct index 234 * \param _projected_forces container 235 */ 236 static void ForceStore( 237 const atom &_walker, 238 const bond::ptr &_current_bond, 239 const size_t &_timestep, 240 const double _force, 241 const BondVectors &_bv, 242 std::vector< // time step 243 std::vector< // which bond side 244 std::vector<double> > // over all bonds 245 > &_projected_forces) 246 { 247 std::vector<double> &forcelist = (&_walker == _current_bond->leftatom) ? 248 _projected_forces[_timestep][leftside] : _projected_forces[_timestep][rightside]; 249 const size_t index = _bv.getIndexForBond(_current_bond); 250 ASSERT( index != (size_t)-1, 251 "ForceAnnealing() - could not find bond "+toString(*_current_bond) 252 +" in bondvectors"); 253 forcelist[index] = _force; 254 } 255 219 256 /** Performs Gradient optimization on the bonds. 220 257 * … … 274 311 const BondVectors::container_t &sorted_bonds = bv.getSorted(); 275 312 276 // knowing the number of bonds in total, we can setup the storage for the277 // projected forces278 enum whichatom_t {279 leftside=0,280 rightside=1,281 MAX_sides282 };283 313 std::vector< // time step 284 314 std::vector< // which bond side … … 294 324 typedef std::map<atomId_t, BondVectors::weights_t > weights_per_atom_t; 295 325 std::vector<weights_per_atom_t> weights_per_atom(2); 326 typedef std::map<atomId_t, Vector> RemnantGradient_per_atom_t; 327 RemnantGradient_per_atom_t RemnantGradient_per_atom; 296 328 for (size_t timestep = 0; timestep <= 1; ++timestep) { 297 329 const size_t CurrentStep = CurrentTimeStep-timestep-1 >= 0 ? CurrentTimeStep-timestep-1 : 0; … … 320 352 weights_per_atom[timestep].insert( 321 353 std::make_pair(walker.getId(), 322 bv.getWeightsForAtomAtStep(walker, CurrentStep)) );354 bv.getWeightsForAtomAtStep(walker, BondVectors, CurrentStep)) ); 323 355 ASSERT( inserter.second, 324 356 "ForceAnnealing::operator() - weight map for atom "+toString(walker) … … 332 364 // projected gradient over all bonds and place in one of projected_forces 333 365 // using the obtained weights 334 { 335 BondVectors::weights_t::const_iterator weightiter = weights.begin(); 336 std::vector<Vector>::const_iterator vectoriter = BondVectors.begin(); 337 Vector forcesum_check; 338 for(BondList::const_iterator bonditer = ListOfBonds.begin(); 339 bonditer != ListOfBonds.end(); ++bonditer, ++weightiter, ++vectoriter) { 340 const bond::ptr ¤t_bond = *bonditer; 341 const Vector &BondVector = *vectoriter; 342 343 std::vector<double> &forcelist = (&walker == current_bond->leftatom) ? 344 projected_forces[timestep][leftside] : projected_forces[timestep][rightside]; 345 const size_t index = bv.getIndexForBond(current_bond); 346 ASSERT( index != (size_t)-1, 347 "ForceAnnealing() - could not find bond "+toString(*current_bond) 348 +" in bondvectors"); 349 forcelist[index] = (*weightiter)*walkerGradient.ScalarProduct(BondVector); 350 LOG(4, "DEBUG: BondVector " << BondVector << " receives projected force of " 351 << forcelist[index]); 352 forcesum_check += forcelist[index] * BondVector; 353 } 354 ASSERT( weightiter == weights.end(), 355 "ForceAnnealing - weightiter is not at end when it should be."); 356 ASSERT( vectoriter == BondVectors.end(), 357 "ForceAnnealing - vectoriter is not at end when it should be."); 358 LOG(3, "DEBUG: sum of projected forces is " << forcesum_check); 359 } 360 366 BondVectors::forcestore_t forcestoring = 367 boost::bind(&ForceAnnealing::ForceStore, _1, _2, _3, _4, 368 boost::cref(bv), boost::ref(projected_forces)); 369 const Vector RemnantGradient = bv.getRemnantGradientForAtomAtStep( 370 walker, BondVectors, weights, timestep, forcestoring 371 ); 372 RemnantGradient_per_atom.insert( std::make_pair(walker.getId(), RemnantGradient) ); 361 373 } else { 362 374 LOG(2, "DEBUG: Gradient is " << walkerGradient << " less than " … … 487 499 } 488 500 489 // apply the gathered updates 501 // apply the gathered updates and set remnant gradients for atomic annealing 490 502 for (std::map<atomId_t, Vector>::const_iterator iter = GatheredUpdates.begin(); 491 503 iter != GatheredUpdates.end(); ++iter) { … … 501 513 + update); 502 514 walker->setAtomicVelocity(update); 503 //walker->setAtomicForce( RemnantGradient_per_atom[walker->getId()] );515 walker->setAtomicForce( RemnantGradient_per_atom[walker->getId()] ); 504 516 } 505 517 } -
src/Dynamics/unittests/BondVectorsUnitTest.cpp
r7b4e67 rf433ec 197 197 CPPUNIT_ASSERT( fabs(weight_sum - 1.) < MYEPSILON ); 198 198 // check weight 199 CPPUNIT_ASSERT _EQUAL( weights[0], 1.);199 CPPUNIT_ASSERT( fabs(weight_sum - 1.) < 1e-10 ); 200 200 } 201 201 … … 289 289 // check number of weights 290 290 CPPUNIT_ASSERT_EQUAL( weights.size(), (size_t)5 ); 291 // check sum of weights: one linear independent, two dependent vectors = 1 + 2*0.5 292 const double weight_sum = std::accumulate(weights.begin(), weights.end(), 0.); 293 CPPUNIT_ASSERT( fabs(weight_sum - 2.) < 1e-10 ); 294 } 291 // check sum of weights 292 const double weight_sum = std::accumulate(weights.begin(), weights.end(), 0.); 293 CPPUNIT_ASSERT( fabs(weights[0] - .372244) < 1e-6 ); 294 CPPUNIT_ASSERT( fabs(weights[1] - .529694) < 1e-6 ); 295 CPPUNIT_ASSERT( fabs(weights[2] - .2) < 1e-6 ); 296 CPPUNIT_ASSERT( fabs(weights[3] - .248464) < 1e-6 ); 297 CPPUNIT_ASSERT( fabs(weights[4] - .248464) < 1e-6 ); 298 } -
src/Dynamics/unittests/Makefile.am
r7b4e67 rf433ec 11 11 BondVectorsUnitTest 12 12 13 XFAIL_TESTS += BondVectorsUnitTest14 15 13 TESTS += $(DYNAMICSTESTS) 16 14 check_PROGRAMS += $(DYNAMICSTESTS)
Note:
See TracChangeset
for help on using the changeset viewer.