| 1 | /* | 
|---|
| 2 | * Project: MoleCuilder | 
|---|
| 3 | * Description: creates and alters molecular systems | 
|---|
| 4 | * Copyright (C)  2010 University of Bonn. All rights reserved. | 
|---|
| 5 | * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | /** | 
|---|
| 9 | * \file potentials.dox | 
|---|
| 10 | * | 
|---|
| 11 | * Created on: Nov 28, 2012 | 
|---|
| 12 | *    Author: heber | 
|---|
| 13 | */ | 
|---|
| 14 |  | 
|---|
| 15 | /** \page potentials Empirical Potentials and FunctionModels | 
|---|
| 16 | * | 
|---|
| 17 | * On this page we explain what is meant with the Potentials sub folder. | 
|---|
| 18 | * | 
|---|
| 19 | * First, we are based on fragmenting a molecular system, i.e. dissecting its | 
|---|
| 20 | * bond structure into connected subgraphs, calculating the energies of the | 
|---|
| 21 | * fragments (ab-initio) and summing up to a good approximation of the total | 
|---|
| 22 | * energy of the whole system. | 
|---|
| 23 | * Second, having calculated these energies, there quickly comes up the thought | 
|---|
| 24 | * that one actually calculates quite similar systems all time and if one could | 
|---|
| 25 | * not cache results in an intelligent (i.e. interpolating) fashion ... | 
|---|
| 26 | * | 
|---|
| 27 | * That's where so-called empirical potentials come into play. They are | 
|---|
| 28 | * functions depending on a number of "fitted" parameters and the variable | 
|---|
| 29 | * distances within a molecular fragment (i.e. the bond lengths) in order to | 
|---|
| 30 | * give a value for the total energy without the need to solve a complex | 
|---|
| 31 | * ab-initio model. | 
|---|
| 32 | * | 
|---|
| 33 | * Empirical potentials have been thought of by fellows such as Lennard-Jones, | 
|---|
| 34 | * Morse, Tersoff, Stillinger and Weber, etc. And in their honor, the | 
|---|
| 35 | * potential form is named after its inventor. Hence, we speak e.g. of a | 
|---|
| 36 | * Lennard-Jones potential. | 
|---|
| 37 | * | 
|---|
| 38 | * So, what we have to do in order to cache results is the following procedure: | 
|---|
| 39 | * -# gather similar fragments | 
|---|
| 40 | * -# perform a fit procedure to obtain the parameters for the empirical | 
|---|
| 41 | *    potential | 
|---|
| 42 | * -# evaluate the potential instead of an ab-initio calculation | 
|---|
| 43 | * | 
|---|
| 44 | * The terms we use, model the classes that are implemented: | 
|---|
| 45 | * -# EmpiricalPotential: Contains the interface to a function that can be | 
|---|
| 46 | *    evaluated given a number of arguments_t, i.e. distances. Also, one might | 
|---|
| 47 | *    want to evaluate derivatives. | 
|---|
| 48 | * -# FunctionModel: Is a function that can be fitted, i.e. that has internal | 
|---|
| 49 | *    parameters to be set and got. | 
|---|
| 50 | * -# argument_t: The Argument stores not only the distance but also the index | 
|---|
| 51 | *    pair of the associated atoms and also their charges, to let the potential | 
|---|
| 52 | *    check on validity. | 
|---|
| 53 | * -# SerializablePotential: Eventually, one wants to store to or parse from | 
|---|
| 54 | *    a file all potential parameters. This functionality is encoded in this | 
|---|
| 55 | *    class. | 
|---|
| 56 | * -# HomologyGraph: "Similar" fragments in our case have to have the same bond | 
|---|
| 57 | *    graph. It is stored in the HomologyGraph that acts as representative | 
|---|
| 58 | * -# HomologyContainer: This container combines, in multimap fashion, all | 
|---|
| 59 | *    similar fragments with their energies together, with the HomologyGraph | 
|---|
| 60 | *    as their "key". | 
|---|
| 61 | * -# TrainingData: Here, we combine InputVector and OutputVector that contain | 
|---|
| 62 | *    the set of distances required for the FunctionModel (e.g. only a single | 
|---|
| 63 | *    distance/argument for a pair potential, three for an angle potential, | 
|---|
| 64 | *    etc.) and also the expected OutputVector. This in combination with the | 
|---|
| 65 | *    FunctionModel is the basis for the non-linear regression used for the | 
|---|
| 66 | *    fitting procedure. | 
|---|
| 67 | * -# Extractors: These set of functions yield the set of distances from a | 
|---|
| 68 | *    given fragment that is stored in the HomologyContainer. | 
|---|
| 69 | * -# FunctionApproximation: Contains the interface to the levmar package where | 
|---|
| 70 | *    the Levenberg-Marquardt (Newton + Trust region) algorithm is used to | 
|---|
| 71 | *    perform the fit. | 
|---|
| 72 | * | 
|---|
| 73 | * \section potentials-howto-use Howto use the potentials | 
|---|
| 74 | * | 
|---|
| 75 | *  We just give a brief run-down in terms of code on how to use the potentials. | 
|---|
| 76 | *  Here, we just describe what to do in order to perform the fitting. This is | 
|---|
| 77 | *  basically what is implemented in FragmentationFitPotentialAction. | 
|---|
| 78 | * | 
|---|
| 79 | *  \code | 
|---|
| 80 | *  // we need the homology container and the representative graph we want to | 
|---|
| 81 | *  // fit to. | 
|---|
| 82 | *  HomologyContainer homologies; | 
|---|
| 83 | *  const HomologyGraph graph = getSomeGraph(homologies); | 
|---|
| 84 | *  Fragment::charges_t h2o; | 
|---|
| 85 | *  h2o += 8,1,1; | 
|---|
| 86 | *  // TrainingData needs so called Extractors to get the required distances | 
|---|
| 87 | *  // from the stored fragment. These are functions are bound. | 
|---|
| 88 | *  TrainingData AngleData( | 
|---|
| 89 | *      boost::bind(&Extractors::gatherDistancesFromFragment, | 
|---|
| 90 | *          boost::bind(&Fragment::getPositions, _1), | 
|---|
| 91 | *          boost::bind(&Fragment::getCharges, _1), | 
|---|
| 92 | *          boost::cref(h2o), | 
|---|
| 93 | *          _2) | 
|---|
| 94 | *      ); | 
|---|
| 95 | *  // now we extract the distances and energies and store them | 
|---|
| 96 | *  AngleData(homologies.getHomologousGraphs(graph)); | 
|---|
| 97 | *  // give ParticleTypes of this potential to make it unique | 
|---|
| 98 | *  PairPotential_Angle::ParticleTypes_t types = | 
|---|
| 99 | *        boost::assign::list_of<PairPotential_Angle::ParticleType_t> | 
|---|
| 100 | *        (8)(1)(1) | 
|---|
| 101 | *      ; | 
|---|
| 102 | *  PairPotential_Angle angle(types); | 
|---|
| 103 | *  // give initial parameter | 
|---|
| 104 | *  FunctionModel::parameters_t params(PairPotential_Angle::MAXPARAMS, 0.); | 
|---|
| 105 | *  // ... set some potential-specific initial parameters in params struct | 
|---|
| 106 | *  angle.setParameters(params); | 
|---|
| 107 | * | 
|---|
| 108 | *  // use the potential as a FunctionModel along with prepared TrainingData | 
|---|
| 109 | *  FunctionModel &model = angle; | 
|---|
| 110 | *  FunctionApproximation approximator(AngleData, model); | 
|---|
| 111 | *  approximator(FunctionApproximation::ParameterDerivative); | 
|---|
| 112 | * | 
|---|
| 113 | *  // obtain resulting parameters and check remaining L_2 and L_max error | 
|---|
| 114 | *  angleparams = model.getParameters(); | 
|---|
| 115 | *  LOG(1, "INFO: L2sum = " << AngleData(model) | 
|---|
| 116 | *      << ", LMax = " << AngleData(model) << "."); | 
|---|
| 117 | *  \endcode | 
|---|
| 118 | * | 
|---|
| 119 | *  The evaluation of the fitted potential is then trivial, e.g. | 
|---|
| 120 | *  \code | 
|---|
| 121 | *  // constructed someplace | 
|---|
| 122 | *  PairPotential_Angle angle(...); | 
|---|
| 123 | * | 
|---|
| 124 | *  // evaluate | 
|---|
| 125 | *  FunctionModel::arguments_t args; | 
|---|
| 126 | *  // .. initialise args to the desired distances | 
|---|
| 127 | *  const double value = angle(args)[0]; // output is a vector! | 
|---|
| 128 | *  \endcode | 
|---|
| 129 | * | 
|---|
| 130 | * \section potentials-stability-of-fit note in stability of fit | 
|---|
| 131 | * | 
|---|
| 132 | *  As we always start from random initial parameters (within a certain sensible | 
|---|
| 133 | *  range at least), the non-linear fit does not always converge. For this case | 
|---|
| 134 | *  the FragmentationFitPotentialAction has the option "take-best-of" to allow | 
|---|
| 135 | *  for multiple fits where the best (in terms of l2 error) is taken eventually. | 
|---|
| 136 | * | 
|---|
| 137 | * \section potentials-howto-add Howto add new potentials | 
|---|
| 138 | * | 
|---|
| 139 | *  Adding a new potential requires the following: | 
|---|
| 140 | *  -# Add the new modules to Potentials/Specifics | 
|---|
| 141 | *  -# Add a unit test on the potential in Potentials/Specifics/unittests | 
|---|
| 142 | *  -# Give the potential a type name and add it to PotentialTypes.def. Note | 
|---|
| 143 | *     that the name must not contain white space. | 
|---|
| 144 | *  -# Add the potential name as case to PotentialFactory such that it knows | 
|---|
| 145 | *     how to instantiate your new potential when requested. | 
|---|
| 146 | * | 
|---|
| 147 | * PotentialTypes.def contains a boost::preprocessor sequence of all | 
|---|
| 148 | * potential names. PotentialFactory uses this sequence to build its enum to | 
|---|
| 149 | * type map and inverse which the user sees when specifying the potential to | 
|---|
| 150 | * fit via PotentialTypeValidator. | 
|---|
| 151 | * | 
|---|
| 152 | * | 
|---|
| 153 | * \date 2013-04-09 | 
|---|
| 154 | */ | 
|---|