| 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 | }
|
|---|