Changeset baccf6


Ignore:
Timestamp:
Jul 8, 2013, 2:22:03 PM (11 years ago)
Author:
Frederik Heber <heber@…>
Branches:
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
Children:
49dcf7
Parents:
7c1091
git-author:
Frederik Heber <heber@…> (05/10/13 07:11:56)
git-committer:
Frederik Heber <heber@…> (07/08/13 14:22:03)
Message:

FitPotentialAction now uses new CompoundPotential to fit.

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/Actions/FragmentationAction/FitPotentialAction.cpp

    r7c1091 rbaccf6  
    6060#include "FunctionApproximation/TrainingData.hpp"
    6161#include "FunctionApproximation/writeDistanceEnergyTable.hpp"
     62#include "Potentials/CompoundPotential.hpp"
     63#include "Potentials/PotentialDeserializer.hpp"
    6264#include "Potentials/PotentialFactory.hpp"
     65#include "Potentials/PotentialRegistry.hpp"
     66#include "Potentials/PotentialSerializer.hpp"
    6367#include "Potentials/SerializablePotential.hpp"
    6468
     
    109113
    110114Action::state_ptr FragmentationFitPotentialAction::performCall() {
    111   // charges specify the potential type
    112   SerializablePotential::ParticleTypes_t chargenumbers;
    113   {
    114     const std::vector<const element *> &charges = params.charges.get();
    115     std::transform(charges.begin(), charges.end(), std::back_inserter(chargenumbers),
    116         boost::bind(&element::getAtomicNumber, _1));
    117   }
    118115  // fragment specifies the homology fragment to use
    119116  SerializablePotential::ParticleTypes_t fragmentnumbers;
     
    122119    std::transform(fragment.begin(), fragment.end(), std::back_inserter(fragmentnumbers),
    123120        boost::bind(&element::getAtomicNumber, _1));
     121  }
     122
     123  // either charges and a potential is specified or a file
     124  if (boost::filesystem::exists(params.potential_file.get())) {
     125    std::ifstream returnstream(params.potential_file.get().string().c_str());
     126    if (returnstream.good()) {
     127      PotentialDeserializer deserialize(returnstream);
     128      deserialize();
     129    } else {
     130      ELOG(0, "Failed to parse from " << params.potential_file.get().string() << ".");
     131      return Action::failure;
     132    }
     133    returnstream.close();
     134
     135    LOG(0, "STATUS: I'm training now a set of potentials parsed from "
     136        << params.potential_file.get().string() << " on a fragment "
     137        << fragmentnumbers << " on data from " << params.homology_file.get() << ".");
     138
     139  } else {
     140    if (params.charges.get().empty()) {
     141      ELOG(1, "Neither charges nor potential file given!");
     142      return Action::failure;
     143    } else {
     144      // charges specify the potential type
     145      SerializablePotential::ParticleTypes_t chargenumbers;
     146      {
     147        const std::vector<const element *> &charges = params.charges.get();
     148        std::transform(charges.begin(), charges.end(), std::back_inserter(chargenumbers),
     149            boost::bind(&element::getAtomicNumber, _1));
     150      }
     151
     152      LOG(0, "STATUS: I'm training now a " << params.potentialtype.get()
     153          << " potential on charges " << chargenumbers << " on data from "
     154          << params.homology_file.get() << ".");
     155
     156      // register desired potential and an additional constant one
     157      EmpiricalPotential *potential =
     158          PotentialFactory::getInstance().createInstance(
     159              params.potentialtype.get(),
     160              chargenumbers);
     161      PotentialRegistry::getInstance().registerInstance(potential);
     162      EmpiricalPotential *constant =
     163          PotentialFactory::getInstance().createInstance(
     164              std::string("constant"),
     165              SerializablePotential::ParticleTypes_t());
     166      PotentialRegistry::getInstance().registerInstance(constant);
     167    }
    124168  }
    125169
     
    149193  }
    150194
    151   LOG(0, "STATUS: I'm training now a " << params.potentialtype.get() << " potential on charges "
    152       << chargenumbers << " on data from " << params.homology_file.get() << ".");
     195  // then we ought to pick the right HomologyGraph ...
     196  const HomologyGraph graph = getFirstGraphwithSpecifiedElements(homologies,fragmentnumbers);
     197  if (graph != HomologyGraph()) {
     198    LOG(1, "First representative graph containing fragment "
     199        << fragmentnumbers << " is " << graph << ".");
     200  } else {
     201    ELOG(1, "Specific fragment " << fragmentnumbers << " not found in homologies!");
     202    return Action::failure;
     203  }
     204
     205  // fit potential
     206  FunctionModel *model = new CompoundPotential(graph);
     207  ASSERT( model != NULL,
     208      "FragmentationFitPotentialAction::performCall() - model is NULL.");
    153209
    154210  /******************** TRAINING ********************/
    155211  // fit potential
    156   FunctionModel *model =
    157       PotentialFactory::getInstance().createInstance(
    158           params.potentialtype.get(),
    159           chargenumbers);
    160   ASSERT( model != NULL,
    161       "main() - model returned from PotentialFactory is NULL.");
    162212  FunctionModel::parameters_t bestparams(model->getParameterDimension(), 0.);
    163213  {
    164     // then we ought to pick the right HomologyGraph ...
    165     const HomologyGraph graph = getFirstGraphwithSpecifiedElements(homologies,fragmentnumbers);
    166     if (graph != HomologyGraph()) {
    167       LOG(1, "First representative graph containing fragment "
    168           << fragmentnumbers << " is " << graph << ".");
    169 
    170       // Afterwards we go through all of this type and gather the distance and the energy value
    171       TrainingData data(model->getFragmentSpecificExtractor());
    172       data(homologies.getHomologousGraphs(graph));
    173 
    174       // print distances and energies if desired for debugging
    175       if (!data.getTrainingInputs().empty()) {
    176         // print which distance is which
    177         size_t counter=1;
    178         if (DoLog(3)) {
    179           const FunctionModel::arguments_t &inputs = data.getTrainingInputs()[0];
    180           for (FunctionModel::arguments_t::const_iterator iter = inputs.begin();
    181               iter != inputs.end(); ++iter) {
    182             const argument_t &arg = *iter;
    183             LOG(3, "DEBUG: distance " << counter++ << " is between (#"
    184                 << arg.indices.first << "c" << arg.types.first << ","
    185                 << arg.indices.second << "c" << arg.types.second << ").");
    186           }
    187         }
    188 
    189         // print table
    190         LOG(3, "DEBUG: I gathered the following training data:\n" <<
    191             _detail::writeDistanceEnergyTable(data.getDistanceEnergyTable()));
    192       }
    193 
    194       // now perform the function approximation by optimizing the model function
    195       FunctionApproximation approximator(data, *model);
    196       if (model->isBoxConstraint() && approximator.checkParameterDerivatives()) {
    197         double l2error = std::numeric_limits<double>::infinity();
    198         // seed with current time
    199         srand((unsigned)time(0));
    200         for (unsigned int runs=0; runs < params.best_of_howmany.get(); ++runs) {
    201           // generate new random initial parameter values
    202           model->setParametersToRandomInitialValues(data);
    203           LOG(1, "INFO: Initial parameters of run " << runs << " are "
    204               << model->getParameters() << ".");
    205           approximator(FunctionApproximation::ParameterDerivative);
    206           LOG(1, "INFO: Final parameters of run " << runs << " are "
    207               << model->getParameters() << ".");
    208           const double new_l2error = data.getL2Error(*model);
    209           if (new_l2error < l2error) {
    210             // store currently best parameters
    211             l2error = new_l2error;
    212             bestparams = model->getParameters();
    213             LOG(1, "STATUS: New fit from run " << runs
    214                 << " has better error of " << l2error << ".");
    215           }
    216         }
    217         // reset parameters from best fit
    218         model->setParameters(bestparams);
    219         LOG(1, "INFO: Best parameters with L2 error of "
    220             << l2error << " are " << model->getParameters() << ".");
    221       } else {
    222         ELOG(0, "We require parameter derivatives for a box constraint minimization.");
    223         return Action::failure;
    224       }
    225 
    226       // create a map of each fragment with error.
    227       typedef std::multimap< double, size_t > WorseFragmentMap_t;
    228       WorseFragmentMap_t WorseFragmentMap;
    229       HomologyContainer::range_t fragmentrange = homologies.getHomologousGraphs(graph);
    230       // fragments make it into the container in reversed order, hence count from top down
    231       size_t index= std::distance(fragmentrange.first, fragmentrange.second)-1;
    232       for (HomologyContainer::const_iterator iter = fragmentrange.first;
    233           iter != fragmentrange.second;
    234           ++iter) {
    235         const Fragment& fragment = iter->second.first;
    236         const double &energy = iter->second.second;
    237 
    238         // create arguments from the fragment
    239         FunctionModel::extractor_t extractor = model->getFragmentSpecificExtractor();
    240         FunctionModel::arguments_t args = extractor(fragment, 1);
    241 
    242         // calculate value from potential
    243         const double fitvalue = (*model)(args)[0];
    244 
    245         // insert difference into map
    246         const double error = fabs(energy - fitvalue);
    247         WorseFragmentMap.insert( std::make_pair( error, index-- ) );
    248 
    249         {
    250           // give only the distances in the debugging text
    251           std::stringstream streamargs;
    252           BOOST_FOREACH (argument_t arg, args) {
    253             streamargs << " " << arg.distance*AtomicLengthToAngstroem;
    254           }
    255           LOG(2, "DEBUG: frag.#" << index+1 << "'s error is |" << energy << " - " << fitvalue
    256               << "| = " << error << " for args " << streamargs.str() << ".");
     214    // Afterwards we go through all of this type and gather the distance and the energy value
     215    TrainingData data(model->getFragmentSpecificExtractor());
     216    data(homologies.getHomologousGraphs(graph));
     217
     218    // print distances and energies if desired for debugging
     219    if (!data.getTrainingInputs().empty()) {
     220      // print which distance is which
     221      size_t counter=1;
     222      if (DoLog(3)) {
     223        const FunctionModel::arguments_t &inputs = data.getTrainingInputs()[0];
     224        for (FunctionModel::arguments_t::const_iterator iter = inputs.begin();
     225            iter != inputs.end(); ++iter) {
     226          const argument_t &arg = *iter;
     227          LOG(3, "DEBUG: distance " << counter++ << " is between (#"
     228              << arg.indices.first << "c" << arg.types.first << ","
     229              << arg.indices.second << "c" << arg.types.second << ").");
    257230        }
    258231      }
    259       LOG(0, "RESULT: WorstFragmentMap " << WorseFragmentMap << ".");
    260 
    261       SerializablePotential *potential = dynamic_cast<SerializablePotential *>(model);
    262       if (potential != NULL) {
    263         LOG(1, "STATUS: Resulting parameters are " << std::endl << *potential);
    264       } else {
    265         LOG(1, "INFO: FunctionModel is no serializable potential.");
     232
     233      // print table
     234      LOG(3, "DEBUG: I gathered the following training data:\n" <<
     235          _detail::writeDistanceEnergyTable(data.getDistanceEnergyTable()));
     236    }
     237
     238    // now perform the function approximation by optimizing the model function
     239    FunctionApproximation approximator(data, *model);
     240    if (model->isBoxConstraint() && approximator.checkParameterDerivatives()) {
     241      double l2error = std::numeric_limits<double>::infinity();
     242      // seed with current time
     243      srand((unsigned)time(0));
     244      for (unsigned int runs=0; runs < params.best_of_howmany.get(); ++runs) {
     245        // generate new random initial parameter values
     246        model->setParametersToRandomInitialValues(data);
     247        LOG(1, "INFO: Initial parameters of run " << runs << " are "
     248            << model->getParameters() << ".");
     249        approximator(FunctionApproximation::ParameterDerivative);
     250        LOG(1, "INFO: Final parameters of run " << runs << " are "
     251            << model->getParameters() << ".");
     252        const double new_l2error = data.getL2Error(*model);
     253        if (new_l2error < l2error) {
     254          // store currently best parameters
     255          l2error = new_l2error;
     256          bestparams = model->getParameters();
     257          LOG(1, "STATUS: New fit from run " << runs
     258              << " has better error of " << l2error << ".");
     259        }
    266260      }
    267     }
     261      // reset parameters from best fit
     262      model->setParameters(bestparams);
     263      LOG(1, "INFO: Best parameters with L2 error of "
     264          << l2error << " are " << model->getParameters() << ".");
     265    } else {
     266      ELOG(0, "We require parameter derivatives for a box constraint minimization.");
     267      return Action::failure;
     268    }
     269
     270    // create a map of each fragment with error.
     271    typedef std::multimap< double, size_t > WorseFragmentMap_t;
     272    WorseFragmentMap_t WorseFragmentMap;
     273    HomologyContainer::range_t fragmentrange = homologies.getHomologousGraphs(graph);
     274    // fragments make it into the container in reversed order, hence count from top down
     275    size_t index= std::distance(fragmentrange.first, fragmentrange.second)-1;
     276    for (HomologyContainer::const_iterator iter = fragmentrange.first;
     277        iter != fragmentrange.second;
     278        ++iter) {
     279      const Fragment& fragment = iter->second.first;
     280      const double &energy = iter->second.second;
     281
     282      // create arguments from the fragment
     283      FunctionModel::extractor_t extractor = model->getFragmentSpecificExtractor();
     284      FunctionModel::arguments_t args = extractor(fragment, 1);
     285
     286      // calculate value from potential
     287      const double fitvalue = (*model)(args)[0];
     288
     289      // insert difference into map
     290      const double error = fabs(energy - fitvalue);
     291      WorseFragmentMap.insert( std::make_pair( error, index-- ) );
     292
     293      {
     294        // give only the distances in the debugging text
     295        std::stringstream streamargs;
     296        BOOST_FOREACH (argument_t arg, args) {
     297          streamargs << " " << arg.distance*AtomicLengthToAngstroem;
     298        }
     299        LOG(2, "DEBUG: frag.#" << index+1 << "'s error is |" << energy << " - " << fitvalue
     300            << "| = " << error << " for args " << streamargs.str() << ".");
     301      }
     302    }
     303    LOG(0, "RESULT: WorstFragmentMap " << WorseFragmentMap << ".");
     304
     305    // print fitted potentials
     306    std::stringstream potentials;
     307    PotentialSerializer serialize(potentials);
     308    serialize();
     309    LOG(1, "STATUS: Resulting parameters are " << std::endl << potentials.str());
    268310  }
    269311  delete model;
  • src/Actions/FragmentationAction/FitPotentialAction.def

    r7c1091 rbaccf6  
    1111#include <vector>
    1212
     13#include "Parameters/Validators/DummyValidator.hpp"
    1314#include "Parameters/Validators/RangeValidator.hpp"
    1415#include "Parameters/Validators/STLVectorValidator.hpp"
     
    2021// ValueStorage by the token "Z" -> first column: int, Z, "Z"
    2122// "undefine" if no parameters are required, use (NOPARAM_DEFAULT) for each (undefined) default value
    22 #define paramtypes (boost::filesystem::path)(std::string)(std::vector<const element *>)(std::vector<const element *>)(unsigned int)
    23 #define paramtokens ("homology-file")("fit-potential")("potential-charges")("fragment-charges")("take-best-of")
    24 #define paramdescriptions ("homology file to parse")("potential type to fit")("charges specifying the potential")("charges specifying the fragment")("take the best among this many approximations")
    25 #define paramdefaults (NOPARAM_DEFAULT)(NOPARAM_DEFAULT)(NOPARAM_DEFAULT)(NOPARAM_DEFAULT)(PARAM_DEFAULT(3))
    26 #define paramreferences (homology_file)(potentialtype)(charges)(fragment)(best_of_howmany)
     23#define paramtypes (boost::filesystem::path)(std::string)(boost::filesystem::path)(std::vector<const element *>)(std::vector<const element *>)(unsigned int)
     24#define paramtokens ("homology-file")("fit-potential")("potential-file")("potential-charges")("fragment-charges")("take-best-of")
     25#define paramdescriptions ("homology file to parse")("potential type to fit")("potential file specifying multiple potentials to fit")("charges specifying the potential")("charges specifying the fragment")("take the best among this many approximations")
     26#define paramdefaults (NOPARAM_DEFAULT)(NOPARAM_DEFAULT)(NOPARAM_DEFAULT)(NOPARAM_DEFAULT)(NOPARAM_DEFAULT)(PARAM_DEFAULT(3))
     27#define paramreferences (homology_file)(potentialtype)(potential_file)(charges)(fragment)(best_of_howmany)
    2728#define paramvalids \
    2829(FilePresentValidator()) \
    2930(PotentialTypeValidator()) \
    30 (STLVectorValidator< std::vector<const element *> >(1,99, ElementValidator())) \
     31(DummyValidator<boost::filesystem::path>()) \
     32(STLVectorValidator< std::vector<const element *> >(0,99, ElementValidator())) \
    3133(STLVectorValidator< std::vector<const element *> >(1,99, ElementValidator())) \
    3234(RangeValidator< unsigned int>(1,99))
  • tests/Python/AllActions/options.dat

    r7c1091 rbaccf6  
    134134position        "9.78 2.64 2.64"
    135135potential-charges       "1 1"
     136potential-file  "test.potentials"
    136137radius  "20."
    137138random-atom-displacement        "0."
  • tests/regression/Fragmentation/FitPotential/testsuite-fragmentation-fit-potential.at

    r7c1091 rbaccf6  
    2121AT_SETUP([Fragmentation - Fit morse potential to water])
    2222AT_KEYWORDS([fragmentation fit-potential morse])
    23 AT_XFAIL_IF([/bin/true])
    2423AT_SKIP_IF([../../molecuilder --help --actionname fit-potential; if test $? -eq 5; then /bin/true; else /bin/false; fi])
    2524
     
    3130AT_CHECK([grep "Best parameters with L2 error" stdout | awk '{if ($8 > 1e-6) exit 1}'], 0, [ignore], [ignore])
    3231# check parameters to printed precision
    33 AT_CHECK([grep "morse:.*particle_type1=8,.*particle_type2=1,.*spring_constant=1.2652,.*equilibrium_distance=1.78095,.*dissociation_energy=0.401285;" stdout], 0, [ignore], [ignore])
     32AT_CHECK([grep "morse:.*particle_type1=8,.*particle_type2=1,.*spring_constant=1.27.*,.*equilibrium_distance=1.78.*,.*dissociation_energy=0.19.*;" stdout], 0, [ignore], [ignore])
    3433
    3534AT_CLEANUP
     
    3736AT_SETUP([Fragmentation - Fit harmonic_angle potential to water])
    3837AT_KEYWORDS([fragmentation fit-potential harmonic_angle])
    39 AT_XFAIL_IF([/bin/true])
    4038AT_SKIP_IF([../../molecuilder --help --actionname fit-potential; if test $? -eq 5; then /bin/true; else /bin/false; fi])
    4139
     
    4745AT_CHECK([grep "||e||_2:" stdout | awk '{if ($7 > 1e-6) exit 1}'], 0, [ignore], [ignore])
    4846# check parameters to printed precision
    49 AT_CHECK([grep "harmonic_angle:.*particle_type1=1,.*particle_type2=8,.*particle_type3=1,.*spring_constant=0.100497,.*equilibrium_distance=-0.274675;" stdout], 0, [ignore], [ignore])
     47AT_CHECK([grep "harmonic_angle:.*particle_type1=1,.*particle_type2=8,.*particle_type3=1,.*spring_constant=0.10.*,.*equilibrium_distance=-0.27.*;" stdout], 0, [ignore], [ignore])
    5048
    5149AT_CLEANUP
Note: See TracChangeset for help on using the changeset viewer.