source: src/LevMartester.cpp@ 355af8

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 355af8 was 4ec18b, checked in by Frederik Heber <heber@…>, 12 years ago

Added class TrainingData encapsulating the training input and output vectors.

  • Property mode set to 100644
File size: 29.7 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2012 University of Bonn. All rights reserved.
5 * Please see the COPYING file or "Copyright notice" in builder.cpp for details.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * LevMartester.cpp
26 *
27 * Created on: Sep 27, 2012
28 * Author: heber
29 */
30
31
32// include config.h
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include <boost/archive/text_iarchive.hpp>
38
39#include "CodePatterns/MemDebug.hpp"
40
41#include <boost/assign.hpp>
42#include <boost/bind.hpp>
43#include <boost/filesystem.hpp>
44#include <boost/function.hpp>
45#include <boost/program_options.hpp>
46
47#include <cstdlib>
48#include <ctime>
49#include <fstream>
50#include <iostream>
51#include <iterator>
52#include <list>
53#include <vector>
54
55#include <levmar.h>
56
57#include "CodePatterns/Assert.hpp"
58#include "CodePatterns/Log.hpp"
59
60#include "LinearAlgebra/Vector.hpp"
61
62#include "Fragmentation/Homology/HomologyContainer.hpp"
63#include "Fragmentation/SetValues/Fragment.hpp"
64#include "FunctionApproximation/FunctionApproximation.hpp"
65#include "FunctionApproximation/FunctionModel.hpp"
66#include "Helpers/defs.hpp"
67#include "Potentials/Specifics/PairPotential_Morse.hpp"
68#include "Potentials/Specifics/PairPotential_Angle.hpp"
69#include "Potentials/Specifics/SaturationPotential.hpp"
70
71namespace po = boost::program_options;
72
73using namespace boost::assign;
74
75HomologyGraph getFirstGraphWithThreeCarbons(const HomologyContainer &homologies)
76{
77 FragmentNode SaturatedCarbon(6,4); // carbon has atomic number 6 and should have 4 bonds for C3H8
78 FragmentNode DanglingCarbon(6,3); // carbon has atomic number 6 and should have 3 pure bonds for C3H8
79 for (HomologyContainer::container_t::const_iterator iter =
80 homologies.begin(); iter != homologies.end(); ++iter) {
81 if ((iter->first.hasNode(SaturatedCarbon,2)) && (iter->first.hasNode(DanglingCarbon,1)))
82 return iter->first;
83 }
84 return HomologyGraph();
85}
86
87HomologyGraph getFirstGraphWithTwoCarbons(const HomologyContainer &homologies)
88{
89 FragmentNode SaturatedCarbon(6,3); // carbon has atomic number 6 and should have 4 bonds for C2H6
90 for (HomologyContainer::container_t::const_iterator iter =
91 homologies.begin(); iter != homologies.end(); ++iter) {
92 if (iter->first.hasNode(SaturatedCarbon,2))
93 return iter->first;
94 }
95 return HomologyGraph();
96}
97
98HomologyGraph getFirstGraphWithOneCarbon(const HomologyContainer &homologies)
99{
100 FragmentNode SaturatedCarbon(6,2); // carbon has atomic number 6 and has 3 bonds (to other Hs)
101 for (HomologyContainer::container_t::const_iterator iter =
102 homologies.begin(); iter != homologies.end(); ++iter) {
103 if (iter->first.hasNode(SaturatedCarbon,1))
104 return iter->first;
105 }
106 return HomologyGraph();
107}
108
109FunctionModel::arguments_t
110gatherAllDistanceArguments(
111 const Fragment::charges_t &charges,
112 const Fragment::positions_t &positions,
113 const size_t globalid)
114{
115 FunctionModel::arguments_t result;
116
117 // go through current configuration and gather all other distances
118 Fragment::charges_t::const_iterator firstchargeiter = charges.begin();
119 Fragment::positions_t::const_iterator firstpositer = positions.begin();
120 for (;firstchargeiter != charges.end();
121 ++firstchargeiter, ++firstpositer) {
122 Fragment::charges_t::const_iterator secondchargeiter = charges.begin();//firstchargeiter;
123 Fragment::positions_t::const_iterator secondpositer = positions.begin();//firstpositer;
124 for (;
125 secondchargeiter != charges.end();
126 ++secondchargeiter, ++secondpositer) {
127 if (firstchargeiter == secondchargeiter)
128 continue;
129 argument_t arg;
130 const Vector firsttemp((*firstpositer)[0],(*firstpositer)[1],(*firstpositer)[2]);
131 const Vector secondtemp((*secondpositer)[0],(*secondpositer)[1],(*secondpositer)[2]);
132 arg.distance = firsttemp.distance(secondtemp);
133 arg.indices = std::make_pair(
134 std::distance(
135 charges.begin(), firstchargeiter),
136 std::distance(
137 charges.begin(), secondchargeiter)
138 );
139 arg.globalid = globalid;
140 result.push_back(arg);
141 }
142 ASSERT( secondpositer == positions.end(),
143 "gatherAllDistanceArguments() - there are not as many positions as charges.");
144 }
145 ASSERT( firstpositer == positions.end(),
146 "gatherAllDistanceArguments() - there are not as many positions as charges.");
147
148 return result;
149}
150
151/** This function returns the elements of the sum over index "k" for an
152 * argument containing indices "i" and "j"
153 * @param inputs vector of all configuration (containing each a vector of all arguments)
154 * @param arg argument containing indices "i" and "j"
155 * @param cutoff cutoff criterion for sum over k
156 * @return vector of argument pairs (a vector) of ik and jk for at least all k
157 * within distance of \a cutoff to i
158 */
159std::vector<FunctionModel::arguments_t>
160getTripleFromArgument(const FunctionApproximation::inputs_t &inputs, const argument_t &arg, const double cutoff)
161{
162 typedef std::list<argument_t> arg_list_t;
163 typedef std::map<size_t, arg_list_t > k_args_map_t;
164 k_args_map_t tempresult;
165 ASSERT( inputs.size() > arg.globalid,
166 "getTripleFromArgument() - globalid "+toString(arg.globalid)
167 +" is greater than all inputs "+toString(inputs.size())+".");
168 const FunctionModel::arguments_t &listofargs = inputs[arg.globalid];
169 for (FunctionModel::arguments_t::const_iterator argiter = listofargs.begin();
170 argiter != listofargs.end();
171 ++argiter) {
172 // first index must be either i or j but second index not
173 if (((argiter->indices.first == arg.indices.first)
174 || (argiter->indices.first == arg.indices.second))
175 && ((argiter->indices.second != arg.indices.first)
176 && (argiter->indices.second != arg.indices.second))) {
177 // we need arguments ik and jk
178 std::pair< k_args_map_t::iterator, bool> inserter =
179 tempresult.insert( std::make_pair( argiter->indices.second, arg_list_t(1,*argiter)));
180 if (!inserter.second) {
181 // is present one ik or jk, if ik insert jk at back
182 if (inserter.first->second.begin()->indices.first == arg.indices.first)
183 inserter.first->second.push_back(*argiter);
184 else // if jk, insert ik at front
185 inserter.first->second.push_front(*argiter);
186 }
187 }
188// // or second index must be either i or j but first index not
189// else if (((argiter->indices.first != arg.indices.first)
190// && (argiter->indices.first != arg.indices.second))
191// && ((argiter->indices.second == arg.indices.first)
192// || (argiter->indices.second == arg.indices.second))) {
193// // we need arguments ki and kj
194// std::pair< k_args_map_t::iterator, bool> inserter =
195// tempresult.insert( std::make_pair( argiter->indices.first, arg_list_t(1,*argiter)));
196// if (!inserter.second) {
197// // is present one ki or kj, if ki insert kj at back
198// if (inserter.first->second.begin()->indices.second == arg.indices.first)
199// inserter.first->second.push_back(*argiter);
200// else // if kj, insert ki at front
201// inserter.first->second.push_front(*argiter);
202// }
203// }
204 }
205 // check that i,j are NOT contained
206 ASSERT( tempresult.count(arg.indices.first) == 0,
207 "getTripleFromArgument() - first index of argument present in k_args_map?");
208 ASSERT( tempresult.count(arg.indices.second) == 0,
209 "getTripleFromArgument() - first index of argument present in k_args_map?");
210
211 // convert
212 std::vector<FunctionModel::arguments_t> result;
213 for (k_args_map_t::const_iterator iter = tempresult.begin();
214 iter != tempresult.end();
215 ++iter) {
216 ASSERT( iter->second.size() == 2,
217 "getTripleFromArgument() - for index "+toString(iter->first)+" we did not find both ik and jk.");
218 result.push_back( FunctionModel::arguments_t(iter->second.begin(), iter->second.end()) );
219 }
220 return result;
221}
222
223double
224function_angle(
225 const double &r_ij,
226 const double &r_ik,
227 const double &r_jk
228 )
229{
230// Info info(__func__);
231 const double angle = pow(r_ij,2.) + pow(r_ik,2.) - pow(r_jk,2.);
232 const double divisor = 2.* r_ij * r_ik;
233
234// LOG(2, "DEBUG: cos(theta)= " << angle/divisor);
235 if (divisor == 0.)
236 return 0.;
237 else
238 return angle/divisor;
239}
240
241/** Namespace containing all simple extractor functions.
242 *
243 */
244namespace Extractors {
245 /** Simple extractor of all unique pair distances of a given \a fragment.
246 *
247 * \param fragment fragment with all nuclei positions
248 * \param index index refers to the index within the global set of configurations
249 * \return vector of of argument_t containing all found distances
250 */
251 FunctionModel::arguments_t gatherAllDistances(
252 const Fragment& fragment,
253 const size_t index
254 ) {
255 // get distance out of Fragment
256 const Fragment::charges_t charges = fragment.getCharges();
257 const Fragment::positions_t positions = fragment.getPositions();
258 return gatherAllDistanceArguments(charges, positions, index);
259 }
260
261 /** Gather first distance for the two matching charges.
262 *
263 * \param fragment fragment with all nuclei positions
264 * \param index index refers to the index within the global set of configurations
265 * \param firstelement first element of pair
266 * \param secondelement second element of pair, order is reflected in indices of return argument_t
267 * \return vector of of argument_t containing all found distances
268 */
269 FunctionModel::arguments_t gatherFirstDistance(
270 const Fragment& fragment,
271 const size_t index,
272 const size_t firstelement,
273 const size_t secondelement
274 ) {
275 const Fragment::charges_t charges = fragment.getCharges();
276 const Fragment::positions_t positions = fragment.getPositions();
277 typedef Fragment::charges_t::const_iterator chargeiter_t;
278 std::vector< chargeiter_t > firstpair;
279 firstpair.reserve(2);
280 firstpair +=
281 std::find(charges.begin(), charges.end(), firstelement),
282 std::find(charges.begin(), charges.end(), secondelement);
283 if ((firstpair[0] == charges.end()) || (firstpair[1] == charges.end())) {
284 // complain if tuple not found
285 ELOG(1, "Could not find pair " << firstelement << "," << secondelement
286 << " in fragment " << fragment);
287 return FunctionModel::arguments_t();
288 }
289 // convert position_t to Vector
290 std::vector< std::pair<Vector, size_t> > DistancePair;
291 for (std::vector<chargeiter_t>::const_iterator firstpairiter = firstpair.begin();
292 firstpairiter != firstpair.end(); ++firstpairiter) {
293 Fragment::positions_t::const_iterator positer = positions.begin();
294 const size_t steps = std::distance(charges.begin(), *firstpairiter);
295 std::advance(positer, steps);
296 DistancePair.push_back(
297 std::make_pair(Vector((*positer)[0], (*positer)[1], (*positer)[2]),
298 steps));
299 }
300 // finally convert Vector pair to distance-like argument
301 argument_t arg;
302 arg.indices.first = DistancePair[0].second;
303 arg.indices.second = DistancePair[1].second;
304 arg.distance = DistancePair[0].first.distance(DistancePair[1].first);
305 arg.globalid = index;
306
307 return FunctionModel::arguments_t(1, arg);
308 }
309
310}; /* namespace Extractors */
311
312/** This class encapsulates the training data for a given potential function
313 * to learn.
314 *
315 * The data is added piece-wise by calling the operator() with a specific
316 * Fragment.
317 */
318class TrainingData
319{
320public:
321 //!> typedef for a range within the HomologyContainer at which fragments to look at
322 typedef std::pair<
323 HomologyContainer::const_iterator,
324 HomologyContainer::const_iterator> range_t;
325 //!> Training tuple input vector pair
326 typedef FunctionApproximation::inputs_t InputVector_t;
327 //!> Training tuple output vector pair
328 typedef FunctionApproximation::outputs_t OutputVector_t;
329 //!> Typedef for a function containing how to extract required information from a Fragment.
330 typedef boost::function< FunctionModel::arguments_t (const Fragment &, const size_t)> extractor_t;
331
332public:
333 /** Constructor for class TrainingData.
334 *
335 */
336 explicit TrainingData(const extractor_t &_extractor) :
337 extractor(extractor)
338 {}
339 /** Destructor for class TrainingData.
340 *
341 */
342 ~TrainingData()
343 {}
344
345 /** We go through the given \a range of homologous fragments and call
346 * TrainingData::extractor on them in order to gather the distance and
347 * the energy value, stored internally.
348 *
349 * \param range given range within a HomologyContainer of homologous fragments
350 */
351 void operator()(const range_t &range) {
352 for (HomologyContainer::const_iterator iter = range.first; iter != range.second; ++iter) {
353 // get distance out of Fragment
354 const Fragment &fragment = iter->second.first;
355 FunctionModel::arguments_t args = extractor(
356 fragment,
357 DistanceVector.size()
358 );
359 DistanceVector.push_back( args );
360 const double &energy = iter->second.second;
361 EnergyVector.push_back( FunctionModel::results_t(1, energy) );
362 }
363 }
364
365 /** Getter for const access to internal training data inputs.
366 *
367 * \return const ref to training tuple of input vector
368 */
369 const InputVector_t& getTrainingInputs() const {
370 return DistanceVector;
371 }
372
373 /** Getter for const access to internal training data outputs.
374 *
375 * \return const ref to training tuple of output vector
376 */
377 const OutputVector_t& getTrainingOutputs() const {
378 return EnergyVector;
379 }
380
381private:
382 // prohibit use of default constructor, as we always require extraction functor.
383 TrainingData();
384
385private:
386 //!> private training data vector
387 InputVector_t DistanceVector;
388 OutputVector_t EnergyVector;
389 //!> function to be used for training input data extraction from a fragment
390 const extractor_t extractor;
391};
392
393// print training data for debugging
394std::ostream &operator<<(std::ostream &out, const TrainingData &data)
395{
396 const TrainingData::InputVector_t &DistanceVector = data.getTrainingInputs();
397 const TrainingData::OutputVector_t &EnergyVector = data.getTrainingOutputs();
398 out << "(" << DistanceVector.size()
399 << "," << EnergyVector.size() << ") data pairs: ";
400 FunctionApproximation::inputs_t::const_iterator initer = DistanceVector.begin();
401 FunctionApproximation::outputs_t::const_iterator outiter = EnergyVector.begin();
402 for (; initer != DistanceVector.end(); ++initer, ++outiter) {
403 for (size_t index = 0; index < (*initer).size(); ++index)
404 out << "(" << (*initer)[index].indices.first << "," << (*initer)[index].indices.second
405 << ") " << (*initer)[index].distance;
406 out << " with energy " << *outiter;
407 }
408 return out;
409}
410
411int main(int argc, char **argv)
412{
413 std::cout << "Hello to the World from LevMar!" << std::endl;
414
415 // load homology file
416 po::options_description desc("Allowed options");
417 desc.add_options()
418 ("help", "produce help message")
419 ("homology-file", po::value< boost::filesystem::path >(), "homology file to parse")
420 ;
421
422 po::variables_map vm;
423 po::store(po::parse_command_line(argc, argv, desc), vm);
424 po::notify(vm);
425
426 if (vm.count("help")) {
427 std::cout << desc << "\n";
428 return 1;
429 }
430
431 boost::filesystem::path homology_file;
432 if (vm.count("homology-file")) {
433 homology_file = vm["homology-file"].as<boost::filesystem::path>();
434 LOG(1, "INFO: Parsing " << homology_file.string() << ".");
435 } else {
436 LOG(0, "homology-file level was not set.");
437 }
438 HomologyContainer homologies;
439 if (boost::filesystem::exists(homology_file)) {
440 std::ifstream returnstream(homology_file.string().c_str());
441 if (returnstream.good()) {
442 boost::archive::text_iarchive ia(returnstream);
443 ia >> homologies;
444 } else {
445 ELOG(2, "Failed to parse from " << homology_file.string() << ".");
446 }
447 returnstream.close();
448 } else {
449 ELOG(0, homology_file << " does not exist.");
450 }
451
452 // first we try to look into the HomologyContainer
453 LOG(1, "INFO: Listing all present homologies ...");
454 for (HomologyContainer::container_t::const_iterator iter =
455 homologies.begin(); iter != homologies.end(); ++iter) {
456 LOG(1, "INFO: graph " << iter->first << " has Fragment "
457 << iter->second.first << " and associated energy " << iter->second.second << ".");
458 }
459
460 /******************** Angle TRAINING ********************/
461 {
462 // then we ought to pick the right HomologyGraph ...
463 const HomologyGraph graph = getFirstGraphWithThreeCarbons(homologies);
464 LOG(1, "First representative graph containing three saturated carbons is " << graph << ".");
465
466 // Afterwards we go through all of this type and gather the distance and the energy value
467 typedef std::pair<
468 FunctionApproximation::inputs_t,
469 FunctionApproximation::outputs_t> InputOutputVector_t;
470 InputOutputVector_t DistanceEnergyVector;
471 std::pair<HomologyContainer::const_iterator, HomologyContainer::const_iterator> range =
472 homologies.getHomologousGraphs(graph);
473 for (HomologyContainer::const_iterator fragiter = range.first; fragiter != range.second; ++fragiter) {
474 // get distance out of Fragment
475 const double &energy = fragiter->second.second;
476 const Fragment &fragment = fragiter->second.first;
477 const Fragment::charges_t charges = fragment.getCharges();
478 const Fragment::positions_t positions = fragment.getPositions();
479 std::vector< std::pair<Vector, size_t> > DistanceVectors;
480 for (Fragment::charges_t::const_iterator chargeiter = charges.begin();
481 chargeiter != charges.end(); ++chargeiter) {
482 if (*chargeiter == 6) {
483 Fragment::positions_t::const_iterator positer = positions.begin();
484 const size_t steps = std::distance(charges.begin(), chargeiter);
485 std::advance(positer, steps);
486 DistanceVectors.push_back(
487 std::make_pair(Vector((*positer)[0], (*positer)[1], (*positer)[2]),
488 steps));
489 }
490 }
491 if (DistanceVectors.size() == (size_t)3) {
492 FunctionModel::arguments_t args(3);
493 // we require specific ordering of the carbons: ij, ik, jk
494 typedef std::vector< std::pair<size_t, size_t> > indices_t;
495 indices_t indices;
496 indices += std::make_pair(0,1), std::make_pair(0,2), std::make_pair(1,2);
497 // create the three arguments
498 for (indices_t::const_iterator iter = indices.begin(); iter != indices.end(); ++iter) {
499 const size_t &firstindex = iter->first;
500 const size_t &secondindex = iter->second;
501 argument_t &arg = args[(size_t)std::distance(const_cast<const indices_t&>(indices).begin(), iter)];
502 arg.indices.first = DistanceVectors[firstindex].second;
503 arg.indices.second = DistanceVectors[secondindex].second;
504 arg.distance = DistanceVectors[firstindex].first.distance(DistanceVectors[secondindex].first);
505 arg.globalid = DistanceEnergyVector.first.size();
506 }
507 // make largest distance last to create correct angle
508 // (this would normally depend on the order of the nodes in the subgraph)
509 std::list<argument_t> sorted_args;
510 double greatestdistance = 0.;
511 for(FunctionModel::arguments_t::const_iterator iter = args.begin(); iter != args.end(); ++iter)
512 greatestdistance = std::max(greatestdistance, iter->distance);
513 for(FunctionModel::arguments_t::const_iterator iter = args.begin(); iter != args.end(); ++iter)
514 if (iter->distance == greatestdistance)
515 sorted_args.push_back(*iter);
516 else
517 sorted_args.push_front(*iter);
518 // and add the training pair
519 DistanceEnergyVector.first.push_back( FunctionModel::arguments_t(sorted_args.begin(), sorted_args.end()) );
520 DistanceEnergyVector.second.push_back( FunctionModel::results_t(1,energy) );
521 } else {
522 ELOG(2, "main() - found not exactly three carbon atoms in fragment "
523 << fragment << ".");
524 }
525 }
526 // print training data for debugging
527 {
528 LOG(1, "INFO: I gathered the following (" << DistanceEnergyVector.first.size()
529 << "," << DistanceEnergyVector.second.size() << ") data pairs: ");
530 FunctionApproximation::inputs_t::const_iterator initer = DistanceEnergyVector.first.begin();
531 FunctionApproximation::outputs_t::const_iterator outiter = DistanceEnergyVector.second.begin();
532 for (; initer != DistanceEnergyVector.first.end(); ++initer, ++outiter) {
533 std::stringstream stream;
534 const double cos_angle = function_angle((*initer)[0].distance,(*initer)[1].distance,(*initer)[2].distance);
535 for (size_t index = 0; index < (*initer).size(); ++index)
536 stream << " (" << (*initer)[index].indices.first << "," << (*initer)[index].indices.second
537 << ") " << (*initer)[index].distance;
538 stream << " with energy " << *outiter << " and cos(angle) " << cos_angle;
539 LOG(1, "INFO:" << stream.str());
540 }
541 }
542 // NOTICE that distance are in bohrradi as they come from MPQC!
543
544 // now perform the function approximation by optimizing the model function
545 FunctionModel::parameters_t params(PairPotential_Angle::MAXPARAMS, 0.);
546 params[PairPotential_Angle::energy_offset] = -1.;
547 params[PairPotential_Angle::spring_constant] = 1.;
548 params[PairPotential_Angle::equilibrium_distance] = 0.2;
549 PairPotential_Angle angle;
550 LOG(0, "INFO: Initial parameters are " << params << ".");
551 angle.setParameters(params);
552 FunctionModel &model = angle;
553 FunctionApproximation approximator(
554 DistanceEnergyVector.first.begin()->size(),
555 DistanceEnergyVector.second.begin()->size(),
556 model);
557 approximator.setTrainingData(DistanceEnergyVector.first,DistanceEnergyVector.second);
558 if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
559 approximator(FunctionApproximation::ParameterDerivative);
560 else
561 ELOG(0, "We require parameter derivatives for a box constraint minimization.");
562 params = model.getParameters();
563
564 LOG(0, "RESULT: Best parameters are " << params << ".");
565 }
566
567 /******************** MORSE TRAINING ********************/
568 {
569 // then we ought to pick the right HomologyGraph ...
570 const HomologyGraph graph = getFirstGraphWithTwoCarbons(homologies);
571 LOG(1, "First representative graph containing two saturated carbons is " << graph << ".");
572
573 // Afterwards we go through all of this type and gather the distance and the energy value
574 TrainingData MorseData(
575 boost::bind(&Extractors::gatherFirstDistance, _1, _2, 6, 6) // gather first carbon pair
576 );
577 MorseData(homologies.getHomologousGraphs(graph));
578 LOG(1, "INFO: I gathered the following training data: " << MorseData);
579 // NOTICE that distance are in bohrradi as they come from MPQC!
580
581 // now perform the function approximation by optimizing the model function
582 FunctionModel::parameters_t params(PairPotential_Morse::MAXPARAMS, 0.);
583 params[PairPotential_Morse::dissociation_energy] = 0.5;
584 params[PairPotential_Morse::energy_offset] = -1.;
585 params[PairPotential_Morse::spring_constant] = 1.;
586 params[PairPotential_Morse::equilibrium_distance] = 2.9;
587 PairPotential_Morse morse;
588 morse.setParameters(params);
589 FunctionModel &model = morse;
590 FunctionApproximation approximator(
591 MorseData.getTrainingInputs().begin()->size(),
592 MorseData.getTrainingOutputs().begin()->size(),
593 model);
594 approximator.setTrainingData(MorseData.getTrainingInputs(),MorseData.getTrainingOutputs());
595 if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
596 approximator(FunctionApproximation::ParameterDerivative);
597 else
598 ELOG(0, "We require parameter derivatives for a box constraint minimization.");
599 params = model.getParameters();
600
601 LOG(0, "RESULT: Best parameters are " << params << ".");
602 }
603
604 /******************* SATURATION TRAINING *******************/
605 FunctionModel::parameters_t params(SaturationPotential::MAXPARAMS, 0.);
606 {
607 // then we ought to pick the right HomologyGraph ...
608 const HomologyGraph graph = getFirstGraphWithOneCarbon(homologies);
609 LOG(1, "First representative graph containing one saturated carbon is " << graph << ".");
610
611 // Afterwards we go through all of this type and gather the distance and the energy value
612 typedef std::pair<
613 FunctionApproximation::inputs_t,
614 FunctionApproximation::outputs_t> InputOutputVector_t;
615 InputOutputVector_t DistanceEnergyVector;
616 std::pair<HomologyContainer::const_iterator, HomologyContainer::const_iterator> range =
617 homologies.getHomologousGraphs(graph);
618 double EnergySum = 0.; //std::numeric_limits<double>::max();
619 size_t counter = 0.;
620 for (HomologyContainer::const_iterator iter = range.first; iter != range.second; ++iter) {
621 const double &energy = iter->second.second;
622// if (energy <= EnergySum)
623// EnergySum = energy;
624 EnergySum += energy;
625 ++counter;
626 }
627 EnergySum *= 1./(double)counter;
628 for (HomologyContainer::const_iterator iter = range.first; iter != range.second; ++iter) {
629 // get distance out of Fragment
630 const double &energy = iter->second.second;
631 const Fragment &fragment = iter->second.first;
632 const Fragment::charges_t charges = fragment.getCharges();
633 const Fragment::positions_t positions = fragment.getPositions();
634 FunctionModel::arguments_t args =
635 gatherAllDistanceArguments(charges, positions, DistanceEnergyVector.first.size());
636 DistanceEnergyVector.first.push_back( args );
637 DistanceEnergyVector.second.push_back( FunctionModel::results_t(1,energy-EnergySum) );
638 }
639 // print training data for debugging
640 {
641 LOG(1, "INFO: I gathered the following (" << DistanceEnergyVector.first.size()
642 << "," << DistanceEnergyVector.second.size() << ") data pairs: ");
643 FunctionApproximation::inputs_t::const_iterator initer = DistanceEnergyVector.first.begin();
644 FunctionApproximation::outputs_t::const_iterator outiter = DistanceEnergyVector.second.begin();
645 for (; initer != DistanceEnergyVector.first.end(); ++initer, ++outiter) {
646 std::stringstream stream;
647 for (size_t index = 0; index < (*initer).size(); ++index)
648 stream << "(" << (*initer)[index].indices.first << "," << (*initer)[index].indices.second
649 << ") " << (*initer)[index].distance;
650 stream << " with energy " << *outiter;
651 LOG(1, "INFO: " << stream.str());
652 }
653 }
654 // NOTICE that distance are in bohrradi as they come from MPQC!
655
656 // now perform the function approximation by optimizing the model function
657 boost::function< std::vector<FunctionModel::arguments_t>(const argument_t &, const double)> triplefunction =
658 boost::bind(&getTripleFromArgument, DistanceEnergyVector.first, _1, _2);
659 srand((unsigned)time(0)); // seed with current time
660 LOG(0, "INFO: Initial parameters are " << params << ".");
661
662 SaturationPotential saturation(triplefunction);
663 saturation.setParameters(params);
664 FunctionModel &model = saturation;
665 FunctionApproximation approximator(
666 DistanceEnergyVector.first.begin()->size(),
667 DistanceEnergyVector.second.begin()->size(),
668 model);
669 approximator.setTrainingData(DistanceEnergyVector.first,DistanceEnergyVector.second);
670 if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
671 approximator(FunctionApproximation::ParameterDerivative);
672 else
673 ELOG(0, "We require parameter derivatives for a box constraint minimization.");
674
675 params = model.getParameters();
676
677 LOG(0, "RESULT: Best parameters are " << params << ".");
678
679// std::cout << "\tsaturationparticle:";
680// std::cout << "\tparticle_type=C,";
681// std::cout << "\tA=" << params[SaturationPotential::A] << ",";
682// std::cout << "\tB=" << params[SaturationPotential::B] << ",";
683// std::cout << "\tlambda=" << params[SaturationPotential::lambda] << ",";
684// std::cout << "\tmu=" << params[SaturationPotential::mu] << ",";
685// std::cout << "\tbeta=" << params[SaturationPotential::beta] << ",";
686// std::cout << "\tn=" << params[SaturationPotential::n] << ",";
687// std::cout << "\tc=" << params[SaturationPotential::c] << ",";
688// std::cout << "\td=" << params[SaturationPotential::d] << ",";
689// std::cout << "\th=" << params[SaturationPotential::h] << ",";
690//// std::cout << "\toffset=" << params[SaturationPotential::offset] << ",";
691// std::cout << "\tR=" << saturation.R << ",";
692// std::cout << "\tS=" << saturation.S << ";";
693// std::cout << std::endl;
694
695 // check L2 and Lmax error against training set
696 double L2sum = 0.;
697 double Lmax = 0.;
698 size_t maxindex = -1;
699 FunctionApproximation::inputs_t::const_iterator initer = DistanceEnergyVector.first.begin();
700 FunctionApproximation::outputs_t::const_iterator outiter = DistanceEnergyVector.second.begin();
701 for (; initer != DistanceEnergyVector.first.end(); ++initer, ++outiter) {
702 const FunctionModel::results_t result = model((*initer));
703 const double temp = fabs((*outiter)[0] - result[0]);
704 LOG(2, "DEBUG: L2 contribution = " << (*outiter)[0] << "-" << result[0] << "=" << temp);
705 if (temp > Lmax) {
706 Lmax = temp;
707 maxindex = std::distance(const_cast<const FunctionApproximation::inputs_t &>(DistanceEnergyVector.first).begin(), initer);
708 }
709 L2sum += temp*temp;
710 }
711 LOG(1, "INFO: L2sum = " << L2sum << ", LMax = " << Lmax << " from " << maxindex);
712 }
713
714 return 0;
715}
Note: See TracBrowser for help on using the repository browser.