source: src/FunctionApproximation/Extractors.cpp@ 9897ee9

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
Last change on this file since 9897ee9 was 9897ee9, checked in by Frederik Heber <heber@…>, 12 years ago

Added combineArguments to Extractors.

  • this is required for chaining arguments_t returning functions in a tree-like
fashion, as e.g. will be required for SaturationPotential
getFragmentSpecificExtractor(), which has two types but needs to extract arguments for all possible three combinations.
  • Property mode set to 100644
File size: 19.9 KB
Line 
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 * Extractors.cpp
26 *
27 * Created on: 15.10.2012
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "CodePatterns/MemDebug.hpp"
37
38#include <sstream>
39#include <utility>
40#include <vector>
41#include <boost/assign.hpp>
42#include <boost/foreach.hpp>
43
44#include "CodePatterns/Assert.hpp"
45#include "CodePatterns/Log.hpp"
46
47#include "LinearAlgebra/Vector.hpp"
48
49#include "FunctionApproximation/Extractors.hpp"
50#include "FunctionApproximation/FunctionArgument.hpp"
51
52using namespace boost::assign;
53
54FunctionModel::arguments_t
55Extractors::gatherAllDistanceArguments(
56 const Fragment::positions_t& positions,
57 const Fragment::charges_t& charges,
58 const size_t globalid)
59{
60 FunctionModel::arguments_t result;
61
62 // go through current configuration and gather all other distances
63 Fragment::positions_t::const_iterator firstpositer = positions.begin();
64 for (;firstpositer != positions.end(); ++firstpositer) {
65 Fragment::positions_t::const_iterator secondpositer = positions.begin();//firstpositer;
66 for (; secondpositer != positions.end(); ++secondpositer) {
67 if (firstpositer == secondpositer)
68 continue;
69 argument_t arg;
70 const Vector firsttemp((*firstpositer)[0],(*firstpositer)[1],(*firstpositer)[2]);
71 const Vector secondtemp((*secondpositer)[0],(*secondpositer)[1],(*secondpositer)[2]);
72 arg.distance = firsttemp.distance(secondtemp);
73 arg.types = std::make_pair(
74 charges[ std::distance(positions.begin(), firstpositer) ],
75 charges[ std::distance(positions.begin(), secondpositer) ]
76 );
77 arg.indices = std::make_pair(
78 std::distance(
79 positions.begin(), firstpositer),
80 std::distance(
81 positions.begin(), secondpositer)
82 );
83 arg.globalid = globalid;
84 result.push_back(arg);
85 }
86 }
87
88 return result;
89}
90
91FunctionModel::arguments_t
92Extractors::gatherAllSymmetricDistanceArguments(
93 const Fragment::positions_t& positions,
94 const Fragment::charges_t& charges,
95 const size_t globalid)
96{
97 FunctionModel::arguments_t result;
98
99 // go through current configuration and gather all other distances
100 Fragment::positions_t::const_iterator firstpositer = positions.begin();
101 for (;firstpositer != positions.end(); ++firstpositer) {
102 Fragment::positions_t::const_iterator secondpositer = firstpositer;
103 for (; secondpositer != positions.end(); ++secondpositer) {
104 if (firstpositer == secondpositer)
105 continue;
106 argument_t arg;
107 const Vector firsttemp((*firstpositer)[0],(*firstpositer)[1],(*firstpositer)[2]);
108 const Vector secondtemp((*secondpositer)[0],(*secondpositer)[1],(*secondpositer)[2]);
109 arg.distance = firsttemp.distance(secondtemp);
110 arg.types = std::make_pair(
111 charges[ std::distance(positions.begin(), firstpositer) ],
112 charges[ std::distance(positions.begin(), secondpositer) ]
113 );
114 arg.indices = std::make_pair(
115 std::distance(
116 positions.begin(), firstpositer),
117 std::distance(
118 positions.begin(), secondpositer)
119 );
120 arg.globalid = globalid;
121 result.push_back(arg);
122 }
123 }
124
125 return result;
126}
127
128Fragment::positions_t Extractors::_detail::gatherPositionsFromTargets(
129 const Fragment::positions_t& positions,
130 const Fragment::charges_t& charges,
131 const chargeiters_t &targets
132 )
133{
134 Fragment::positions_t filtered_positions;
135 for (chargeiters_t::const_iterator firstpairiter = targets.begin();
136 firstpairiter != targets.end(); ++firstpairiter) {
137 Fragment::positions_t::const_iterator positer = positions.begin();
138 const size_t steps = std::distance(charges.begin(), *firstpairiter);
139 std::advance(positer, steps);
140 filtered_positions.push_back(*positer);
141 }
142 return filtered_positions;
143}
144
145FunctionModel::arguments_t Extractors::_detail::gatherDistancesFromTargets(
146 const Fragment::positions_t& positions,
147 const Fragment::charges_t& charges,
148 const chargeiters_t &targets,
149 const size_t globalid
150 )
151{
152 Fragment::positions_t filtered_positions;
153 Fragment::charges_t filtered_charges;
154 for (chargeiters_t::const_iterator firstpairiter = targets.begin();
155 firstpairiter != targets.end(); ++firstpairiter) {
156 Fragment::positions_t::const_iterator positer = positions.begin();
157 const size_t steps = std::distance(charges.begin(), *firstpairiter);
158 std::advance(positer, steps);
159 filtered_positions.push_back(*positer);
160 filtered_charges.push_back(**firstpairiter);
161 }
162 return Extractors::gatherAllSymmetricDistanceArguments(
163 filtered_positions,
164 filtered_charges,
165 globalid);
166}
167
168Extractors::elementcounts_t
169Extractors::_detail::getElementCounts(
170 const Fragment::charges_t elements
171 )
172{
173 elementcounts_t elementcounts;
174 for (Fragment::charges_t::const_iterator elementiter = elements.begin();
175 elementiter != elements.end(); ++elementiter) {
176 // insert new element
177 std::pair< elementcounts_t::iterator, bool> inserter =
178 elementcounts.insert( std::make_pair( *elementiter, 1) );
179 // if already present, just increase its count
180 if (!inserter.second)
181 ++(inserter.first->second);
182 }
183 return elementcounts;
184}
185
186Extractors::elementtargets_t
187Extractors::_detail::convertElementcountsToTargets(
188 const Fragment::charges_t &charges,
189 const elementcounts_t &elementcounts
190 )
191{
192 elementtargets_t elementtargets;
193 for (elementcounts_t::const_iterator countiter = elementcounts.begin();
194 countiter != elementcounts.end();
195 ++countiter) {
196 chargeiter_t chargeiter = charges.begin();
197 const element_t &element = countiter->first;
198 const count_t &count = countiter->second;
199 for (count_t i = 0; i < count; ++i) {
200 chargeiter_t tempiter = std::find(chargeiter, charges.end(), element);
201 if (tempiter != charges.end()) {
202 // try to insert new list
203 std::pair< elementtargets_t::iterator, bool> inserter =
204 elementtargets.insert( std::make_pair( countiter->first, chargeiters_t(1, tempiter)) );
205 // if already present, append to it
206 if (!inserter.second) {
207 inserter.first->second.push_back(tempiter);
208 } else { // if created, increase vector's reserve to known size
209 inserter.first->second.reserve(countiter->second);
210 }
211 // search from this element onwards then
212 chargeiter = ++tempiter;
213 } else {
214 //ELOG(1, "Could not find desired number of elements " << count << " in fragment.");
215 return Extractors::elementtargets_t();
216 }
217 }
218 }
219 return elementtargets;
220}
221
222Extractors::elementtargets_t
223Extractors::_detail::convertChargesToTargetMap(
224 const Fragment::charges_t& charges,
225 Fragment::charges_t elements
226 )
227{
228 // place each charge into a map
229 elementtargets_t completeelementtargets;
230 for (chargeiter_t chargeiter = charges.begin();
231 chargeiter != charges.end();
232 ++chargeiter) {
233 std::pair< elementtargets_t::iterator, bool> inserter =
234 completeelementtargets.insert( std::make_pair( *chargeiter, chargeiters_t(1, chargeiter)) );
235 // if already present, append to it
236 if (!inserter.second) {
237 inserter.first->second.push_back(chargeiter);
238 }
239 }
240 // pick out desired charges only
241 std::sort(elements.begin(), elements.end());
242 Fragment::charges_t::iterator eraseiter =
243 std::unique(elements.begin(), elements.end());
244 elements.erase(eraseiter, elements.end());
245 elementtargets_t elementtargets;
246 for(Fragment::charges_t::const_iterator iter = elements.begin();
247 iter != elements.end();
248 ++iter) {
249 elementtargets_t::const_iterator finditer = completeelementtargets.find(*iter);
250 ASSERT( finditer != completeelementtargets.end(),
251 "Extractors::_detail::convertChargesToTargetMap() - no element "+toString(*iter)+" present?");
252 std::pair< elementtargets_t::iterator, bool> inserter =
253 elementtargets.insert( std::make_pair( finditer->first, finditer->second) );
254 ASSERT( inserter.second,
255 "Extractors::_detail::convertChargesToTargetMap() - key twice?");
256 }
257 return elementtargets;
258}
259
260
261Extractors::chargeiters_t
262Extractors::_detail::realignElementtargets(
263 const elementtargets_t &elementtargets,
264 const Fragment::charges_t elements,
265 const elementcounts_t &elementcounts
266 )
267{
268 chargeiters_t targets;
269 elementcounts_t counts; // how many chargeiters of this element have been used
270 if (!elements.empty()) { // skip if no elements given
271 targets.reserve(elements.size());
272 for (Fragment::charges_t::const_iterator elementiter = elements.begin();
273 elementiter != elements.end(); ++elementiter) {
274 const element_t &element = *elementiter;
275 count_t &count = counts[element]; // if not present, std::map creates instances with default of 0
276#ifndef NDEBUG
277 {
278 elementcounts_t::const_iterator testiter = elementcounts.find(element);
279 ASSERT( (testiter != elementcounts.end()) && (count < testiter->second),
280 "Extractors::_detail::realignElementTargets() - we want to use more chargeiters for element "
281 +toString(element)+" than we counted initially.");
282 }
283#endif
284 elementtargets_t::const_iterator targetiter = elementtargets.find(element);
285 if (targetiter != elementtargets.end()) {
286 const chargeiters_t &chargeiters = targetiter->second;
287 const chargeiter_t &chargeiter = chargeiters[count++];
288 targets.push_back(chargeiter);
289 }
290 }
291 }
292 return targets;
293}
294
295FunctionModel::arguments_t
296Extractors::gatherAllDistancesFromFragment(
297 const Fragment::positions_t& positions,
298 const Fragment::charges_t& charges,
299 const Fragment::charges_t elements,
300 const size_t globalid
301 )
302{
303 /// The main problem here is that we have to know how many same
304 /// elements (but different atoms!) we are required to find. Hence,
305 /// we first have to count same elements, then get different targets
306 /// for each and then associated them in correct order back again.
307
308 // 1. we have to place each charge into a map as unique chargeiter, i.e. map
309 elementtargets_t elementtargets =
310 Extractors::_detail::convertChargesToTargetMap(
311 charges,
312 elements);
313
314 // 2. now we have to combine elementcounts out of elementtargets per desired element
315 // in a combinatorial fashion
316 targets_per_combination_t combinations =
317 Extractors::_detail::CombineChargesAndTargets(
318 elements,
319 elementtargets);
320
321 // 3. finally, convert chargeiters into argument list
322 FunctionModel::arguments_t args =
323 Extractors::_detail::convertTargetsToArguments(
324 positions,
325 charges,
326 combinations,
327 globalid);
328
329 return args;
330}
331
332Extractors::targets_per_combination_t
333Extractors::_detail::CombineChargesAndTargets(
334 const Fragment::charges_t& elements,
335 const elementtargets_t& elementtargets
336 )
337{
338 // recursively create all correct combinations of targets
339 targets_per_combination_t combinations;
340 chargeiters_t currenttargets;
341 boost::function<void (const chargeiters_t &currenttargets)> addFunction =
342 boost::bind(&targets_per_combination_t::push_back,
343 boost::ref(combinations),
344 _1);
345 pickLastElementAsTarget(elements, elementtargets, currenttargets, addFunction);
346
347 return combinations;
348}
349
350FunctionModel::arguments_t
351Extractors::_detail::convertTargetsToArguments(
352 const Fragment::positions_t& positions,
353 const Fragment::charges_t& charges,
354 const targets_per_combination_t combinations,
355 const size_t globalid
356 )
357{
358 FunctionModel::arguments_t args;
359 // create arguments from each combination
360 for (targets_per_combination_t::const_iterator iter = combinations.begin();
361 iter != combinations.end();
362 ++iter) {
363 Fragment::positions_t partpositions;
364 Fragment::charges_t partcharges;
365 partpositions.reserve(iter->size());
366 partcharges.reserve(iter->size());
367 for(chargeiters_t::const_iterator targetiter = iter->begin();
368 targetiter != iter->end();
369 ++targetiter) {
370 Fragment::positions_t::const_iterator positer = positions.begin();
371 std::advance(positer, std::distance(charges.begin(), *targetiter));
372 partpositions.push_back(*positer);
373 partcharges.push_back(**targetiter);
374 }
375 FunctionModel::arguments_t partargs =
376 gatherAllSymmetricDistanceArguments(partpositions, partcharges, globalid);
377 args.insert(args.end(), partargs.begin(), partargs.end());
378 }
379
380 return args;
381}
382
383void
384Extractors::_detail::pickLastElementAsTarget(
385 Fragment::charges_t elements,
386 elementtargets_t elementtargets,
387 chargeiters_t &currenttargets,
388 boost::function<void (const chargeiters_t &currenttargets)> &addFunction
389 )
390{
391 // get last element from charges
392 const Fragment::charge_t charge = elements.back();
393 elements.pop_back();
394 elementtargets_t::iterator iter = elementtargets.find(charge);
395 if (iter == elementtargets.end())
396 return;
397 bool NotEmpty = !iter->second.empty();
398 while (NotEmpty) {
399 // get last target from the vector of chargeiters
400 chargeiter_t target = iter->second.back();
401 iter->second.pop_back();
402 // remove this key if empty
403 if (iter->second.empty()) {
404 elementtargets.erase(iter);
405 NotEmpty = false;
406 }
407 currenttargets.push_back(target);
408 if (elements.empty()) {
409 // call add function
410 {
411 std::stringstream targetstream;
412 BOOST_FOREACH( chargeiter_t target, currenttargets ) {
413 targetstream << " " << *target;
414 }
415 LOG(3, "DEBUG: Adding set" << targetstream.str() << ".");
416 }
417 addFunction(currenttargets);
418 } else {
419 // if not, call us recursively
420 pickLastElementAsTarget(elements, elementtargets, currenttargets, addFunction);
421 }
422 // pop last in currenset again
423 currenttargets.pop_back();
424 }
425}
426
427Extractors::chargeiters_t
428Extractors::_detail::gatherTargetsFromFragment(
429 const Fragment::charges_t& charges,
430 const Fragment::charges_t elements
431 )
432{
433 /// The main problem here is that we have to know how many same
434 /// elements (but different atoms!) we are required to find. Hence,
435 /// we first have to count same elements, then get different targets
436 /// for each and then associated them in correct order back again.
437
438 // 1. we have to make elements unique with counts, hence convert to map
439 elementcounts_t elementcounts =
440 Extractors::_detail::getElementCounts(elements);
441
442 // 2. then for each element we need as many targets (chargeiters) as counts
443 elementtargets_t elementtargets =
444 Extractors::_detail::convertElementcountsToTargets(charges, elementcounts);
445
446 // 3. we go again through elements and use one found target for each count
447 // in that order
448 chargeiters_t targets =
449 Extractors::_detail::realignElementtargets(elementtargets, elements, elementcounts);
450
451#ifndef NDEBUG
452 // check all for debugging
453 for (chargeiters_t::const_iterator chargeiter = targets.begin();
454 chargeiter != targets.end();
455 ++chargeiter)
456 ASSERT( *chargeiter != charges.end(),
457 "Extractors::gatherTargetsFromFragment() - we have not found enough targets?!");
458#endif
459
460 return targets;
461}
462
463Fragment::positions_t
464Extractors::gatherPositionsFromFragment(
465 const Fragment::positions_t positions,
466 const Fragment::charges_t charges,
467 const Fragment::charges_t& elements
468 )
469{
470 // 1.-3. gather correct charge positions
471 chargeiters_t targets =
472 Extractors::_detail::gatherTargetsFromFragment(charges, elements);
473 // 4. convert position_t to Vector
474 return Extractors::_detail::gatherPositionsFromTargets(
475 positions,
476 charges,
477 targets);
478}
479
480FunctionModel::arguments_t
481Extractors::gatherDistancesFromFragment(
482 const Fragment::positions_t positions,
483 const Fragment::charges_t charges,
484 const Fragment::charges_t& elements,
485 const size_t globalid
486 )
487{
488 // 1.-3. gather correct charge positions
489 chargeiters_t targets =
490 Extractors::_detail::gatherTargetsFromFragment(charges, elements);
491 // 4. convert position_t to Vector
492 return Extractors::_detail::gatherDistancesFromTargets(
493 positions,
494 charges,
495 targets,
496 globalid);
497}
498
499FunctionModel::arguments_t Extractors::reorderArgumentsByIncreasingDistance(
500 const FunctionModel::arguments_t &args
501 )
502{
503 FunctionModel::arguments_t returnargs(args);
504 std::sort(returnargs.begin(), returnargs.end(), argument_t::DistanceComparator);
505 return returnargs;
506}
507
508FunctionModel::arguments_t Extractors::reorderArgumentsByParticleTypes(
509 const FunctionModel::arguments_t &args,
510 const ParticleTypes_t &_types
511 )
512{
513 typedef std::list< argument_t > ListArguments_t;
514 ListArguments_t availableList(args.begin(), args.end());
515 FunctionModel::arguments_t returnargs;
516 returnargs.reserve(args.size());
517
518 // TODO: fill a lookup map such that we don't have O(M^3) scaling, if M is number
519 // of types (and we always must have M(M-1)/2 args) but O(M^2 log(M)). However, as
520 // M is very small (<=3), this is not necessary fruitful now.
521// typedef ParticleTypes_t firsttype;
522// typedef ParticleTypes_t secondtype;
523// typedef std::map< firsttype, std::map< secondtype, boost::ref(args) > > ArgsLookup_t;
524// ArgsLookup_t ArgsLookup;
525
526 // basically, we have two choose any two pairs out of types but only those
527 // where the first is less than the letter. Hence, we start the second
528 // iterator at the current position of the first one and skip the equal case.
529 for (ParticleTypes_t::const_iterator firstiter = _types.begin();
530 firstiter != _types.end();
531 ++firstiter) {
532 for (ParticleTypes_t::const_iterator seconditer = firstiter;
533 seconditer != _types.end();
534 ++seconditer) {
535 if (seconditer == firstiter)
536 continue;
537
538 // search the right one in _args (we might allow switching places of
539 // firstiter and seconditer, as distance is symmetric).
540 ListArguments_t::iterator iter = availableList.begin();
541 for (;iter != availableList.end(); ++iter) {
542 LOG(3, "DEBUG: Current args is " << *iter << ".");
543 if ((iter->types.first == *firstiter)
544 && (iter->types.second == *seconditer)) {
545 returnargs.push_back( *iter );
546 break;
547 }
548 else if ((iter->types.first == *seconditer)
549 && (iter->types.second == *firstiter)) {
550 argument_t flippedtypes(*iter);
551 std::swap( flippedtypes.indices.first, flippedtypes.indices.second );
552 std::swap( flippedtypes.types.first, flippedtypes.types.second );
553 returnargs.push_back( flippedtypes );
554 break;
555 }
556 }
557 ASSERT( iter != availableList.end(),
558 "Extractors::reorderArgumentsByParticleTypes() - could not find arguments to "
559 +toString(*firstiter)+","+toString(*seconditer)+".");
560 availableList.erase(iter);
561 }
562 }
563// LOG(2, "DEBUG: Final list of args is " << returnargs << ".");
564
565 return returnargs;
566}
567
568
569FunctionModel::arguments_t Extractors::combineArguments(
570 const FunctionModel::arguments_t &firstargs,
571 const FunctionModel::arguments_t &secondargs)
572{
573 FunctionModel::arguments_t args(firstargs);
574 args.insert(args.end(), secondargs.begin(), secondargs.end());
575 return args;
576}
Note: See TracBrowser for help on using the repository browser.