- Timestamp:
- May 18, 2016, 10:02:53 PM (9 years ago)
- 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:
- 01120c
- Parents:
- d9dbef
- git-author:
- Frederik Heber <heber@…> (03/07/16 13:51:28)
- git-committer:
- Frederik Heber <heber@…> (05/18/16 22:02:53)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Actions/PotentialAction/FitPartialChargesAction.cpp
rd9dbef rd8ed62 58 58 #include "Element/element.hpp" 59 59 #include "Element/periodentafel.hpp" 60 #include "Fragmentation/Homology/AtomFragmentsMap.hpp" 60 61 #include "Fragmentation/Homology/HomologyContainer.hpp" 61 62 #include "Fragmentation/Homology/HomologyGraph.hpp" … … 117 118 } 118 119 119 ActionState::ptr PotentialFitPartialChargesAction::performCall() { 120 121 // fragment specifies the homology fragment to use 122 SerializablePotential::ParticleTypes_t fragmentnumbers; 123 { 124 const std::vector<const element *> &fragment = params.fragment.get(); 125 std::transform(fragment.begin(), fragment.end(), std::back_inserter(fragmentnumbers), 126 boost::bind(&element::getAtomicNumber, _1)); 127 } 128 129 // parse homologies into container 130 HomologyContainer &homologies = World::getInstance().getHomologies(); 131 const HomologyGraph graph = getFirstGraphwithSpecifiedElements(homologies,fragmentnumbers); 132 HomologyContainer::range_t range = homologies.getHomologousGraphs(graph); 133 // for the moment just use the very first fragment 134 if (range.first == range.second) { 135 STATUS("HomologyContainer does not contain specified fragment."); 136 return Action::failure; 137 } 138 139 // average partial charges over all fragments 140 HomologyContainer::const_iterator iter = range.first; 120 void enforceZeroTotalCharge( 121 PartialNucleiChargeFitter::charges_t &_averaged_charges) 122 { 123 double charge_sum = 0.; 124 charge_sum = std::accumulate(_averaged_charges.begin(), _averaged_charges.end(), charge_sum); 125 if (fabs(charge_sum) > MYEPSILON) { 126 std::transform( 127 _averaged_charges.begin(), _averaged_charges.end(), 128 _averaged_charges.begin(), 129 boost::bind(std::minus<double>(), _1, charge_sum/_averaged_charges.size())); 130 } 131 charge_sum = 0.; 132 charge_sum = std::accumulate(_averaged_charges.begin(), _averaged_charges.end(), charge_sum); 133 ASSERT( fabs(charge_sum) < MYEPSILON, 134 "enforceZeroTotalCharge() - enforcing neutral net charge failed, " 135 +toString(charge_sum)+" is the remaining net charge."); 136 } 137 138 size_t obtainAverageChargesOverFragments( 139 PartialNucleiChargeFitter::charges_t &_average_charges, 140 const std::pair< 141 HomologyContainer::const_iterator, 142 HomologyContainer::const_iterator> &_range, 143 const double _radius 144 ) 145 { 146 HomologyContainer::const_iterator iter = _range.first; 141 147 if (!iter->second.containsGrids) { 142 STATUS("This HomologyGraph does not contain sampled grids."); 143 return Action::failure; 144 } 145 PartialNucleiChargeFitter::charges_t averaged_charges; 146 averaged_charges.resize(iter->second.fragment.getCharges().size(), 0.); 148 ELOG(1, "This HomologyGraph does not contain sampled grids."); 149 return 0; 150 } 151 _average_charges.resize(iter->second.fragment.getCharges().size(), 0.); 147 152 size_t NoFragments = 0; 148 153 for (; 149 iter != range.second; ++iter, ++NoFragments) {154 iter != _range.second; ++iter, ++NoFragments) { 150 155 if (!iter->second.containsGrids) { 151 156 ELOG(2, "This HomologyGraph does not contain sampled grids,\ndid you forget to add '--store-grids 1' to AnalyseFragmentResults."); 152 return Action::failure;157 return 0; 153 158 } 154 159 const Fragment &fragment = iter->second.fragment; … … 161 166 && (potential.begin[2] == potential.end[2]))) { 162 167 ELOG(1, "Sampled grid contains grid made of zero points."); 163 return Action::failure;168 return 0; 164 169 } 165 170 … … 171 176 positions.push_back( Vector(pos[0], pos[1], pos[2]) ); 172 177 } 173 PartialNucleiChargeFitter fitter(potential, positions, params.radius.get());178 PartialNucleiChargeFitter fitter(potential, positions, _radius); 174 179 fitter(); 175 180 PartialNucleiChargeFitter::charges_t return_charges = fitter.getSolutionAsCharges_t(); 181 LOG(2, "DEBUG: fitted charges are " << return_charges); 176 182 std::transform( 177 183 return_charges.begin(), return_charges.end(), 178 averaged_charges.begin(),179 averaged_charges.begin(),184 _average_charges.begin(), 185 _average_charges.begin(), 180 186 std::plus<PartialNucleiChargeFitter::charge_t>()); 181 187 } 182 std::transform(averaged_charges.begin(),averaged_charges.end(), 183 averaged_charges.begin(), 184 std::bind1st(std::multiplies<PartialNucleiChargeFitter::charge_t>(),1./NoFragments) 185 ); 186 187 // make sum of charges zero if desired 188 if (params.enforceZeroCharge.get()) { 189 double charge_sum = 0.; 190 charge_sum = std::accumulate(averaged_charges.begin(), averaged_charges.end(), charge_sum); 191 if (fabs(charge_sum) > MYEPSILON) { 192 std::transform( 193 averaged_charges.begin(), averaged_charges.end(), 194 averaged_charges.begin(), 195 boost::bind(std::minus<double>(), _1, charge_sum/averaged_charges.size())); 196 } 197 charge_sum = 0.; 198 charge_sum = std::accumulate(averaged_charges.begin(), averaged_charges.end(), charge_sum); 199 ASSERT( fabs(charge_sum) < MYEPSILON, 200 "PotentialFitPartialChargesAction::performCall() - enforcing neutral net charge failed, " 201 +toString(charge_sum)+" is the remaining net charge."); 202 } 203 204 // place all fitted charges into ParticleRegistry 188 if (NoFragments != 0) 189 std::transform(_average_charges.begin(), _average_charges.end(), 190 _average_charges.begin(), 191 std::bind1st(std::multiplies<PartialNucleiChargeFitter::charge_t>(),1./(double)NoFragments) 192 ); 193 LOG(2, "DEBUG: final averaged charges are " << _average_charges); 194 195 return NoFragments; 196 } 197 198 ActionState::ptr PotentialFitPartialChargesAction::performCall() 199 { 200 // check for selected atoms 201 const World &world = const_cast<const World &>(World::getInstance()); 202 if (world.beginAtomSelection() == world.endAtomSelection()) { 203 STATUS("There are no atoms selected for fitting partial charges to."); 204 return Action::failure; 205 } 206 207 /// obtain possible fragments to each selected atom 208 AtomFragmentsMap::keysets_t fragments; 209 const AtomFragmentsMap::AtomFragmentsMap_t &atommap = 210 AtomFragmentsMap::getConstInstance().getMap(); 211 for (World::AtomSelectionConstIterator iter = world.beginAtomSelection(); 212 iter != world.endAtomSelection(); ++iter) { 213 const AtomFragmentsMap::AtomFragmentsMap_t::const_iterator atomiter = 214 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() ); 221 } 222 223 /// 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); 236 const HomologyContainer::range_t range = homologies.getHomologousGraphs(graph); 237 if (range.first == range.second) { 238 STATUS("HomologyContainer does not contain specified fragment."); 239 return Action::failure; 240 } 241 242 // fit and average partial charges over all homologous fragments 243 PartialNucleiChargeFitter::charges_t averaged_charges; 244 const size_t NoFragments = 245 obtainAverageChargesOverFragments(averaged_charges, range, params.radius.get()); 246 if ((NoFragments == 0) && (range.first != range.second)) { 247 STATUS("Fitting for fragment "+toString(*fragmentiter)+" failed."); 248 return Action::failure; 249 } 250 251 // make sum of charges zero if desired 252 if (params.enforceZeroCharge.get()) 253 enforceZeroTotalCharge(averaged_charges); 254 255 // place into map for later retrieval 256 fittedcharges_per_fragment.insert( std::make_pair(*fragmentiter, averaged_charges)); 257 258 // output status info fitted charges 259 LOG(2, "DEBUG: For fragment " << *fragmentiter << " we have fitted the following charges " 260 << averaged_charges << ", averaged over " << NoFragments << " fragments."); 261 } 262 263 /// obtain average charge for each atom the fitted charges over all its fragments 264 typedef std::map<atomId_t, double> fitted_charges_t; 265 fitted_charges_t fitted_charges; 266 for (World::AtomSelectionConstIterator atomiter = world.beginAtomSelection(); 267 atomiter != world.endAtomSelection(); ++atomiter) { 268 const AtomFragmentsMap::AtomFragmentsMap_t::const_iterator keysetsiter = 269 atommap.find(atomiter->first); 270 ASSERT(keysetsiter != atommap.end(), 271 "PotentialFitPartialChargesAction::performCall() - we checked already that " 272 +toString(atomiter->first)+" should be present!"); 273 const AtomFragmentsMap::keysets_t & keysets = keysetsiter->second; 274 275 double average_charge = 0.; 276 size_t NoFragments = 0; 277 // go over all fragments associated to this atom 278 for (AtomFragmentsMap::keysets_t::const_iterator keysetsiter = keysets.begin(); 279 keysetsiter != keysets.end(); ++keysetsiter) { 280 const KeySet &keyset = *keysetsiter; 281 282 // find the associated charge in the charge vector 283 const FragmentFittedChargeMap_t::const_iterator chargesiter = 284 fittedcharges_per_fragment.find(keyset); 285 ASSERT(chargesiter != fittedcharges_per_fragment.end(), 286 "PotentialFitPartialChargesAction::performCall() - no charge to "+toString(keyset) 287 +" any longer present in fittedcharges_per_fragment?"); 288 const PartialNucleiChargeFitter::charges_t &charges = chargesiter->second; 289 PartialNucleiChargeFitter::charges_t::const_iterator chargeiter = 290 charges.begin(); 291 const KeySet::const_iterator keysetiter = keyset.find(atomiter->first); 292 ASSERT( keysetiter != keyset.end(), 293 "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?"); 300 301 // and add onto charge sum 302 const double & charge_in_fragment = *chargeiter; 303 average_charge += charge_in_fragment; 304 ++NoFragments; 305 } 306 // average to obtain final partial charge for this atom 307 average_charge = 1./(size_t)NoFragments; 308 fitted_charges.insert( std::make_pair(atomiter->first, average_charge) ); 309 } 310 311 /// place all fitted charges into ParticleRegistry 205 312 const ParticleFactory &factory = 206 313 const_cast<const ParticleFactory&>(ParticleFactory::getInstance()); 207 314 const periodentafel &periode = *World::getInstance().getPeriode(); 208 ASSERT(averaged_charges.size() == fragmentnumbers.size(), 209 "PotentialFitPartialChargesAction::performCall() - charges and elements length mismatch."); 210 for (size_t i=0;i<averaged_charges.size(); ++i) { 211 const std::string name = Particle::findFreeName(periode, fragmentnumbers[i]); 212 LOG(2, "INFO: Adding particle " << name << " for element " 213 << fragmentnumbers[i] << ", charge " << averaged_charges[i]); 214 factory.createInstance(name, fragmentnumbers[i], averaged_charges[i]); 215 } 216 217 // output fitted charges 218 LOG(0, "STATUS: We have fitted the following charges " << averaged_charges 219 << ", averaged over " << NoFragments << " fragments."); 315 for (fitted_charges_t::const_iterator chargeiter = fitted_charges.begin(); 316 chargeiter != fitted_charges.end(); ++chargeiter) { 317 const atom * const walker = World::getInstance().getAtom(AtomById(chargeiter->first)); 318 ASSERT( walker != NULL, 319 "PotentialFitPartialChargesAction::performCall() - atom " 320 +toString(chargeiter->first)+" not present in the World?"); 321 const double &charge = chargeiter->second; 322 const atomicNumber_t elementno = walker->getElementNo(); 323 const std::string name = Particle::findFreeName(periode, elementno); 324 LOG(1, "INFO: Adding particle " << name << " for atom " 325 << *walker << " with element " << elementno << ", charge " << charge); 326 factory.createInstance(name, elementno, charge); 327 } 220 328 221 329 return Action::success;
Note:
See TracChangeset
for help on using the changeset viewer.