Changeset 01120c for src/Actions


Ignore:
Timestamp:
May 18, 2016, 10:02:53 PM (9 years ago)
Author:
Frederik Heber <heber@…>
Branches:
Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, 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_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, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, 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:
c1ec8e
Parents:
d8ed62
git-author:
Frederik Heber <heber@…> (03/07/16 19:10:44)
git-committer:
Frederik Heber <heber@…> (05/18/16 22:02:53)
Message:

FitPartialChargesAction properly treats hydrogens now.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Actions/PotentialAction/FitPartialChargesAction.cpp

    rd8ed62 r01120c  
    4444#include "World.hpp"
    4545
     46#include <boost/bimap.hpp>
    4647#include <boost/bind.hpp>
    4748#include <boost/filesystem.hpp>
     
    5657#include "Potentials/PartialNucleiChargeFitter.hpp"
    5758
     59#include "AtomIdSet.hpp"
     60#include "Descriptors/AtomIdDescriptor.hpp"
    5861#include "Element/element.hpp"
    5962#include "Element/periodentafel.hpp"
     
    7679/** =========== define the function ====================== */
    7780
    78 inline
    79 HomologyGraph getFirstGraphwithSpecifiedElements(
    80     const HomologyContainer &homologies,
    81     const SerializablePotential::ParticleTypes_t &types)
    82 {
    83   ASSERT( !types.empty(),
    84       "getFirstGraphwithSpecifiedElements() - charges is empty?");
    85   // create charges
    86   Fragment::charges_t charges;
    87   charges.resize(types.size());
    88   std::transform(types.begin(), types.end(),
    89       charges.begin(), boost::lambda::_1);
    90   // convert into count map
    91   Extractors::elementcounts_t counts_per_charge =
    92       Extractors::_detail::getElementCounts(charges);
    93   ASSERT( !counts_per_charge.empty(),
    94       "getFirstGraphwithSpecifiedElements() - charge counts are empty?");
    95   LOG(2, "DEBUG: counts_per_charge is " << counts_per_charge << ".");
    96   // we want to check each (unique) key only once
    97   HomologyContainer::const_key_iterator olditer = homologies.key_end();
    98   for (HomologyContainer::const_key_iterator iter =
    99       homologies.key_begin(); iter != homologies.key_end();
    100       iter = homologies.getNextKey(iter)) {
    101     // if it's the same as the old one, skip it
    102     if (olditer == iter)
    103       continue;
    104     else
    105       olditer = iter;
    106     // if it's a new key, check if every element has the right number of counts
    107     Extractors::elementcounts_t::const_iterator countiter = counts_per_charge.begin();
    108     for (; countiter != counts_per_charge.end(); ++countiter)
    109       if (!(*iter).hasTimesAtomicNumber(
    110           static_cast<size_t>(countiter->first),
    111           static_cast<size_t>(countiter->second))
    112           )
    113         break;
    114     if( countiter == counts_per_charge.end())
    115       return *iter;
    116   }
    117   return HomologyGraph();
    118 }
    119 
    120 void enforceZeroTotalCharge(
     81static void enforceZeroTotalCharge(
    12182    PartialNucleiChargeFitter::charges_t &_averaged_charges)
    12283{
     
    13495      "enforceZeroTotalCharge() - enforcing neutral net charge failed, "
    13596      +toString(charge_sum)+" is the remaining net charge.");
    136 }
    137 
    138 size_t obtainAverageChargesOverFragments(
     97
     98  LOG(2, "DEBUG: final charges with net zero charge are " << _averaged_charges);
     99}
     100
     101static size_t obtainAverageChargesOverFragments(
    139102    PartialNucleiChargeFitter::charges_t &_average_charges,
    140103    const std::pair<
     
    196159}
    197160
     161inline SerializablePotential::ParticleTypes_t
     162getParticleTypesForAtomIdSet(const AtomIdSet &_atoms)
     163{
     164  SerializablePotential::ParticleTypes_t particletypes;
     165  particletypes.resize(_atoms.size());
     166  std::transform(
     167      _atoms.begin(), _atoms.end(),
     168      particletypes.begin(),
     169      boost::bind(&atom::getElementNo, _1));
     170  return particletypes;
     171}
     172
    198173ActionState::ptr PotentialFitPartialChargesAction::performCall()
    199174{
     
    206181
    207182  /// obtain possible fragments to each selected atom
    208   AtomFragmentsMap::keysets_t fragments;
    209   const AtomFragmentsMap::AtomFragmentsMap_t &atommap =
    210       AtomFragmentsMap::getConstInstance().getMap();
     183  const AtomFragmentsMap &atomfragments = AtomFragmentsMap::getConstInstance();
     184  if (!atomfragments.checkCompleteness()) {
     185    STATUS("AtomFragmentsMap failed internal consistency check, missing forcekeysets?");
     186    return Action::failure;
     187  }
     188  std::set<KeySet> fragments;
     189  const AtomFragmentsMap::AtomFragmentsMap_t &atommap = atomfragments.getMap();
    211190  for (World::AtomSelectionConstIterator iter = world.beginAtomSelection();
    212191      iter != world.endAtomSelection(); ++iter) {
    213192    const AtomFragmentsMap::AtomFragmentsMap_t::const_iterator atomiter =
    214193        atommap.find(iter->first);
    215     if (atomiter == atommap.end()) {
    216       ELOG(2, "There are no fragments associated to " << iter->first << ".");
    217       continue;
    218     }
    219     const AtomFragmentsMap::keysets_t &keysets = atomiter->second;
    220     fragments.insert( fragments.end(), keysets.begin(), keysets.end() );
     194    if (iter->second->getElementNo() != 1) {
     195      if (atomiter == atommap.end()) {
     196        ELOG(2, "There are no fragments associated to " << iter->first << ".");
     197        continue;
     198      }
     199      const AtomFragmentsMap::keysets_t &keysets = atomiter->second;
     200      LOG(2, "DEBUG: atom " << iter->first << " has " << keysets.size() << " fragments.");
     201      fragments.insert( keysets.begin(), keysets.end() );
     202    } else {
     203      LOG(3, "DEBUG: Skipping atom " << iter->first << " as it's hydrogen.");
     204    }
     205  }
     206
     207  // reduce given fragments to homologous graphs to avoid multiple fittings
     208  typedef std::map<KeySet, HomologyGraph> KeysetsToGraph_t;
     209  KeysetsToGraph_t keyset_graphs;
     210  typedef std::map<HomologyGraph, PartialNucleiChargeFitter::charges_t> GraphFittedChargeMap_t;
     211  GraphFittedChargeMap_t fittedcharges_per_fragment;
     212  HomologyContainer &homologies = World::getInstance().getHomologies();
     213  for (std::set<KeySet>::const_iterator fragmentiter = fragments.begin();
     214      fragmentiter != fragments.end(); ++fragmentiter) {
     215    const KeySet &keyset = *fragmentiter;
     216    const AtomFragmentsMap::indices_t &forceindices = atomfragments.getFullKeyset(keyset);
     217    ASSERT( !forceindices.empty(),
     218        "PotentialFitPartialChargesAction::performCall() - force keyset to "
     219        +toString(keyset)+" is empty.");
     220    KeySet forcekeyset;
     221    forcekeyset.insert(forceindices.begin(), forceindices.end());
     222    forcekeyset.erase(-1);
     223    const HomologyGraph graph(forcekeyset);
     224    LOG(2, "DEBUG: Associating keyset " << forcekeyset << " with graph " << graph);
     225    keyset_graphs.insert( std::make_pair(keyset, graph) );
     226    fittedcharges_per_fragment.insert( std::make_pair(graph, PartialNucleiChargeFitter::charges_t()) );
    221227  }
    222228
    223229  /// then go through all fragments and get partial charges for each
    224   typedef std::map<
    225       KeySet,
    226       PartialNucleiChargeFitter::charges_t> FragmentFittedChargeMap_t;
    227   FragmentFittedChargeMap_t fittedcharges_per_fragment;
    228   for (AtomFragmentsMap::keysets_t::const_iterator fragmentiter = fragments.begin();
    229       fragmentiter != fragments.end(); ++fragmentiter) {
    230     // fragment specifies the homology fragment to use
    231     SerializablePotential::ParticleTypes_t fragmentnumbers(fragmentiter->begin(), fragmentiter->end());
    232 
    233     // obtain range of homogolous fragments from container
    234     HomologyContainer &homologies = World::getInstance().getHomologies();
    235     const HomologyGraph graph = getFirstGraphwithSpecifiedElements(homologies,fragmentnumbers);
     230  for (GraphFittedChargeMap_t::iterator graphiter = fittedcharges_per_fragment.begin();
     231      graphiter != fittedcharges_per_fragment.end(); ++graphiter) {
     232    const HomologyGraph &graph = graphiter->first;
     233    LOG(2, "DEBUG: Now fitting charges to graph " << graph);
    236234    const HomologyContainer::range_t range = homologies.getHomologousGraphs(graph);
    237235    if (range.first == range.second) {
     
    241239
    242240    // fit and average partial charges over all homologous fragments
    243     PartialNucleiChargeFitter::charges_t averaged_charges;
     241    PartialNucleiChargeFitter::charges_t &averaged_charges = graphiter->second;
    244242    const size_t NoFragments =
    245243        obtainAverageChargesOverFragments(averaged_charges, range, params.radius.get());
    246244    if ((NoFragments == 0) && (range.first != range.second)) {
    247       STATUS("Fitting for fragment "+toString(*fragmentiter)+" failed.");
     245      STATUS("Fitting for fragment "+toString(*graphiter)+" failed.");
    248246      return Action::failure;
    249247    }
     
    253251      enforceZeroTotalCharge(averaged_charges);
    254252
    255     // place into map for later retrieval
    256     fittedcharges_per_fragment.insert( std::make_pair(*fragmentiter, averaged_charges));
    257 
    258253    // output status info fitted charges
    259     LOG(2, "DEBUG: For fragment " << *fragmentiter << " we have fitted the following charges "
     254    LOG(2, "DEBUG: For fragment " << *graphiter << " we have fitted the following charges "
    260255        << averaged_charges << ", averaged over " << NoFragments << " fragments.");
    261256  }
     
    266261  for (World::AtomSelectionConstIterator atomiter = world.beginAtomSelection();
    267262      atomiter != world.endAtomSelection(); ++atomiter) {
     263    const atom * walker = atomiter->second;
     264    if (walker->getElementNo() == 1) {
     265      // it's hydrogen, check its bonding and use its bond partner instead to request
     266      // keysets
     267      const BondList &ListOfBonds = walker->getListOfBonds();
     268      if ( ListOfBonds.size() != 1) {
     269        ELOG(1, "Solitary hydrogen in atom " << atomiter->first << " detected, skipping.");
     270        continue;
     271      }
     272      walker = (*ListOfBonds.begin())->GetOtherAtom(walker);
     273    }
     274    const atomId_t walkerid = walker->getId();
    268275    const AtomFragmentsMap::AtomFragmentsMap_t::const_iterator keysetsiter =
    269         atommap.find(atomiter->first);
     276        atommap.find(walkerid);
    270277    ASSERT(keysetsiter != atommap.end(),
    271278        "PotentialFitPartialChargesAction::performCall() - we checked already that "
    272         +toString(atomiter->first)+" should be present!");
     279        +toString(walkerid)+" should be present!");
    273280    const AtomFragmentsMap::keysets_t & keysets = keysetsiter->second;
    274281
     
    280287      const KeySet &keyset = *keysetsiter;
    281288
     289      const AtomFragmentsMap::indices_t &forcekeyset = atomfragments.getFullKeyset(keyset);
     290      ASSERT( !forcekeyset.empty(),
     291          "PotentialFitPartialChargesAction::performCall() - force keyset to "
     292          +toString(keyset)+" is empty.");
     293
    282294      // find the associated charge in the charge vector
    283       const FragmentFittedChargeMap_t::const_iterator chargesiter =
    284           fittedcharges_per_fragment.find(keyset);
     295      const HomologyGraph &graph = keyset_graphs[keyset];
     296      const GraphFittedChargeMap_t::const_iterator chargesiter =
     297          fittedcharges_per_fragment.find(graph);
    285298      ASSERT(chargesiter != fittedcharges_per_fragment.end(),
    286299          "PotentialFitPartialChargesAction::performCall() - no charge to "+toString(keyset)
    287300          +" any longer present in fittedcharges_per_fragment?");
    288301      const PartialNucleiChargeFitter::charges_t &charges = chargesiter->second;
     302      ASSERT( charges.size() == forcekeyset.size(),
     303          "PotentialFitPartialChargesAction::performCall() - charges "
     304          +toString(charges.size())+" and keyset "+toString(forcekeyset.size())
     305          +" do not have the same length?");
    289306      PartialNucleiChargeFitter::charges_t::const_iterator chargeiter =
    290307          charges.begin();
    291       const KeySet::const_iterator keysetiter = keyset.find(atomiter->first);
    292       ASSERT( keysetiter != keyset.end(),
     308      const AtomFragmentsMap::indices_t::const_iterator forcekeysetiter =
     309          std::find(forcekeyset.begin(), forcekeyset.end(), atomiter->first);
     310      ASSERT( forcekeysetiter != forcekeyset.end(),
    293311          "PotentialFitPartialChargesAction::performCall() - atom "
    294           +toString(atomiter->first)+" not contained in keyset "+toString(keyset));
    295       std::advance(chargeiter, std::distance(keyset.begin(), keysetiter));
    296       ASSERT( chargeiter != charges.end(),
    297           "PotentialFitPartialChargesAction::performCall() - charges "
    298           +toString(charges.size())+" and keyset "+toString(keyset.size())
    299           +" do not have the same length?");
     312          +toString(atomiter->first)+" not contained in force keyset "+toString(forcekeyset));
     313      std::advance(chargeiter, std::distance(forcekeyset.begin(), forcekeysetiter));
    300314
    301315      // and add onto charge sum
     
    305319    }
    306320    // average to obtain final partial charge for this atom
    307     average_charge = 1./(size_t)NoFragments;
     321    average_charge *= 1./(double)NoFragments;
    308322    fitted_charges.insert( std::make_pair(atomiter->first, average_charge) );
     323
     324    LOG(2, "DEBUG: For atom " << atomiter->first << " we have an average charge of "
     325        << average_charge);
    309326  }
    310327
Note: See TracChangeset for help on using the changeset viewer.