Simpatico  v1.10
LinkMaster.cpp
1 #ifdef MCMD_LINK
2 /*
3 * Simpatico - Simulation Package for Polymeric and Molecular Liquids
4 *
5 * Copyright 2010 - 2017, Veronica Chappa and The Regents of the University of Minnesota
6 * Distributed under the terms of the GNU General Public License.
7 */
8 
9 #include "LinkMaster.h"
10 #include <util/misc/Observer.h>
11 #include <util/random/Random.h>
12 
13 namespace McMd
14 {
15 
16  using namespace Util;
17 
18  /*
19  * Constructor.
20  */
22  : linkCapacity_(0),
23  atomCapacity_(0)
24  { setClassName("LinkMaster"); }
25 
29  void LinkMaster::readParameters(std::istream& in)
30  {
31  read<int>(in, "linkCapacity", linkCapacity_);
32  read<int>(in, "atomCapacity", atomCapacity_);
33  allocate();
34  }
35 
39  void LinkMaster::addLink(Atom& atom0, Atom& atom1, int typeId)
40  {
41  Link* linkPtr;
42  int atom0Id = atom0.id();
43  int atom1Id = atom1.id();
44 
45  // Check preconditions
46  if (atom0Id < 0 || atom0Id >= atomCapacity_) {
47  Log::file() << "Atom0Id = " << atom0Id << std::endl;
48  Log::file() << "atomCapacity = " << atomCapacity_ << std::endl;
49  UTIL_THROW("Invalid atom0 id");
50  }
51  if (atom1Id < 0 || atom1Id >= atomCapacity_) {
52  Log::file() << "Atom1Id = " << atom1Id << std::endl;
53  Log::file() << "atomCapacity = " << atomCapacity_ << std::endl;
54  UTIL_THROW("Invalid atom1 id");
55  }
56 
57  // Pop an unused Link off the reservoir
58  linkPtr = &reservoir_.pop();
59  linkSet_.append(*linkPtr);
60 
61  // Initialize the link, and add its address to linkPtrs_[atomId]
62  linkPtr->setAtoms(atom0,atom1);
63  linkPtr->setTypeId(typeId);
64  linkPtr->setIsActive(true);
65  atomLinkSets_[atom0Id].append(*linkPtr);
66  atomLinkSets_[atom1Id].append(*linkPtr);
67 
68  // Notify observers of addition of this Link.
69  LinkAddEvent event(linkPtr);
71  }
72 
73 
78  {
79  Link* linkPtr = &link(id);
80  int atom0Id;
81  int atom1Id;
82 
83  if (!link(id).isActive()) {
84  UTIL_THROW("Attempt to remove a nonactive link");
85  }
86  atom0Id = linkPtr->atom0().id();
87  atom1Id = linkPtr->atom1().id();
88  // Remove link from atom0 and atom1 link sets
89  if (!atomLinkSets_[atom0Id].isElement(*linkPtr)) {
90  UTIL_THROW("Link is not in atomLinkSets of atom0");
91  }
92  if (!atomLinkSets_[atom1Id].isElement(*linkPtr)) {
93  UTIL_THROW("Link is not in atomLinkSets of atom1");
94  }
95  atomLinkSets_[atom0Id].remove(*linkPtr);
96  atomLinkSets_[atom1Id].remove(*linkPtr);
97 
98  // Notify observers of removal of this Link.
99  // Notify before clearing Link so atomPtrs and typeId are available.
100  LinkRemoveEvent event(linkPtr);
102 
103  // Clear the link: nullify atomPtrs, set typeId = -1, isActive = false
104  linkPtr->clear();
105 
106  // Return link to reservoir
107  linkSet_.remove(*linkPtr);
108  reservoir_.push(*linkPtr);
109 
110  }
111 
112  /*
113  * Modify the atoms attached to a link
114  */
115  void LinkMaster::reSetAtoms(Link& link, Atom& atom0, Atom& atom1)
116  {
117  int atom0Id = atom0.id();
118  int atom1Id = atom1.id();
119  int oldAtom0Id = link.atom0().id();
120  int oldAtom1Id = link.atom1().id();
121 
122  // Check preconditions
123  if (!link.isActive()) {
124  UTIL_THROW("Attempt to reset atoms for a nonactive link");
125  }
126  if (atom0Id < 0 || atom0Id >= atomCapacity_) {
127  Log::file() << "Atom0Id = " << atom0Id << std::endl;
128  Log::file() << "atomCapacity = " << atomCapacity_ << std::endl;
129  UTIL_THROW("Invalid atom0 id");
130  }
131  if (atom1Id < 0 || atom1Id >= atomCapacity_) {
132  Log::file() << "Atom1Id = " << atom1Id << std::endl;
133  Log::file() << "atomCapacity = " << atomCapacity_ << std::endl;
134  UTIL_THROW("Invalid atom1 id");
135  }
136 
137  // Remove link from oldAtom0 and oldAtom1 link sets
138  if (!atomLinkSets_[oldAtom0Id].isElement(link)) {
139  UTIL_THROW("Link is not in atomLinkSets of atom0");
140  }
141  if (!atomLinkSets_[oldAtom1Id].isElement(link)) {
142  UTIL_THROW("Link is not in atomLinkSets of atom1");
143  }
144  atomLinkSets_[oldAtom0Id].remove(link);
145  atomLinkSets_[oldAtom1Id].remove(link);
146 
147  // Change the atoms
148  link.setAtoms(atom0,atom1);
149  atomLinkSets_[atom0Id].append(link);
150  atomLinkSets_[atom1Id].append(link);
151 
152  LinkResetEvent event(&link);
154 
155  }
156 
157  /*
158  * Modify one atom attached to a link
159  */
160  void LinkMaster::reSetAtom(Link& link, Atom& atom, int endId)
161  {
162  int atomId = atom.id();
163  int oldAtomId;
164 
165  if (endId==0){
166  oldAtomId = link.atom0().id();
167  }
168  else {
169  oldAtomId = link.atom1().id();
170  }
171 
172  // Check preconditions
173  if (!link.isActive()) {
174  UTIL_THROW("Attempt to reset an atom for a nonactive link");
175  }
176  if (atomId < 0 || atomId >= atomCapacity_) {
177  Log::file() << "AtomId = " << atomId << std::endl;
178  Log::file() << "atomCapacity = " << atomCapacity_ << std::endl;
179  UTIL_THROW("Invalid atom id");
180  }
181 
182  // Remove link from oldAtom link sets
183  if (!atomLinkSets_[oldAtomId].isElement(link)) {
184  UTIL_THROW("Link is not in atomLinkSets of atom");
185  }
186  atomLinkSets_[oldAtomId].remove(link);
187 
188  // Change the atom
189  if (endId==0){
190  link.setAtoms(atom,link.atom1());
191  }
192  else {
193  link.setAtoms(link.atom0(),atom);
194  }
195  atomLinkSets_[atomId].append(link);
196 
197  ReSetAtomEvent event(&link, endId);
199 
200  }
201 
202  /*
203  * Get a randomly chosen link of a specified Species.
204  */
206  {
207  int n = nLink();
208  if (n <= 0) {
209  UTIL_THROW("Number of links in species <= 0");
210  }
211  int id = random.uniformInt(0, n);
212  return linkSet_[id];
213  }
214 
215 
219  void LinkMaster::allocate()
220  {
221 
222  links_.allocate(linkCapacity_);
223  reservoir_.allocate(linkCapacity_);
224  linkSet_.allocate(links_);
225 
226  // Set tags for all Links.
227  for (int i = 0; i < linkCapacity_; ++i) {
228  links_[i].setTag(i);
229  }
230 
231  // Push all links onto reservoir stack, in reverse order.
232  // The first element links_[0] wll be at the top of stack.
233  int i;
234  for (i = linkCapacity_ - 1; i >= 0; --i) {
235  reservoir_.push(links_[i]);
236  }
237 
238  // Allocate array of pointers to links.
239  atomLinkSets_.allocate(atomCapacity_);
240  }
241 
242  /*
243  * Return true if this LinkMaster is valid, or throw an Exception.
244  */
245  bool LinkMaster::isValid() const
246  {
247 
248  if (links_.isAllocated()) {
249 
250  if (links_.capacity() != reservoir_.capacity()) {
251  UTIL_THROW("Unequal capacities for links_ and reservoir_");
252  }
253  if (links_.capacity() != reservoir_.size() + linkSet_.size()) {
254  UTIL_THROW("links_ capacity != reservoir_ + linkSet_ sizes");
255  }
256 
257  // Check consistency of all links in linkSet
258  const Link* linkPtr;
259  const Atom* atom0Ptr;
260  const Atom* atom1Ptr;
261  int i;
262  for (i = 0; i < linkSet_.size(); ++i) {
263 
264  linkPtr = &(linkSet_[i]);
265  atom0Ptr = &(linkPtr->atom0());
266  atom1Ptr = &(linkPtr->atom1());
267 
268  // Check:
269 
270  // that neither atom0Ptr nor atom1Ptr is null
271  if (atom0Ptr == 0 || atom1Ptr == 0) {
272  UTIL_THROW("Link with one or both atoms missing");
273  }
274 
275  // that atom0Ptr and atom1Ptr are distinct
276  if (atom0Ptr == atom1Ptr) {
277  UTIL_THROW("Link connects an atom to itself");
278  }
279 
280  // that the link is active
281  if (!linkPtr->isActive()) {
282  UTIL_THROW("Link in linkSet is not Active");
283  }
284 
285  // that the Link is in the AtomLinkSet of atom0 and of atom1
286  if (!atomLinkSets_[atom0Ptr->id()].isElement(*linkPtr)) {
287  UTIL_THROW("Link is not in atomLinkSets of atom0");
288  }
289  if (!atomLinkSets_[atom1Ptr->id()].isElement(*linkPtr)) {
290  UTIL_THROW("Link is not in atomLinkSets of atom1");
291  }
292 
293  }
294 
295  // Count all active links in links_ array
296  int nCount = 0;
297  for (i = 0; i < linkCapacity_; ++i) {
298  linkPtr = &links_[i];
299  if (linkPtr->isActive()) {
300  ++nCount;
301  }
302  }
303  if (nCount != linkSet_.size()) {
304  UTIL_THROW("Number of Links with atoms != linkSet.size()");
305  }
306 
307  // Count all links int AtomLinkSets_ (each appears twice)
308  nCount = 0;
309  for (i = 0; i < atomCapacity_; ++i) {
310  nCount += atomLinkSets_[i].size();
311  }
312  if (nCount != 2*linkSet_.size()) {
313  UTIL_THROW("Number links in atom sets != 2*linkSet.size()");
314  }
315 
316  }
317 
318  return true;
319  }
320 
325  {
326  for (int id = nLink()-1; id >= 0; id--) {
327  removeLink(id);
328  }
329  }
330 
331 }
332 #endif
int nLink() const
Get the total number of active Links.
Definition: LinkMaster.h:261
void notifyObservers(const Event &event)
Notify the list of observers about an Event.
Definition: Notifier.h:98
void removeLink(int id)
Remove a Link.
Definition: LinkMaster.cpp:77
Event signalling the reset of an atom from the LinkMaster.
Definition: LinkEvents.h:105
void reSetAtoms(Link &link, Atom &atom0, Atom &atom1)
Modify the atoms attached to a link.
Definition: LinkMaster.cpp:115
Event signalling removal of a Link from the LinkMaster.
Definition: LinkEvents.h:78
bool isActive() const
Is this parameter active?
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
LinkMaster()
Constructor.
Definition: LinkMaster.cpp:21
A point particle within a Molecule.
Utility classes for scientific computation.
Definition: accumulators.mod:1
void clear()
Clear LinkMaster.
Definition: LinkMaster.cpp:324
int id() const
Get global index for this Atom within the Simulation.
long uniformInt(long range1, long range2)
Return random long int x uniformly distributed in range1 <= x < range2.
Definition: Random.h:224
void reSetAtom(Link &link, Atom &atom, int endId)
Modify one atom attached to a link.
Definition: LinkMaster.cpp:160
Event signalling addition of Link to the LinkMaster.
Definition: LinkEvents.h:20
static std::ostream & file()
Get log ostream by reference.
Definition: Log.cpp:57
Single-processor Monte Carlo (MC) and molecular dynamics (MD).
void setClassName(const char *className)
Set class name string.
bool isValid() const
Return true if this LinkMaster is valid, or throw an Exception.
Definition: LinkMaster.cpp:245
Link & link(int id) const
Return an active link by an internal set index.
Definition: LinkMaster.h:255
Link & randomLink(Random &random)
Get a randomly chosen link by reference.
Definition: LinkMaster.cpp:205
Event signalling reset of Link to the LinkMaster.
Definition: LinkEvents.h:49
Random number generator.
Definition: Random.h:46
void addLink(Atom &atom0, Atom &atom1, int typeId)
Add a link betwen two specific Atoms.
Definition: LinkMaster.cpp:39
void readParameters(std::istream &in)
Read linkCapacity and allocate.
Definition: LinkMaster.cpp:29