source: src/Actions/AtomAction/SaturateAction.cpp@ e0e77e

Candidate_v1.7.0 stable
Last change on this file since e0e77e was 2390e6, checked in by Frederik Heber <frederik.heber@…>, 5 years ago

SaturateAction may use outer shell information.

  • when considering the outer shell, then we look at both occupied and unoccupied orbitals. The ideal polygon will be created for the number of all orbitals, but only the unoccupied will be allowed to be taken by either present bonds or saturation hydrogens.
  • SphericalPointDistribution allows to occupy less than present points.
  • I have tested this manually by adding oxygen, saturation, adding carbon, saturating again, then turning oxygen into nitrogen and saturating. Results were always exactly as hoped for.
  • DOCU: Added note to action in userguide.
  • Property mode set to 100644
File size: 6.8 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2015 Frederik Heber. 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 * SaturateAction.cpp
25 *
26 * Created on: Jan 26, 2015
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 "CodePatterns/Log.hpp"
38
39#include "Actions/AtomAction/SaturateAction.hpp"
40#include "Actions/UndoRedoHelpers.hpp"
41#include "Atom/atom.hpp"
42#include "Atom/AtomicInfo.hpp"
43#include "Element/element.hpp"
44#include "Element/periodentafel.hpp"
45#include "Fragmentation/Exporters/SphericalPointDistribution.hpp"
46#include "molecule.hpp"
47#include "World.hpp"
48#include "WorldTime.hpp"
49
50using namespace MoleCuilder;
51
52// and construct the stuff
53#include "SaturateAction.def"
54#include "Action_impl_pre.hpp"
55/** =========== define the function ====================== */
56ActionState::ptr AtomSaturateAction::performCall() {
57
58 // get hydrogen element
59 const element * const hydrogen = World::getInstance().getPeriode()->FindElement(1);
60
61 // go through each atom
62 std::vector<AtomicInfo> addedHydrogens;
63 World &world = World::getInstance();
64 for (World::AtomSelectionIterator iter = world.beginAtomSelection();
65 iter != world.endAtomSelection(); ++iter) {
66 atom * const _atom = iter->second;
67
68 // if atom is attached to molecule, add hydrogens there, too
69 molecule * mol = NULL;
70 if (_atom->getMolecule() == NULL) {
71 mol = World::getInstance().createMolecule();
72 mol->AddAtom(_atom);
73 } else {
74 mol = World::getInstance().getMolecule(MoleculeById(_atom->getMolecule()->getId()));
75 }
76 ASSERT( mol != NULL,
77 "AtomSaturateAction::performCall() - mol is still NULL." );
78
79 // radius of polygon on sphere
80 double typical_distance = _atom->getType()->getHBondDistance(0);
81 if (typical_distance == -1.)
82 typical_distance = 1.;
83
84 // check for any bonds and get vacant positions
85 SphericalPointDistribution::Polygon_t vacant_positions;
86 const BondList& ListOfBonds = _atom->getListOfBonds();
87 SphericalPointDistribution PointSphere(typical_distance);
88 int num_orbitals_outer_shell;
89 int num_unoccupied_orbitals;
90 if (params.useOuterShell.get()) {
91 /*
92 * Number of valence electrons (getValence()) + number of unoccupied
93 * orbitals (getNoValenceOrbitals()) is the number of electrons able
94 * to fit into the outer shell. Hence, half the number gives the number
95 * of orbitals in the outer shell
96 */
97 num_orbitals_outer_shell =
98 (((int)_atom->getType()->getValence())+_atom->getType()->getNoValenceOrbitals())/2;
99 num_unoccupied_orbitals = _atom->getType()->getNoValenceOrbitals();
100 } else {
101 /**
102 * Here, same number of points on the polyhedra and available ones.
103 */
104 num_orbitals_outer_shell = num_unoccupied_orbitals = _atom->getType()->getNoValenceOrbitals();
105 }
106 if (ListOfBonds.size() == 0) {
107 vacant_positions = PointSphere.getSimplePolygon(num_orbitals_outer_shell);
108
109 // if less available then present in the ideal polygon, remove some
110 if (num_unoccupied_orbitals < vacant_positions.size())
111 vacant_positions.resize(num_unoccupied_orbitals);
112
113 LOG(3, "DEBUG: Using ideal positions as " << vacant_positions);
114 } else {
115 SphericalPointDistribution::WeightedPolygon_t current_positions;
116 for (BondList::const_iterator bonditer = ListOfBonds.begin();
117 bonditer != ListOfBonds.end(); ++bonditer) {
118 const Vector position =
119 (*bonditer)->GetOtherAtom(_atom)->getPosition().getVectorToPoint(_atom->getPosition());
120 current_positions.push_back(
121 std::make_pair( (1./position.Norm())*position, (*bonditer)->getDegree() ));
122 }
123 LOG(3, "DEBUG: current occupied positions are " << current_positions);
124
125 // get ideal polygon and currently occupied positions
126 const SphericalPointDistribution::Polygon_t ideal_positions =
127 PointSphere.getSimplePolygon(num_orbitals_outer_shell);
128 LOG(3, "DEBUG: ideal positions are " << ideal_positions);
129
130 // find the best matching rotated polygon
131 vacant_positions = PointSphere.getRemainingPoints(
132 current_positions,
133 num_orbitals_outer_shell,
134 num_unoccupied_orbitals);
135 LOG(3, "DEBUG: Resulting vacant positions are " << vacant_positions);
136
137 // scale vacant positions to typical_distance
138 std::for_each(
139 vacant_positions.begin(), vacant_positions.end(),
140 boost::bind(&Vector::Scale, _1, boost::cref(typical_distance)));
141 LOG(3, "DEBUG: Rescaled vacant positions are " << vacant_positions);
142 }
143
144 // add the hydrogens
145 const Vector AtomsPosition = _atom->getPosition();
146 for (SphericalPointDistribution::Polygon_t::const_iterator iter = vacant_positions.begin();
147 iter != vacant_positions.end(); ++iter) {
148 // for every Vector add a point relative to atom's position
149 atom * hydrogenAtom = World::getInstance().createAtom();
150 hydrogenAtom->setType(hydrogen);
151 hydrogenAtom->setPosition(AtomsPosition + *iter);
152 mol->AddAtom(hydrogenAtom);
153 // add bond
154 _atom->addBond(WorldTime::getTime(), hydrogenAtom);
155 // mark down for undo state
156 addedHydrogens.push_back(AtomicInfo(*(hydrogenAtom)));
157 }
158 }
159
160 return ActionState::ptr(new AtomSaturateState(addedHydrogens, params));
161}
162
163ActionState::ptr AtomSaturateAction::performUndo(ActionState::ptr _state) {
164 AtomSaturateState *state = assert_cast<AtomSaturateState*>(_state.get());
165
166 // remove all added hydrogen atoms
167 RemoveAtomsFromAtomicInfo(state->addedHydrogens);
168
169 return ActionState::ptr(_state);
170}
171
172ActionState::ptr AtomSaturateAction::performRedo(ActionState::ptr _state){
173 AtomSaturateState *state = assert_cast<AtomSaturateState*>(_state.get());
174
175 // re-add all added hydrogen atoms
176 AddAtomsFromAtomicInfo(state->addedHydrogens);
177
178 return ActionState::ptr(_state);
179}
180
181bool AtomSaturateAction::canUndo() {
182 return true;
183}
184
185bool AtomSaturateAction::shouldUndo() {
186 return true;
187}
188/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.