solver  1.0
RoboticLine.cpp
1 /*
2  This file is part of the EnergyOptimizatorOfRoboticCells program.
3 
4  EnergyOptimizatorOfRoboticCells is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  EnergyOptimizatorOfRoboticCells is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with EnergyOptimizatorOfRoboticCells. If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include <cmath>
19 #include <map>
20 #include <mutex>
21 #include <stdexcept>
22 #include <typeinfo>
23 #include "RoboticLine.h"
24 #include "SolverConfig.h"
25 #include "Shared/Utils.h"
26 #include "Shared/Exceptions.h"
28 
29 using namespace std;
30 
31 double Movement::energyConsumption(const double& duration) const {
32  assert(duration >= 0.0 && mMinDuration <= duration+TIME_ERR && duration <= mMaxDuration+TIME_ERR && "Invalid duration of the movement!");
33 
34  double consumption = 0.0;
35  for (const Monomial& m : mEnergyFunction)
36  consumption += m.coeff*pow(duration, m.degree);
37 
38  return consumption;
39 }
40 
42  double inputPower = 0.0;
43  if (m != nullptr)
44  inputPower = m->expectedInputPower();
45  else
46  throw InvalidArgument(caller(), "Malicious attempt to pass a null pointer as an argument!");
47 
48  for (const auto& ldpc : mLocationDependentPowerConsumption) {
49  if (ldpc.robotPowerMode() == m)
50  inputPower = ldpc.inputPower();
51  }
52 
53  return inputPower;
54 }
55 
56 double Location::energyConsumption(const double& duration, RobotPowerMode* m) const {
57  assert(duration >= 0.0 && m->minimalDelay() <= duration+TIME_ERR && mParent->minAbsDuration() <= duration+TIME_ERR && "Invalid duration for the location!");
58  return inputPower(m)*duration;
59 }
60 
61 void Location::parent(StaticActivity *parent) {
62  mParent = parent;
63  for (LocationDependentPowerConsumption& ldpc : mLocationDependentPowerConsumption)
64  ldpc.parent(this);
65 }
66 
67 Movement* DynamicActivity::findMovement(const uint32_t& mid) const {
68  for (Movement* mv : mMovements) {
69  if (mv->mid() == mid)
70  return mv;
71  }
72 
73  string msg = "Cannot find dynamic activity " + to_string(mAid) + "'s movement with 'mid=" + to_string(mid) + "'!";
74  throw InvalidArgument(caller(), msg);
75 }
76 
77 StaticActivity* DynamicActivity::cessor(const string& prefix) const {
78 
79  const vector<Activity*>& related = (prefix == "suc" ? mSuccessors : mPredecessors);
80 
81  if (related.size() == 1) {
82  StaticActivity *sa = dynamic_cast<StaticActivity*>(related.front());
83  if (sa != nullptr) {
84  return sa;
85  } else {
86  string msg = "The " + prefix + "cessor of the dynamic activity " + to_string(mAid) + " must be static activity!";
87  throw SolverException(caller(), msg);
88  }
89  } else {
90  string msg = "Dynamic activity " + to_string(mAid) + " must have exactly one " + prefix + "cessor!";
91  throw SolverException(caller(), msg);
92  }
93 }
94 
96  if (mPredecessors.size() == 1)
97  return (predecessor()->successors().size() == 1) ? true : false;
98  else
99  throw SolverException(caller(), "Predecessors were not set!");
100 }
101 
102 void DynamicActivity::parent(Robot *r) {
103  mParent = r;
104  for (Movement *mv : mMovements)
105  mv->parent(this);
106 }
107 
108 void DynamicActivity::freeAllocatedMemory() {
109  for (Movement *mv : mMovements)
110  delete mv;
111 }
112 
114  map<Location*, vector<Movement*> > enteringMovements, leavingMovements;
115  for (Activity *a : predecessors()) {
116  DynamicActivity *da = dynamic_cast<DynamicActivity*>(a);
117  if (da != nullptr) {
118  for (Movement *mv : da->movements())
119  enteringMovements[mv->to()].push_back(mv);
120  } else {
121  string pa = to_string(a->aid()), ca = to_string(aid());
122  string msg = "Static activity "+ca+"'s predecessor "+pa+" should be dynamic activity!";
123  throw SolverException(caller(), msg);
124  }
125  }
126 
127  for (Activity *a : successors()) {
128  DynamicActivity *da = dynamic_cast<DynamicActivity*>(a);
129  if (da != nullptr) {
130  for (Movement* mv : da->movements())
131  leavingMovements[mv->from()].push_back(mv);
132  } else {
133  string sa = to_string(a->aid()), ca = to_string(aid());
134  string msg = "Static activity "+ca+"'s successor "+sa+" should be dynamic activity!";
135  throw SolverException(caller(), msg);
136  }
137  }
138 
139  for (Location* loc : mLocations) {
140  auto ite = enteringMovements.find(loc);
141  auto itl = leavingMovements.find(loc);
142  if (ite != enteringMovements.cend() && itl != leavingMovements.cend()) {
143  vector<Movement*>& entMvs = ite->second, &leavMvs = itl->second;
144  // Sort movements for the fast search, do not remove!
145  sort(entMvs.begin(), entMvs.end());
146  sort(leavMvs.begin(), leavMvs.end());
147  loc->enteringMovements(entMvs);
148  loc->leavingMovements(leavMvs);
149  } else {
150  string ca = to_string(aid()), pt = to_string(loc->point());
151  string msg = "Static activity "+ca+" has isolated point "+pt+"!";
152  throw InvalidDatasetFile(caller(), msg);
153  }
154  }
155 }
156 
157 Location* StaticActivity::findLocation(const uint32_t& lid) const {
158  for (Location* l : mLocations) {
159  if (l->lid() == lid)
160  return l;
161  }
162 
163  string msg = "Cannot find static activity " + to_string(mAid) + "'s location with 'lid=" + to_string(lid) + "'!";
164  throw InvalidArgument(caller(), msg);
165 }
166 
167 double StaticActivity::inputPower(const uint32_t& lid, const uint32_t& pid) const {
168  assert(mParent != nullptr && "Pointers should be initialized by the InstancesReader class!");
169 
170  RobotPowerMode *mode = nullptr;
171  Location *loc = findLocation(lid);
172  const vector<RobotPowerMode*>& modes = mParent->powerModes();
173  auto sit = find_if(modes.cbegin(), modes.cend(), [&pid](RobotPowerMode* m) { return m->pid() == pid; });
174  if (sit != modes.cend())
175  mode = *sit;
176  else
177  throw InvalidArgument(caller(), "Invalid 'pid' argument!");
178 
179  return loc->inputPower(mode);
180 }
181 
182 double StaticActivity::energyConsumption(double duration, const uint32_t& lid, const uint32_t& pid) const {
183  assert(duration >= 0.0 && "Invalid duration value!");
184  return inputPower(lid, pid)*duration;
185 }
186 
187 void StaticActivity::parent(Robot *r) {
188  mParent = r;
189  for (Location* loc : mLocations)
190  loc->parent(this);
191 }
192 
193 void StaticActivity::freeAllocatedMemory() {
194  for (Location* loc : mLocations)
195  delete loc;
196 }
197 
199  RobotPowerMode* fastest = nullptr;
200  for (RobotPowerMode* pwrm : mRobotModes) {
201  if (fastest == nullptr || fastest->minimalDelay() > pwrm->minimalDelay())
202  fastest = pwrm;
203  }
204 
205  assert(fastest != nullptr && "Invalid data-structure! Each robot has to have some power saving modes!");
206 
207  return fastest;
208 }
209 
210 void Robot::parent(RoboticLine* parent) {
211  mParent = parent;
212  for (Activity *a : mActivities)
213  a->parent(this);
214  for (RobotPowerMode *m : mRobotModes)
215  m->parent(this);
216 }
217 
218 void Robot::setActivitiesRelations(const map<uint32_t, Location*>& pointToLocation, const map<Movement*, pair<uint32_t, uint32_t>>& movementToPoints) {
219  for (Activity* a : mActivities) {
220  DynamicActivity *da = dynamic_cast<DynamicActivity*>(a);
221  if (da != nullptr) {
222  StaticActivity *sa1 = nullptr, *sa2 = nullptr;
223  for (Movement* mv : da->movements()) {
224  const auto& points = getValue(movementToPoints, mv, caller());
225  uint32_t from = points.first, to = points.second;
226  auto fSit = pointToLocation.find(from), tSit = pointToLocation.find(to);
227  if (fSit == pointToLocation.cend() || tSit == pointToLocation.cend()) {
228  string msg = "Invalid movement "+to_string(mv->mid());
229  msg += " from point "+to_string(from)+" to point "+to_string(to)+"!";
230  msg += "\nThe point is not connected with the static activity!";
231  throw InvalidDatasetFile(caller(), msg);
232  }
233 
234  assert(fSit->second->parent() != nullptr && tSit->second->parent() != nullptr && "Should be set by XmlReader class!");
235  Activity* a1 = fSit->second->parent(), *a2 = tSit->second->parent();
236 
237  if (sa1 == nullptr || sa2 == nullptr) {
238  sa1 = dynamic_cast<StaticActivity*>(a1);
239  sa2 = dynamic_cast<StaticActivity*>(a2);
240  if (sa1 == nullptr || sa2 == nullptr) {
241  string msg = "Dynamic activity "+to_string(da->aid());
242  msg += " must be interconnected by two static activities!";
243  msg += "\nCheck type of activities "+to_string(a1->aid())+" and "+to_string(a2->aid())+".";
244  throw InvalidDatasetFile(caller(), msg);
245  }
246  } else {
247  if (sa1 != a1 || sa2 != a2) {
248  string msg = "Dynamic activity "+to_string(da->aid());
249  msg += " can interconnect only two static activities!";
250  throw InvalidDatasetFile(caller(), msg);
251  }
252  }
253 
254  mv->from(fSit->second);
255  mv->to(tSit->second);
256  }
257 
258  if (sa1 != nullptr && sa2 != nullptr) {
259  sa1->addSuccessor(da);
260  da->addPredecessor(sa1);
261  da->addSuccessor(sa2);
262  sa2->addPredecessor(da);
263  } else {
264  string msg = "There are no movements for the dynamic activity "+to_string(da->aid())+"!";
265  throw InvalidDatasetFile(caller(), msg);
266  }
267  }
268  }
269 
270  for (Activity *a : mActivities) {
271  StaticActivity *sa = dynamic_cast<StaticActivity*>(a);
272  if (sa != nullptr)
274  }
275 }
276 
277 void Robot::freeAllocatedMemory() {
278  for (Activity *a : mActivities) {
279  a->freeAllocatedMemory();
280  delete a;
281  }
282 
283  for (RobotPowerMode *m : mRobotModes)
284  delete m;
285 }
286 
287 mutex refCounterMutex;
288 map<int64_t*, set<RoboticLine*>> RoboticLine::liveInstances;
289 
290 RoboticLine::RoboticLine() : mRefCounter(new int64_t(1)), mProductionCycleTime(-1) {
291  refCounterMutex.lock();
292  liveInstances[mRefCounter].insert(this);
293  refCounterMutex.unlock();
294 }
295 
296 RoboticLine::RoboticLine(const RoboticLine& l) {
297  refCounterMutex.lock();
298  ++*l.mRefCounter;
299  liveInstances[l.mRefCounter].insert(this);
300  refCounterMutex.unlock();
301  copyDataStructures(l);
302 }
303 
304 RoboticLine& RoboticLine::operator=(const RoboticLine& l) {
305  if (this != &l) {
306  refCounterMutex.lock();
307  ++*l.mRefCounter;
308  liveInstances[mRefCounter].erase(this);
309  liveInstances[l.mRefCounter].insert(this);
310  freeAllocatedMemory();
311  refCounterMutex.unlock();
312  copyDataStructures(l);
313  }
314 
315  return *this;
316 }
317 
320  op->parent(rl);
321  for (Robot* r : mRobots)
322  r->parent(rl);
323 }
324 
325 void RoboticLine::initialiseDataStructures(const map<uint32_t, Location*>& pointToLocation, const map<Movement*, pair<uint32_t, uint32_t>>& movementToPoints) {
326  setParentOfChildren(this);
327  for (Robot* r : mRobots)
328  r->setActivitiesRelations(pointToLocation, movementToPoints);
329 }
330 
331 void RoboticLine::copyDataStructures(const RoboticLine& l) {
335 }
336 
337 RoboticLine::~RoboticLine() {
338  refCounterMutex.lock();
339  liveInstances[mRefCounter].erase(this);
340  freeAllocatedMemory();
341  refCounterMutex.unlock();
342 }
343 
344 void RoboticLine::freeAllocatedMemory() {
345  if (--*mRefCounter <= 0) {
346  for (Robot *r : mRobots) {
347  r->freeAllocatedMemory();
348  delete r;
349  }
350 
352  delete op;
353 
354  delete mRefCounter;
355  } else {
356  // Cannot free the memory, more references to the data still exists, reset parent to an existing robotic cell.
357  if (!liveInstances[mRefCounter].empty()) {
359  } else {
360  refCounterMutex.unlock();
361  throw SolverException(caller(), "Corrupted robotic cell data-structure, memory handling is invalid!");
362  }
363  }
364 }
365 
The instance of the class corresponds to a robot movement between two coordinates.
Definition: RoboticLine.h:133
double mProductionCycleTime
Production cycle time, also called robot cycle time.
Definition: RoboticLine.h:611
The base class incorporating common properties of robot operations and movements. ...
Definition: RoboticLine.h:68
The instance of this class specifies input power of the robot for a particular robot configuration an...
Definition: RoboticLine.h:403
double inputPower(RobotPowerMode *m) const
Definition: RoboticLine.cpp:41
std::vector< std::pair< ActivityMode *, ActivityMode * > > mCollisions
Collisions between robots defined as time disjunctive pairs.
Definition: RoboticLine.h:609
Instance of this class includes all the data structures and methods related to a robot.
Definition: RoboticLine.h:432
std::string mDescription
Description of the robotic cell.
Definition: RoboticLine.h:603
Collection of movements between two static activities.
Definition: RoboticLine.h:261
STL namespace.
A general exception of the program.
Definition: Exceptions.h:58
std::vector< Robot * > mRobots
Robots located in this cell.
Definition: RoboticLine.h:605
Various auxiliary functions used across the program.
void findMovementsForLocations()
Method assigns entering and leaving movements to each location in mLocations.
int64_t * mRefCounter
Counter of references, the number of shallow copies sharing the same data.
Definition: RoboticLine.h:599
Movement * findMovement(const uint32_t &mid) const
It finds a movement according to its identification.
Definition: RoboticLine.cpp:67
constexpr double TIME_ERR
Minimal recognizable difference in the time.
Thrown if the dataset file contains ill-specified robotic cells.
Definition: Exceptions.h:99
The file defines extended exceptions for the better error handling in the program.
std::vector< InterRobotOperation * > mInterRobotOperations
Inter-robot operations between robots.
Definition: RoboticLine.h:607
Exception is thrown if a method is given invalid parameters or a user provides invalid program argume...
Definition: Exceptions.h:120
Collection of locations in which a robot operation (or waiting) can be performed. ...
Definition: RoboticLine.h:304
static std::map< int64_t *, std::set< RoboticLine * > > liveInstances
Track of dynamically created instances, needed for managing the memory.
Definition: RoboticLine.h:614
A part of the energy function of a movement.
Definition: RoboticLine.h:125
double energyConsumption(double duration, const uint32_t &lid, const uint32_t &pid) const
It represents the power saving mode of the robot.
Definition: RoboticLine.h:359
std::string mName
Name of the robotic cell.
Definition: RoboticLine.h:601
StaticActivity * cessor(const std::string &prefix) const
Definition: RoboticLine.cpp:77
double inputPower(const uint32_t &lid, const uint32_t &pid) const
double energyConsumption(const double &duration) const
Definition: RoboticLine.cpp:31
Location * findLocation(const uint32_t &lid) const
It finds a location according to its identification.
The inter-robot operation corresponding to the workpiece/weldment handling.
Definition: RoboticLine.h:518
virtual bool mandatory() const
It returns whether this dynamic activity has to be performed.
Definition: RoboticLine.cpp:95
The file defines allowed inaccuracies in a solution and constants for floats.
void initialiseDataStructures(const std::map< uint32_t, Location * > &pointToLocation, const std::map< Movement *, std::pair< uint32_t, uint32_t >> &movementToPoints)
It recursively sets parents and initializes relations between activities.
void setActivitiesRelations(const std::map< uint32_t, Location * > &pointToLocation, const std::map< Movement *, std::pair< uint32_t, uint32_t >> &movementToPoints)
It initializes precedences between activities (successors, predecessors).
Location of the robot used either during work (welding) or waiting.
Definition: RoboticLine.h:192
The robotic cell corresponds to an instance of this class.
Definition: RoboticLine.h:563
RobotPowerMode * fastestPowerSavingMode() const
The power saving mode with the minimal time for an application is returned.
double energyConsumption(const double &duration, RobotPowerMode *m) const
Definition: RoboticLine.cpp:56
The file contains various classes devoted to abstract representation of the robotic cell...
void setParentOfChildren(RoboticLine *rl)
This method is propagated through all the parts of the robotic cell in order to set parents...