source: src/Actions/MoleculeAction/StretchBondAction.cpp

Candidate_v1.6.1
Last change on this file was bccbe9, checked in by Frederik Heber <frederik.heber@…>, 8 years ago

Extracted extraction (subset of) nodes from BoostGraph into BreadthFirstSearchGatherer.

  • also added helper namespace BoostGraphHelpers.
  • we now treat the vertex indices and vertex names properly. Before that they had to coincide. Now, the name is the atomic id associated with the node and the index is the boost::graph internal index.
  • Property mode set to 100644
File size: 7.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 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * StretchBondAction.cpp
25 *
26 * Created on: Sep 26, 2012
27 * Author: heber
28 */
29
30// include config.h
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35//#include "CodePatterns/MemDebug.hpp"
36
37#include "Actions/MoleculeAction/StretchBondAction.hpp"
38
39#include <boost/bind.hpp>
40
41#include "CodePatterns/Assert.hpp"
42#include "CodePatterns/Log.hpp"
43#include "CodePatterns/Verbose.hpp"
44
45#include "LinearAlgebra/Plane.hpp"
46
47#include "Atom/atom.hpp"
48#include "Bond/bond.hpp"
49#include "Descriptors/AtomIdDescriptor.hpp"
50#include "Graph/BoostGraphCreator.hpp"
51#include "Graph/BoostGraphHelpers.hpp"
52#include "Graph/BreadthFirstSearchGatherer.hpp"
53#include "molecule.hpp"
54#include "World.hpp"
55
56using namespace MoleCuilder;
57
58// and construct the stuff
59#include "StretchBondAction.def"
60#include "Action_impl_pre.hpp"
61
62
63static bool addEdgePredicate(
64 const bond &_bond,
65 const std::vector<atomId_t> &_atomids)
66{
67 ASSERT(_atomids.size() == (size_t)2,
68 "addEdgePredicate() - atomids must contain exactly two ids.");
69 // do not add selected edge
70 return ((_bond.leftatom->getId() != _atomids[0])
71 || (_bond.rightatom->getId() != _atomids[1]));
72}
73
74/** =========== define the function ====================== */
75ActionState::ptr MoleculeStretchBondAction::performCall()
76{
77 // check preconditions
78 const std::vector< atom *> atoms = World::getInstance().getSelectedAtoms();
79 if (atoms.size() != 2) {
80 STATUS("Exactly two atoms must be selected.");
81 return Action::failure;
82 }
83 molecule *mol = World::getInstance().
84 getMolecule(MoleculeById(atoms[0]->getMolecule()->getId()));
85 if (mol != atoms[1]->getMolecule()) {
86 STATUS("The two selected atoms must belong to the same molecule.");
87 return Action::failure;
88 }
89
90 // gather undo information
91 const double olddistance = atoms[0]->getPosition().distance(atoms[1]->getPosition());
92 const double newdistance = params.bonddistance.get();
93 LOG(1, "INFO: Old bond distance is " << olddistance << ", stretching to " << newdistance << ".");
94
95 // gather sorted ids
96 std::vector<atomId_t> atomids(2);
97 atomids[0] = atoms[0]->getId();
98 atomids[1] = atoms[1]->getId();
99 std::sort(atomids.begin(), atomids.end());
100 LOG(1, "DEBUG: Selected nodes are " << atomids);
101
102 const Vector NormalVector = (atoms[0]->getPosition() - atoms[1]->getPosition())* (1./olddistance);
103 const double shift = 0.5*(newdistance - olddistance);
104 std::vector<Vector> Shift(2);
105 Shift[0] = shift * NormalVector;
106 Shift[1] = -shift * NormalVector;
107 Box &domain = World::getInstance().getDomain();
108
109 // Assume the selected bond splits the molecule into two parts, each one on
110 // either side of the bond. We need to perform a BFS from each bond partner
111 // not using the selected bond. Therefrom, we obtain two sets of atoms/nodes.
112 // If both are disjoint, the bond is not contained in a cycle and we simply
113 // shift either set as desired. If not, then we simply shift each atom,
114 // leaving the other positions untouched.
115
116 // get nodes on either side of selected bond via BFS discovery
117 BoostGraphCreator BGcreator;
118 BGcreator.createFromMolecule(*mol,
119 boost::bind(addEdgePredicate, _1, boost::ref(atomids)));
120 BreadthFirstSearchGatherer NodeGatherer(BGcreator);
121 std::vector< BoostGraphHelpers::Nodeset_t > bondside_sets(2);
122 for(size_t j=0;j<2;++j) {
123 bondside_sets[j] = NodeGatherer(atoms[j]->getId());
124 std::sort(bondside_sets[j].begin(), bondside_sets[j].end());
125 }
126
127 // simple test whether bond has split the system in two disjoint sets or not
128 bool isCyclic = false;
129 if ((bondside_sets[0].size() + bondside_sets[1].size()) > BGcreator.getNumVertices()) {
130 // Check whether there are common nodes in each set of distances
131 if (BoostGraphHelpers::isCommonNodeInVector(bondside_sets[0], bondside_sets[1])) {
132 ELOG(2, "Sets contain common node, hence bond must have been by cyclic."
133 << " Shifting only bond partners.");
134 for(size_t j=0;j<2;++j) {
135 bondside_sets[j].clear();
136 bondside_sets[j].push_back( atomids[j] );
137 const Vector &position = atoms[j]->getPosition();
138 atoms[j]->setPosition( domain.enforceBoundaryConditions(position+Shift[j]) );
139 }
140 isCyclic = true;
141 }
142 }
143
144 // go through the molecule and stretch each atom in either set of nodes
145 if (!isCyclic) {
146 for (molecule::iterator iter = mol->begin(); iter != mol->end(); ++iter) {
147 const Vector &position = (*iter)->getPosition();
148 // for each atom determine in which set of nodes it is and shift accordingly
149 const atomId_t &atomid = (*iter)->getId();
150 if (std::binary_search(bondside_sets[0].begin(), bondside_sets[0].end(), atomid)) {
151 (*iter)->setPosition( domain.enforceBoundaryConditions(position+Shift[0]) );
152 } else if (std::binary_search(bondside_sets[1].begin(), bondside_sets[1].end(), atomid)) {
153 (*iter)->setPosition( domain.enforceBoundaryConditions(position+Shift[1]) );
154 } else {
155 ELOG(1, "Atom " << *iter << " is not contained on either side of bond? Undoing done shifts");
156 // Have to undo shifts
157 for (size_t i=0;i<2;++i) {
158 for (BoostGraphHelpers::Nodeset_t::const_iterator iter = bondside_sets[i].begin();
159 iter != bondside_sets[i].end(); ++iter) {
160 atom &walker = *World::getInstance().getAtom(AtomById(*iter));
161 const Vector &position = walker.getPosition();
162 walker.setPosition( domain.enforceBoundaryConditions(position-Shift[i]) );
163 }
164 }
165 return Action::failure;
166 }
167 }
168 }
169
170 MoleculeStretchBondState *UndoState = new MoleculeStretchBondState(Shift, bondside_sets, mol, params);
171 return ActionState::ptr(UndoState);
172}
173
174ActionState::ptr MoleculeStretchBondAction::performUndo(ActionState::ptr _state) {
175 MoleculeStretchBondState *state = assert_cast<MoleculeStretchBondState*>(_state.get());
176
177 // use given plane to undo
178 Box &domain = World::getInstance().getDomain();
179 for (size_t i=0;i<2;++i) {
180 for (BoostGraphHelpers::Nodeset_t::const_iterator iter = state->bondside_sets[i].begin();
181 iter != state->bondside_sets[i].end(); ++iter) {
182 atom &walker = *World::getInstance().getAtom(AtomById(*iter));
183 const Vector &position = walker.getPosition();
184 walker.setPosition( domain.enforceBoundaryConditions(position-state->Shift[i]) );
185 }
186 }
187
188 return ActionState::ptr(_state);
189}
190
191ActionState::ptr MoleculeStretchBondAction::performRedo(ActionState::ptr _state){
192 MoleculeStretchBondState *state = assert_cast<MoleculeStretchBondState*>(_state.get());
193
194 Box &domain = World::getInstance().getDomain();
195 for (size_t i=0;i<2;++i) {
196 for (BoostGraphHelpers::Nodeset_t::const_iterator iter = state->bondside_sets[i].begin();
197 iter != state->bondside_sets[i].end(); ++iter) {
198 atom &walker = *World::getInstance().getAtom(AtomById(*iter));
199 const Vector &position = walker.getPosition();
200 walker.setPosition( domain.enforceBoundaryConditions(position+state->Shift[i]) );
201 }
202 }
203
204 return ActionState::ptr(_state);
205}
206
207bool MoleculeStretchBondAction::canUndo() {
208 return true;
209}
210
211bool MoleculeStretchBondAction::shouldUndo() {
212 return true;
213}
214/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.