pegging.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * Copyright (C) 2007-2013 by Johan De Taeye, frePPLe bvba *
4  * *
5  * This library is free software; you can redistribute it and/or modify it *
6  * under the terms of the GNU Affero General Public License as published *
7  * by the Free Software Foundation; either version 3 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This library is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU Affero General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU Affero General Public *
16  * License along with this program. *
17  * If not, see <http://www.gnu.org/licenses/>. *
18  * *
19  ***************************************************************************/
20 
21 #define FREPPLE_CORE
22 #include "frepple/model.h"
23 
24 namespace frepple
25 {
26 
28 
29 
31 {
32  // Initialize the pegging metadata
33  PeggingIterator::metadata = new MetaCategory("pegging","peggings");
34 
35  // Initialize the Python type
37  x.setName("peggingIterator");
38  x.setDoc("frePPLe iterator for demand pegging");
39  x.supportgetattro();
40  x.supportiter();
41  const_cast<MetaCategory*>(PeggingIterator::metadata)->pythonClass = x.type_object();
42  return x.typeReady();
43 }
44 
45 
47  : downstream(false), firstIteration(true)
48 {
49  // Loop through all delivery operationplans
50  first = false; // ... because the stack is still empty
51  for (Demand::OperationPlan_list::const_iterator opplaniter = d->getDelivery().begin();
52  opplaniter != d->getDelivery().end(); ++opplaniter)
53  followPegging(*opplaniter, 0, (*opplaniter)->getQuantity(), 1.0);
54 
55  // Initialize Python type information
57 }
58 
59 
61  : downstream(b), firstIteration(true)
62 {
63  first = false; // ... because the stack is still empty
64  followPegging(opplan, 0, opplan->getQuantity(), 1.0);
66 }
67 
68 
70 (short l, double q, double f, const FlowPlan* fc, const FlowPlan* fp, bool p)
71 {
72  // Avoid very small pegging quantities
73  if (q < 0.1) return;
74 
75  if (first)
76  {
77  // We can update the current top element of the stack
78  state& t = states.top();
79  t.cons_flowplan = fc;
80  t.prod_flowplan = fp;
81  t.qty = q;
82  t.factor = f;
83  t.level = l;
84  t.pegged = p;
85  first = false;
86  }
87  else
88  // We need to create a new element on the stack
89  states.push(state(l, q, f, fc, fp, p));
90 }
91 
92 
94 {
95  // Validate
96  if (states.empty())
97  throw LogicException("Incrementing the iterator beyond it's end");
98  if (!downstream)
99  throw LogicException("Incrementing a downstream iterator");
100  state& st = states.top();
101 
102  // Handle unconsumed material entries on the stack
103  if (!st.pegged)
104  {
105  states.pop();
106  return *this;
107  }
108 
109  // Mark the top entry in the stack as invalid, so it can be reused
110  first = true;
111 
112  // Take the consuming flowplan and follow the pegging
113  if (st.cons_flowplan)
114  followPegging(st.cons_flowplan->getOperationPlan()->getTopOwner(),
115  st.level-1, st.qty, st.factor);
116 
117  // Pop invalid entries from the stack
118  if (first) states.pop();
119 
120  return *this;
121 }
122 
123 
125 {
126  // Validate
127  if (states.empty())
128  throw LogicException("Incrementing the iterator beyond it's end");
129  if (downstream)
130  throw LogicException("Decrementing an upstream iterator");
131  state& st = states.top();
132 
133  // Handle unconsumed material entries on the stack
134  if (!st.pegged)
135  {
136  states.pop();
137  return *this;
138  }
139 
140  // Mark the top entry in the stack as invalid, so it can be reused
141  first = true;
142 
143  // Take the producing flowplan and follow the pegging
144  if (st.prod_flowplan)
145  followPegging(st.prod_flowplan->getOperationPlan()->getTopOwner(),
146  st.level+1, st.qty, st.factor);
147 
148  // Pop invalid entries from the stack
149  if (first) states.pop();
150 
151  return *this;
152 }
153 
154 
155 DECLARE_EXPORT void PeggingIterator::followPegging
156 (const OperationPlan* op, short nextlevel, double qty, double factor)
157 {
158  // For each flowplan (producing or consuming depending on whether we go
159  // upstream or downstream) ask the buffer to give us the pegged flowplans.
160  bool noFlowPlans = true;
161  if (downstream)
163  i != op->endFlowPlans(); ++i)
164  {
165  // We're interested in producing flowplans of an operationplan when
166  // walking downstream.
167  if (i->getQuantity()>ROUNDING_ERROR)
168  {
169  i->getFlow()->getBuffer()->followPegging(*this, &*i, nextlevel, qty, factor);
170  noFlowPlans = false;
171  }
172  }
173  else
174  for (OperationPlan::FlowPlanIterator i = op->beginFlowPlans();
175  i != op->endFlowPlans(); ++i)
176  {
177  // We're interested in consuming flowplans of an operationplan when
178  // walking upstream.
179  if (i->getQuantity()<-ROUNDING_ERROR)
180  {
181  i->getFlow()->getBuffer()->followPegging(*this, &*i, nextlevel, qty, factor);
182  noFlowPlans = false;
183  }
184  }
185 
186  // Special case: the operationplan doesn't have flowplans
187  // @todo if (noFlowPlans) updateStack(nextlevel, qty, factor, NULL, NULL);
188 
189  // Recursively call this function for all sub-operationplans.
190  for (OperationPlan::iterator j(op); j != OperationPlan::end(); ++j)
191  followPegging(&*j, nextlevel, qty, factor);
192 }
193 
194 
195 DECLARE_EXPORT PyObject* PeggingIterator::iternext()
196 {
197  if (firstIteration)
198  firstIteration = false;
199  else
200  operator--();
201  if (!operator bool()) return NULL;
202  Py_INCREF(this);
203  return static_cast<PyObject*>(this);
204 }
205 
206 
207 DECLARE_EXPORT PyObject* PeggingIterator::getattro(const Attribute& attr)
208 {
209  if (attr.isA(Tags::tag_level))
210  return PythonObject(getLevel());
211  if (attr.isA(Tags::tag_consuming))
213  if (attr.isA(Tags::tag_producing))
215  if (attr.isA(Tags::tag_buffer))
216  return PythonObject(getBuffer());
217  if (attr.isA(Tags::tag_quantity_demand))
219  if (attr.isA(Tags::tag_quantity_buffer))
221  if (attr.isA(Tags::tag_pegged))
222  return PythonObject(getPegged());
223  if (attr.isA(Tags::tag_consuming_date))
224  return PythonObject(getConsumingDate());
225  if (attr.isA(Tags::tag_producing_date))
226  return PythonObject(getProducingDate());
227  return NULL;
228 }
229 
230 
231 } // End namespace