source: src/LevMartester.cpp@ 8aa597

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 8aa597 was 8aa597, checked in by Frederik Heber <heber@…>, 12 years ago

Extracted namespace Extractors into own module.

  • placed gatherAllDistanceArguments() into subspace _detail inside this namespace.
  • Property mode set to 100644
File size: 25.2 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/Extractors.hpp"
65#include "FunctionApproximation/FunctionApproximation.hpp"
66#include "FunctionApproximation/FunctionModel.hpp"
67#include "Helpers/defs.hpp"
68#include "Potentials/Specifics/PairPotential_Morse.hpp"
69#include "Potentials/Specifics/PairPotential_Angle.hpp"
70#include "Potentials/Specifics/SaturationPotential.hpp"
71
72namespace po = boost::program_options;
73
74using namespace boost::assign;
75
76HomologyGraph getFirstGraphWithThreeCarbons(const HomologyContainer &homologies)
77{
78 FragmentNode SaturatedCarbon(6,4); // carbon has atomic number 6 and should have 4 bonds for C3H8
79 FragmentNode DanglingCarbon(6,3); // carbon has atomic number 6 and should have 3 pure bonds for C3H8
80 for (HomologyContainer::container_t::const_iterator iter =
81 homologies.begin(); iter != homologies.end(); ++iter) {
82 if ((iter->first.hasNode(SaturatedCarbon,2)) && (iter->first.hasNode(DanglingCarbon,1)))
83 return iter->first;
84 }
85 return HomologyGraph();
86}
87
88HomologyGraph getFirstGraphWithTwoCarbons(const HomologyContainer &homologies)
89{
90 FragmentNode SaturatedCarbon(6,3); // carbon has atomic number 6 and should have 4 bonds for C2H6
91 for (HomologyContainer::container_t::const_iterator iter =
92 homologies.begin(); iter != homologies.end(); ++iter) {
93 if (iter->first.hasNode(SaturatedCarbon,2))
94 return iter->first;
95 }
96 return HomologyGraph();
97}
98
99HomologyGraph getFirstGraphWithOneCarbon(const HomologyContainer &homologies)
100{
101 FragmentNode SaturatedCarbon(6,2); // carbon has atomic number 6 and has 3 bonds (to other Hs)
102 for (HomologyContainer::container_t::const_iterator iter =
103 homologies.begin(); iter != homologies.end(); ++iter) {
104 if (iter->first.hasNode(SaturatedCarbon,1))
105 return iter->first;
106 }
107 return HomologyGraph();
108}
109
110
111/** This function returns the elements of the sum over index "k" for an
112 * argument containing indices "i" and "j"
113 * @param inputs vector of all configuration (containing each a vector of all arguments)
114 * @param arg argument containing indices "i" and "j"
115 * @param cutoff cutoff criterion for sum over k
116 * @return vector of argument pairs (a vector) of ik and jk for at least all k
117 * within distance of \a cutoff to i
118 */
119std::vector<FunctionModel::arguments_t>
120getTripleFromArgument(const FunctionApproximation::inputs_t &inputs, const argument_t &arg, const double cutoff)
121{
122 typedef std::list<argument_t> arg_list_t;
123 typedef std::map<size_t, arg_list_t > k_args_map_t;
124 k_args_map_t tempresult;
125 ASSERT( inputs.size() > arg.globalid,
126 "getTripleFromArgument() - globalid "+toString(arg.globalid)
127 +" is greater than all inputs "+toString(inputs.size())+".");
128 const FunctionModel::arguments_t &listofargs = inputs[arg.globalid];
129 for (FunctionModel::arguments_t::const_iterator argiter = listofargs.begin();
130 argiter != listofargs.end();
131 ++argiter) {
132 // first index must be either i or j but second index not
133 if (((argiter->indices.first == arg.indices.first)
134 || (argiter->indices.first == arg.indices.second))
135 && ((argiter->indices.second != arg.indices.first)
136 && (argiter->indices.second != arg.indices.second))) {
137 // we need arguments ik and jk
138 std::pair< k_args_map_t::iterator, bool> inserter =
139 tempresult.insert( std::make_pair( argiter->indices.second, arg_list_t(1,*argiter)));
140 if (!inserter.second) {
141 // is present one ik or jk, if ik insert jk at back
142 if (inserter.first->second.begin()->indices.first == arg.indices.first)
143 inserter.first->second.push_back(*argiter);
144 else // if jk, insert ik at front
145 inserter.first->second.push_front(*argiter);
146 }
147 }
148// // or second index must be either i or j but first index not
149// else if (((argiter->indices.first != arg.indices.first)
150// && (argiter->indices.first != arg.indices.second))
151// && ((argiter->indices.second == arg.indices.first)
152// || (argiter->indices.second == arg.indices.second))) {
153// // we need arguments ki and kj
154// std::pair< k_args_map_t::iterator, bool> inserter =
155// tempresult.insert( std::make_pair( argiter->indices.first, arg_list_t(1,*argiter)));
156// if (!inserter.second) {
157// // is present one ki or kj, if ki insert kj at back
158// if (inserter.first->second.begin()->indices.second == arg.indices.first)
159// inserter.first->second.push_back(*argiter);
160// else // if kj, insert ki at front
161// inserter.first->second.push_front(*argiter);
162// }
163// }
164 }
165 // check that i,j are NOT contained
166 ASSERT( tempresult.count(arg.indices.first) == 0,
167 "getTripleFromArgument() - first index of argument present in k_args_map?");
168 ASSERT( tempresult.count(arg.indices.second) == 0,
169 "getTripleFromArgument() - first index of argument present in k_args_map?");
170
171 // convert
172 std::vector<FunctionModel::arguments_t> result;
173 for (k_args_map_t::const_iterator iter = tempresult.begin();
174 iter != tempresult.end();
175 ++iter) {
176 ASSERT( iter->second.size() == 2,
177 "getTripleFromArgument() - for index "+toString(iter->first)+" we did not find both ik and jk.");
178 result.push_back( FunctionModel::arguments_t(iter->second.begin(), iter->second.end()) );
179 }
180 return result;
181}
182
183double
184function_angle(
185 const double &r_ij,
186 const double &r_ik,
187 const double &r_jk
188 )
189{
190// Info info(__func__);
191 const double angle = pow(r_ij,2.) + pow(r_ik,2.) - pow(r_jk,2.);
192 const double divisor = 2.* r_ij * r_ik;
193
194// LOG(2, "DEBUG: cos(theta)= " << angle/divisor);
195 if (divisor == 0.)
196 return 0.;
197 else
198 return angle/divisor;
199}
200
201/** This class encapsulates the training data for a given potential function
202 * to learn.
203 *
204 * The data is added piece-wise by calling the operator() with a specific
205 * Fragment.
206 */
207class TrainingData
208{
209public:
210 //!> typedef for a range within the HomologyContainer at which fragments to look at
211 typedef std::pair<
212 HomologyContainer::const_iterator,
213 HomologyContainer::const_iterator> range_t;
214 //!> Training tuple input vector pair
215 typedef FunctionApproximation::inputs_t InputVector_t;
216 //!> Training tuple output vector pair
217 typedef FunctionApproximation::outputs_t OutputVector_t;
218 //!> Typedef for a function containing how to extract required information from a Fragment.
219 typedef boost::function< FunctionModel::arguments_t (const Fragment &, const size_t)> extractor_t;
220
221public:
222 /** Constructor for class TrainingData.
223 *
224 */
225 explicit TrainingData(const extractor_t &_extractor) :
226 extractor(extractor)
227 {}
228 /** Destructor for class TrainingData.
229 *
230 */
231 ~TrainingData()
232 {}
233
234 /** We go through the given \a range of homologous fragments and call
235 * TrainingData::extractor on them in order to gather the distance and
236 * the energy value, stored internally.
237 *
238 * \param range given range within a HomologyContainer of homologous fragments
239 */
240 void operator()(const range_t &range) {
241 for (HomologyContainer::const_iterator iter = range.first; iter != range.second; ++iter) {
242 // get distance out of Fragment
243 const Fragment &fragment = iter->second.first;
244 FunctionModel::arguments_t args = extractor(
245 fragment,
246 DistanceVector.size()
247 );
248 DistanceVector.push_back( args );
249 const double &energy = iter->second.second;
250 EnergyVector.push_back( FunctionModel::results_t(1, energy) );
251 }
252 }
253
254 /** Getter for const access to internal training data inputs.
255 *
256 * \return const ref to training tuple of input vector
257 */
258 const InputVector_t& getTrainingInputs() const {
259 return DistanceVector;
260 }
261
262 /** Getter for const access to internal training data outputs.
263 *
264 * \return const ref to training tuple of output vector
265 */
266 const OutputVector_t& getTrainingOutputs() const {
267 return EnergyVector;
268 }
269
270private:
271 // prohibit use of default constructor, as we always require extraction functor.
272 TrainingData();
273
274private:
275 //!> private training data vector
276 InputVector_t DistanceVector;
277 OutputVector_t EnergyVector;
278 //!> function to be used for training input data extraction from a fragment
279 const extractor_t extractor;
280};
281
282// print training data for debugging
283std::ostream &operator<<(std::ostream &out, const TrainingData &data)
284{
285 const TrainingData::InputVector_t &DistanceVector = data.getTrainingInputs();
286 const TrainingData::OutputVector_t &EnergyVector = data.getTrainingOutputs();
287 out << "(" << DistanceVector.size()
288 << "," << EnergyVector.size() << ") data pairs: ";
289 FunctionApproximation::inputs_t::const_iterator initer = DistanceVector.begin();
290 FunctionApproximation::outputs_t::const_iterator outiter = EnergyVector.begin();
291 for (; initer != DistanceVector.end(); ++initer, ++outiter) {
292 for (size_t index = 0; index < (*initer).size(); ++index)
293 out << "(" << (*initer)[index].indices.first << "," << (*initer)[index].indices.second
294 << ") " << (*initer)[index].distance;
295 out << " with energy " << *outiter;
296 }
297 return out;
298}
299
300int main(int argc, char **argv)
301{
302 std::cout << "Hello to the World from LevMar!" << std::endl;
303
304 // load homology file
305 po::options_description desc("Allowed options");
306 desc.add_options()
307 ("help", "produce help message")
308 ("homology-file", po::value< boost::filesystem::path >(), "homology file to parse")
309 ;
310
311 po::variables_map vm;
312 po::store(po::parse_command_line(argc, argv, desc), vm);
313 po::notify(vm);
314
315 if (vm.count("help")) {
316 std::cout << desc << "\n";
317 return 1;
318 }
319
320 boost::filesystem::path homology_file;
321 if (vm.count("homology-file")) {
322 homology_file = vm["homology-file"].as<boost::filesystem::path>();
323 LOG(1, "INFO: Parsing " << homology_file.string() << ".");
324 } else {
325 LOG(0, "homology-file level was not set.");
326 }
327 HomologyContainer homologies;
328 if (boost::filesystem::exists(homology_file)) {
329 std::ifstream returnstream(homology_file.string().c_str());
330 if (returnstream.good()) {
331 boost::archive::text_iarchive ia(returnstream);
332 ia >> homologies;
333 } else {
334 ELOG(2, "Failed to parse from " << homology_file.string() << ".");
335 }
336 returnstream.close();
337 } else {
338 ELOG(0, homology_file << " does not exist.");
339 }
340
341 // first we try to look into the HomologyContainer
342 LOG(1, "INFO: Listing all present homologies ...");
343 for (HomologyContainer::container_t::const_iterator iter =
344 homologies.begin(); iter != homologies.end(); ++iter) {
345 LOG(1, "INFO: graph " << iter->first << " has Fragment "
346 << iter->second.first << " and associated energy " << iter->second.second << ".");
347 }
348
349 /******************** Angle TRAINING ********************/
350 {
351 // then we ought to pick the right HomologyGraph ...
352 const HomologyGraph graph = getFirstGraphWithThreeCarbons(homologies);
353 LOG(1, "First representative graph containing three saturated carbons is " << graph << ".");
354
355 // Afterwards we go through all of this type and gather the distance and the energy value
356 typedef std::pair<
357 FunctionApproximation::inputs_t,
358 FunctionApproximation::outputs_t> InputOutputVector_t;
359 InputOutputVector_t DistanceEnergyVector;
360 std::pair<HomologyContainer::const_iterator, HomologyContainer::const_iterator> range =
361 homologies.getHomologousGraphs(graph);
362 for (HomologyContainer::const_iterator fragiter = range.first; fragiter != range.second; ++fragiter) {
363 // get distance out of Fragment
364 const double &energy = fragiter->second.second;
365 const Fragment &fragment = fragiter->second.first;
366 const Fragment::charges_t charges = fragment.getCharges();
367 const Fragment::positions_t positions = fragment.getPositions();
368 std::vector< std::pair<Vector, size_t> > DistanceVectors;
369 for (Fragment::charges_t::const_iterator chargeiter = charges.begin();
370 chargeiter != charges.end(); ++chargeiter) {
371 if (*chargeiter == 6) {
372 Fragment::positions_t::const_iterator positer = positions.begin();
373 const size_t steps = std::distance(charges.begin(), chargeiter);
374 std::advance(positer, steps);
375 DistanceVectors.push_back(
376 std::make_pair(Vector((*positer)[0], (*positer)[1], (*positer)[2]),
377 steps));
378 }
379 }
380 if (DistanceVectors.size() == (size_t)3) {
381 FunctionModel::arguments_t args(3);
382 // we require specific ordering of the carbons: ij, ik, jk
383 typedef std::vector< std::pair<size_t, size_t> > indices_t;
384 indices_t indices;
385 indices += std::make_pair(0,1), std::make_pair(0,2), std::make_pair(1,2);
386 // create the three arguments
387 for (indices_t::const_iterator iter = indices.begin(); iter != indices.end(); ++iter) {
388 const size_t &firstindex = iter->first;
389 const size_t &secondindex = iter->second;
390 argument_t &arg = args[(size_t)std::distance(const_cast<const indices_t&>(indices).begin(), iter)];
391 arg.indices.first = DistanceVectors[firstindex].second;
392 arg.indices.second = DistanceVectors[secondindex].second;
393 arg.distance = DistanceVectors[firstindex].first.distance(DistanceVectors[secondindex].first);
394 arg.globalid = DistanceEnergyVector.first.size();
395 }
396 // make largest distance last to create correct angle
397 // (this would normally depend on the order of the nodes in the subgraph)
398 std::list<argument_t> sorted_args;
399 double greatestdistance = 0.;
400 for(FunctionModel::arguments_t::const_iterator iter = args.begin(); iter != args.end(); ++iter)
401 greatestdistance = std::max(greatestdistance, iter->distance);
402 for(FunctionModel::arguments_t::const_iterator iter = args.begin(); iter != args.end(); ++iter)
403 if (iter->distance == greatestdistance)
404 sorted_args.push_back(*iter);
405 else
406 sorted_args.push_front(*iter);
407 // and add the training pair
408 DistanceEnergyVector.first.push_back( FunctionModel::arguments_t(sorted_args.begin(), sorted_args.end()) );
409 DistanceEnergyVector.second.push_back( FunctionModel::results_t(1,energy) );
410 } else {
411 ELOG(2, "main() - found not exactly three carbon atoms in fragment "
412 << fragment << ".");
413 }
414 }
415 // print training data for debugging
416 {
417 LOG(1, "INFO: I gathered the following (" << DistanceEnergyVector.first.size()
418 << "," << DistanceEnergyVector.second.size() << ") data pairs: ");
419 FunctionApproximation::inputs_t::const_iterator initer = DistanceEnergyVector.first.begin();
420 FunctionApproximation::outputs_t::const_iterator outiter = DistanceEnergyVector.second.begin();
421 for (; initer != DistanceEnergyVector.first.end(); ++initer, ++outiter) {
422 std::stringstream stream;
423 const double cos_angle = function_angle((*initer)[0].distance,(*initer)[1].distance,(*initer)[2].distance);
424 for (size_t index = 0; index < (*initer).size(); ++index)
425 stream << " (" << (*initer)[index].indices.first << "," << (*initer)[index].indices.second
426 << ") " << (*initer)[index].distance;
427 stream << " with energy " << *outiter << " and cos(angle) " << cos_angle;
428 LOG(1, "INFO:" << stream.str());
429 }
430 }
431 // NOTICE that distance are in bohrradi as they come from MPQC!
432
433 // now perform the function approximation by optimizing the model function
434 FunctionModel::parameters_t params(PairPotential_Angle::MAXPARAMS, 0.);
435 params[PairPotential_Angle::energy_offset] = -1.;
436 params[PairPotential_Angle::spring_constant] = 1.;
437 params[PairPotential_Angle::equilibrium_distance] = 0.2;
438 PairPotential_Angle angle;
439 LOG(0, "INFO: Initial parameters are " << params << ".");
440 angle.setParameters(params);
441 FunctionModel &model = angle;
442 FunctionApproximation approximator(
443 DistanceEnergyVector.first.begin()->size(),
444 DistanceEnergyVector.second.begin()->size(),
445 model);
446 approximator.setTrainingData(DistanceEnergyVector.first,DistanceEnergyVector.second);
447 if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
448 approximator(FunctionApproximation::ParameterDerivative);
449 else
450 ELOG(0, "We require parameter derivatives for a box constraint minimization.");
451 params = model.getParameters();
452
453 LOG(0, "RESULT: Best parameters are " << params << ".");
454 }
455
456 /******************** MORSE TRAINING ********************/
457 {
458 // then we ought to pick the right HomologyGraph ...
459 const HomologyGraph graph = getFirstGraphWithTwoCarbons(homologies);
460 LOG(1, "First representative graph containing two saturated carbons is " << graph << ".");
461
462 // Afterwards we go through all of this type and gather the distance and the energy value
463 TrainingData MorseData(
464 boost::bind(&Extractors::gatherFirstDistance, _1, _2, 6, 6) // gather first carbon pair
465 );
466 MorseData(homologies.getHomologousGraphs(graph));
467 LOG(1, "INFO: I gathered the following training data: " << MorseData);
468 // NOTICE that distance are in bohrradi as they come from MPQC!
469
470 // now perform the function approximation by optimizing the model function
471 FunctionModel::parameters_t params(PairPotential_Morse::MAXPARAMS, 0.);
472 params[PairPotential_Morse::dissociation_energy] = 0.5;
473 params[PairPotential_Morse::energy_offset] = -1.;
474 params[PairPotential_Morse::spring_constant] = 1.;
475 params[PairPotential_Morse::equilibrium_distance] = 2.9;
476 PairPotential_Morse morse;
477 morse.setParameters(params);
478 FunctionModel &model = morse;
479 FunctionApproximation approximator(
480 MorseData.getTrainingInputs().begin()->size(),
481 MorseData.getTrainingOutputs().begin()->size(),
482 model);
483 approximator.setTrainingData(MorseData.getTrainingInputs(),MorseData.getTrainingOutputs());
484 if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
485 approximator(FunctionApproximation::ParameterDerivative);
486 else
487 ELOG(0, "We require parameter derivatives for a box constraint minimization.");
488 params = model.getParameters();
489
490 LOG(0, "RESULT: Best parameters are " << params << ".");
491 }
492
493 /******************* SATURATION TRAINING *******************/
494 FunctionModel::parameters_t params(SaturationPotential::MAXPARAMS, 0.);
495 {
496 // then we ought to pick the right HomologyGraph ...
497 const HomologyGraph graph = getFirstGraphWithOneCarbon(homologies);
498 LOG(1, "First representative graph containing one saturated carbon is " << graph << ".");
499
500 // Afterwards we go through all of this type and gather the distance and the energy value
501 typedef std::pair<
502 FunctionApproximation::inputs_t,
503 FunctionApproximation::outputs_t> InputOutputVector_t;
504 InputOutputVector_t DistanceEnergyVector;
505 std::pair<HomologyContainer::const_iterator, HomologyContainer::const_iterator> range =
506 homologies.getHomologousGraphs(graph);
507 double EnergySum = 0.; //std::numeric_limits<double>::max();
508 size_t counter = 0.;
509 for (HomologyContainer::const_iterator iter = range.first; iter != range.second; ++iter) {
510 const double &energy = iter->second.second;
511// if (energy <= EnergySum)
512// EnergySum = energy;
513 EnergySum += energy;
514 ++counter;
515 }
516 EnergySum *= 1./(double)counter;
517 for (HomologyContainer::const_iterator iter = range.first; iter != range.second; ++iter) {
518 // get distance out of Fragment
519 const double &energy = iter->second.second;
520 const Fragment &fragment = iter->second.first;
521 const Fragment::charges_t charges = fragment.getCharges();
522 const Fragment::positions_t positions = fragment.getPositions();
523 FunctionModel::arguments_t args =
524 Extractors::_detail::gatherAllDistanceArguments(positions, DistanceEnergyVector.first.size());
525 DistanceEnergyVector.first.push_back( args );
526 DistanceEnergyVector.second.push_back( FunctionModel::results_t(1,energy-EnergySum) );
527 }
528 // print training data for debugging
529 {
530 LOG(1, "INFO: I gathered the following (" << DistanceEnergyVector.first.size()
531 << "," << DistanceEnergyVector.second.size() << ") data pairs: ");
532 FunctionApproximation::inputs_t::const_iterator initer = DistanceEnergyVector.first.begin();
533 FunctionApproximation::outputs_t::const_iterator outiter = DistanceEnergyVector.second.begin();
534 for (; initer != DistanceEnergyVector.first.end(); ++initer, ++outiter) {
535 std::stringstream stream;
536 for (size_t index = 0; index < (*initer).size(); ++index)
537 stream << "(" << (*initer)[index].indices.first << "," << (*initer)[index].indices.second
538 << ") " << (*initer)[index].distance;
539 stream << " with energy " << *outiter;
540 LOG(1, "INFO: " << stream.str());
541 }
542 }
543 // NOTICE that distance are in bohrradi as they come from MPQC!
544
545 // now perform the function approximation by optimizing the model function
546 boost::function< std::vector<FunctionModel::arguments_t>(const argument_t &, const double)> triplefunction =
547 boost::bind(&getTripleFromArgument, DistanceEnergyVector.first, _1, _2);
548 srand((unsigned)time(0)); // seed with current time
549 LOG(0, "INFO: Initial parameters are " << params << ".");
550
551 SaturationPotential saturation(triplefunction);
552 saturation.setParameters(params);
553 FunctionModel &model = saturation;
554 FunctionApproximation approximator(
555 DistanceEnergyVector.first.begin()->size(),
556 DistanceEnergyVector.second.begin()->size(),
557 model);
558 approximator.setTrainingData(DistanceEnergyVector.first,DistanceEnergyVector.second);
559 if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
560 approximator(FunctionApproximation::ParameterDerivative);
561 else
562 ELOG(0, "We require parameter derivatives for a box constraint minimization.");
563
564 params = model.getParameters();
565
566 LOG(0, "RESULT: Best parameters are " << params << ".");
567
568// std::cout << "\tsaturationparticle:";
569// std::cout << "\tparticle_type=C,";
570// std::cout << "\tA=" << params[SaturationPotential::A] << ",";
571// std::cout << "\tB=" << params[SaturationPotential::B] << ",";
572// std::cout << "\tlambda=" << params[SaturationPotential::lambda] << ",";
573// std::cout << "\tmu=" << params[SaturationPotential::mu] << ",";
574// std::cout << "\tbeta=" << params[SaturationPotential::beta] << ",";
575// std::cout << "\tn=" << params[SaturationPotential::n] << ",";
576// std::cout << "\tc=" << params[SaturationPotential::c] << ",";
577// std::cout << "\td=" << params[SaturationPotential::d] << ",";
578// std::cout << "\th=" << params[SaturationPotential::h] << ",";
579//// std::cout << "\toffset=" << params[SaturationPotential::offset] << ",";
580// std::cout << "\tR=" << saturation.R << ",";
581// std::cout << "\tS=" << saturation.S << ";";
582// std::cout << std::endl;
583
584 // check L2 and Lmax error against training set
585 double L2sum = 0.;
586 double Lmax = 0.;
587 size_t maxindex = -1;
588 FunctionApproximation::inputs_t::const_iterator initer = DistanceEnergyVector.first.begin();
589 FunctionApproximation::outputs_t::const_iterator outiter = DistanceEnergyVector.second.begin();
590 for (; initer != DistanceEnergyVector.first.end(); ++initer, ++outiter) {
591 const FunctionModel::results_t result = model((*initer));
592 const double temp = fabs((*outiter)[0] - result[0]);
593 LOG(2, "DEBUG: L2 contribution = " << (*outiter)[0] << "-" << result[0] << "=" << temp);
594 if (temp > Lmax) {
595 Lmax = temp;
596 maxindex = std::distance(const_cast<const FunctionApproximation::inputs_t &>(DistanceEnergyVector.first).begin(), initer);
597 }
598 L2sum += temp*temp;
599 }
600 LOG(1, "INFO: L2sum = " << L2sum << ", LMax = " << Lmax << " from " << maxindex);
601 }
602
603 return 0;
604}
Note: See TracBrowser for help on using the repository browser.