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 |
|
---|
58 | namespace po = boost::program_options;
|
---|
59 |
|
---|
60 | HomologyGraph 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) */
|
---|
72 | void meyer(double *p, double *x, int m, int n, void *data)
|
---|
73 | {
|
---|
74 | register int i;
|
---|
75 | double 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 |
|
---|
83 | void jacmeyer(double *p, double *jac, int m, int n, void *data)
|
---|
84 | {
|
---|
85 | register int i, j;
|
---|
86 | double 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 |
|
---|
99 | int 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 | }
|
---|