source: src/LevMartester.cpp@ bf12d1

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

Added LevMartester that employs levmar package for non-linear regression.

  • as liblevmar is not a dynamically linked library, we don't need lapack.
  • path to levmar has to be given with --with-levmar (and is not tested so far).
  • LevMartester is linked against liblevmar and with includes.
  • copied Meyer's (reformulated) problem from lmdemo.c which is solved to same result.
  • Property mode set to 100644
File size: 8.0 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 "CodePatterns/MemDebug.hpp"
38
39#include <boost/archive/text_iarchive.hpp>
40#include <boost/filesystem.hpp>
41#include <boost/program_options.hpp>
42
43#include <fstream>
44#include <iostream>
45#include <iterator>
46#include <vector>
47
48#include <levmar.h>
49
50#include "CodePatterns/Assert.hpp"
51#include "CodePatterns/Log.hpp"
52
53#include "LinearAlgebra/Vector.hpp"
54
55#include "Fragmentation/Homology/HomologyContainer.hpp"
56#include "Fragmentation/SetValues/Fragment.hpp"
57
58namespace po = boost::program_options;
59
60HomologyGraph getFirstGraphWithTwoCarbons(const HomologyContainer &homologies)
61{
62 FragmentNode SaturatedCarbon(6,4); // carbon has atomic number 6 and should have 4 bonds for C2H6
63 for (HomologyContainer::container_t::const_iterator iter =
64 homologies.begin(); iter != homologies.end(); ++iter) {
65 if (iter->first.hasNode(SaturatedCarbon,2))
66 return iter->first;
67 }
68 return HomologyGraph();
69}
70
71/* Meyer's (reformulated) problem, minimum at (2.48, 6.18, 3.45) */
72void meyer(double *p, double *x, int m, int n, void *data)
73{
74register int i;
75double ui;
76
77 for(i=0; i<n; ++i){
78 ui=0.45+0.05*i;
79 x[i]=p[0]*exp(10.0*p[1]/(ui+p[2]) - 13.0);
80 }
81}
82
83void jacmeyer(double *p, double *jac, int m, int n, void *data)
84{
85register int i, j;
86double ui, tmp;
87
88 for(i=j=0; i<n; ++i){
89 ui=0.45+0.05*i;
90 tmp=exp(10.0*p[1]/(ui+p[2]) - 13.0);
91
92 jac[j++]=tmp;
93 jac[j++]=10.0*p[0]*tmp/(ui+p[2]);
94 jac[j++]=-10.0*p[0]*p[1]*tmp/((ui+p[2])*(ui+p[2]));
95 }
96}
97
98
99int main(int argc, char **argv)
100{
101 std::cout << "Hello to the World from LevMar!" << std::endl;
102
103 // load homology file
104 po::options_description desc("Allowed options");
105 desc.add_options()
106 ("help", "produce help message")
107 ("homology-file", po::value< boost::filesystem::path >(), "homology file to parse")
108 ;
109
110 po::variables_map vm;
111 po::store(po::parse_command_line(argc, argv, desc), vm);
112 po::notify(vm);
113
114 if (vm.count("help")) {
115 std::cout << desc << "\n";
116 return 1;
117 }
118
119 boost::filesystem::path homology_file;
120 if (vm.count("homology-file")) {
121 homology_file = vm["homology-file"].as<boost::filesystem::path>();
122 LOG(1, "INFO: Parsing " << homology_file.string() << ".");
123 } else {
124 LOG(0, "homology-file level was not set.");
125 }
126 HomologyContainer homologies;
127 if (boost::filesystem::exists(homology_file)) {
128 std::ifstream returnstream(homology_file.string().c_str());
129 if (returnstream.good()) {
130 boost::archive::text_iarchive ia(returnstream);
131 ia >> homologies;
132 } else {
133 ELOG(2, "Failed to parse from " << homology_file.string() << ".");
134 }
135 returnstream.close();
136 } else {
137 ELOG(0, homology_file << " does not exist.");
138 }
139
140 // first we try to look into the HomologyContainer
141 LOG(1, "INFO: Listing all present homologies ...");
142 for (HomologyContainer::container_t::const_iterator iter =
143 homologies.begin(); iter != homologies.end(); ++iter) {
144 LOG(1, "INFO: graph " << iter->first << " has Fragment "
145 << iter->second.first << " and associated energy " << iter->second.second << ".");
146 }
147
148 // then we ought to pick the right HomologyGraph ...
149 const HomologyGraph graph = getFirstGraphWithTwoCarbons(homologies);
150 LOG(1, "First representative graph containing two saturated carbons is " << graph << ".");
151
152 // Afterwards we go through all of this type and gather the distance and the energy value
153 typedef std::vector< std::pair<double, double> > DistanceEnergyVector_t;
154 DistanceEnergyVector_t DistanceEnergyVector;
155 std::pair<HomologyContainer::const_iterator, HomologyContainer::const_iterator> range =
156 homologies.getHomologousGraphs(graph);
157 for (HomologyContainer::const_iterator iter = range.first; iter != range.second; ++iter) {
158 // get distance out of Fragment
159 const Fragment &fragment = iter->second.first;
160 const Fragment::charges_t charges = fragment.getCharges();
161 const Fragment::positions_t positions = fragment.getPositions();
162 std::vector< Vector > DistanceVectors;
163 for (Fragment::charges_t::const_iterator chargeiter = charges.begin();
164 chargeiter != charges.end(); ++chargeiter) {
165 if (*chargeiter == 6) {
166 Fragment::positions_t::const_iterator positer = positions.begin();
167 const size_t steps = std::distance(charges.begin(), chargeiter);
168 std::advance(positer, steps);
169 DistanceVectors.push_back(Vector((*positer)[0], (*positer)[1], (*positer)[2]));
170 }
171 }
172 ASSERT( DistanceVectors.size() == (size_t)2,
173 "main() - found not exactly two carbon atoms in fragment.");
174 const double distance = DistanceVectors[0].distance(DistanceVectors[1]);
175 const double energy = iter->second.second;
176 DistanceEnergyVector.push_back( std::make_pair(distance, energy) );
177 }
178 LOG(1, "INFO: I gathered the following " << DistanceEnergyVector.size() << " data pairs: ");
179 for (DistanceEnergyVector_t::const_iterator dataiter = DistanceEnergyVector.begin();
180 dataiter != DistanceEnergyVector.end(); ++dataiter) {
181 LOG(1, "INFO: " << dataiter->first << " with energy " << dataiter->second);
182 }
183 // NOTICE that distance are in bohrradi as they come from MPQC!
184
185 // let levmar optimize
186 register int i, j;
187 int ret;
188 double p[5], // 5 is max(2, 3, 5)
189 x[16]; // 16 is max(2, 3, 5, 6, 16)
190 int m, n;
191 double opts[LM_OPTS_SZ], info[LM_INFO_SZ];
192
193 opts[0]=LM_INIT_MU; opts[1]=1E-15; opts[2]=1E-15; opts[3]=1E-20;
194 opts[4]= LM_DIFF_DELTA; // relevant only if the Jacobian is approximated using finite differences; specifies forward differencing
195 //opts[4]=-LM_DIFF_DELTA; // specifies central differencing to approximate Jacobian; more accurate but more expensive to compute!
196
197 m=3; n=16;
198 p[0]=8.85; p[1]=4.0; p[2]=2.5;
199 x[0]=34.780; x[1]=28.610; x[2]=23.650; x[3]=19.630;
200 x[4]=16.370; x[5]=13.720; x[6]=11.540; x[7]=9.744;
201 x[8]=8.261; x[9]=7.030; x[10]=6.005; x[11]=5.147;
202 x[12]=4.427; x[13]=3.820; x[14]=3.307; x[15]=2.872;
203 ret=dlevmar_der(meyer, jacmeyer, p, x, m, n, 1000, opts, info, NULL, NULL, NULL); // with analytic Jacobian
204
205 { double *work, *covar;
206 work=(double *)malloc((LM_DIF_WORKSZ(m, n)+m*m)*sizeof(double));
207 if(!work){
208 fprintf(stderr, "memory allocation request failed in main()\n");
209 exit(1);
210 }
211 covar=work+LM_DIF_WORKSZ(m, n);
212
213 ret=dlevmar_dif(meyer, p, x, m, n, 1000, opts, info, work, covar, NULL); // no Jacobian, caller allocates work memory, covariance estimated
214
215 printf("Covariance of the fit:\n");
216 for(i=0; i<m; ++i){
217 for(j=0; j<m; ++j)
218 printf("%g ", covar[i*m+j]);
219 printf("\n");
220 }
221 printf("\n");
222
223 free(work);
224 }
225
226// {
227// double err[16];
228// dlevmar_chkjac(meyer, jacmeyer, p, m, n, NULL, err);
229// for(i=0; i<n; ++i) printf("gradient %d, err %g\n", i, err[i]);
230// }
231
232 printf("Levenberg-Marquardt returned %d in %g iter, reason %g\nSolution: ", ret, info[5], info[6]);
233 for(i=0; i<m; ++i)
234 printf("%.7g ", p[i]);
235 printf("\n\nMinimization info:\n");
236 for(i=0; i<LM_INFO_SZ; ++i)
237 printf("%g ", info[i]);
238 printf("\n");
239
240 return 0;
241}
Note: See TracBrowser for help on using the repository browser.