pegging.cpp
Go to the documentation of this file.
00001 /*************************************************************************** 00002 file : $URL: http://svn.code.sf.net/p/frepple/code/trunk/src/model/pegging.cpp $ 00003 version : $LastChangedRevision: 1713 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2012-07-18 11:46:01 +0200 (Wed, 18 Jul 2012) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007-2012 by Johan De Taeye, frePPLe bvba * 00010 * * 00011 * This library is free software; you can redistribute it and/or modify it * 00012 * under the terms of the GNU Affero General Public License as published * 00013 * by the Free Software Foundation; either version 3 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00019 * GNU Affero General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Affero General Public * 00022 * License along with this program. * 00023 * If not, see <http://www.gnu.org/licenses/>. * 00024 * * 00025 ***************************************************************************/ 00026 00027 #define FREPPLE_CORE 00028 #include "frepple/model.h" 00029 00030 namespace frepple 00031 { 00032 00033 DECLARE_EXPORT const MetaCategory* PeggingIterator::metadata; 00034 00035 00036 int PeggingIterator::initialize() 00037 { 00038 // Initialize the pegging metadata 00039 PeggingIterator::metadata = new MetaCategory("pegging","peggings"); 00040 00041 // Initialize the Python type 00042 PythonType& x = PythonExtension<PeggingIterator>::getType(); 00043 x.setName("peggingIterator"); 00044 x.setDoc("frePPLe iterator for demand pegging"); 00045 x.supportgetattro(); 00046 x.supportiter(); 00047 const_cast<MetaCategory*>(PeggingIterator::metadata)->pythonClass = x.type_object(); 00048 return x.typeReady(); 00049 } 00050 00051 00052 DECLARE_EXPORT PeggingIterator::PeggingIterator(const Demand* d) 00053 : downstream(false), firstIteration(true) 00054 { 00055 // Loop through all delivery operationplans 00056 first = false; // ... because the stack is still empty 00057 for (Demand::OperationPlan_list::const_iterator opplaniter = d->getDelivery().begin(); 00058 opplaniter != d->getDelivery().end(); ++opplaniter) 00059 followPegging(*opplaniter, 0, (*opplaniter)->getQuantity(), 1.0); 00060 00061 // Initialize Python type information 00062 initType(metadata); 00063 } 00064 00065 00066 DECLARE_EXPORT void PeggingIterator::updateStack 00067 (short l, double q, double f, const FlowPlan* fc, const FlowPlan* fp, bool p) 00068 { 00069 // Avoid very small pegging quantities 00070 if (q < 0.1) return; 00071 00072 if (first) 00073 { 00074 // We can update the current top element of the stack 00075 state& t = states.top(); 00076 t.cons_flowplan = fc; 00077 t.prod_flowplan = fp; 00078 t.qty = q; 00079 t.factor = f; 00080 t.level = l; 00081 t.pegged = p; 00082 first = false; 00083 } 00084 else 00085 // We need to create a new element on the stack 00086 states.push(state(l, q, f, fc, fp, p)); 00087 } 00088 00089 00090 DECLARE_EXPORT PeggingIterator& PeggingIterator::operator++() 00091 { 00092 // Validate 00093 if (states.empty()) 00094 throw LogicException("Incrementing the iterator beyond it's end"); 00095 if (!downstream) 00096 throw LogicException("Incrementing a downstream iterator"); 00097 state& st = states.top(); 00098 00099 // Handle unconsumed material entries on the stack 00100 if (!st.pegged) 00101 { 00102 states.pop(); 00103 return *this; 00104 } 00105 00106 // Mark the top entry in the stack as invalid, so it can be reused 00107 first = true; 00108 00109 // Take the consuming flowplan and follow the pegging 00110 if (st.cons_flowplan) 00111 followPegging(st.cons_flowplan->getOperationPlan()->getTopOwner(), 00112 st.level-1, st.qty, st.factor); 00113 00114 // Pop invalid entries from the stack 00115 if (first) states.pop(); 00116 00117 return *this; 00118 } 00119 00120 00121 DECLARE_EXPORT PeggingIterator& PeggingIterator::operator--() 00122 { 00123 // Validate 00124 if (states.empty()) 00125 throw LogicException("Incrementing the iterator beyond it's end"); 00126 if (downstream) 00127 throw LogicException("Decrementing an upstream iterator"); 00128 state& st = states.top(); 00129 00130 // Handle unconsumed material entries on the stack 00131 if (!st.pegged) 00132 { 00133 states.pop(); 00134 return *this; 00135 } 00136 00137 // Mark the top entry in the stack as invalid, so it can be reused 00138 first = true; 00139 00140 // Take the producing flowplan and follow the pegging 00141 if (st.prod_flowplan) 00142 followPegging(st.prod_flowplan->getOperationPlan()->getTopOwner(), 00143 st.level+1, st.qty, st.factor); 00144 00145 // Pop invalid entries from the stack 00146 if (first) states.pop(); 00147 00148 return *this; 00149 } 00150 00151 00152 DECLARE_EXPORT void PeggingIterator::followPegging 00153 (const OperationPlan* op, short nextlevel, double qty, double factor) 00154 { 00155 // For each flowplan (producing or consuming depending on whether we go 00156 // upstream or downstream) ask the buffer to give us the pegged flowplans. 00157 bool noFlowPlans = true; 00158 if (downstream) 00159 for (OperationPlan::FlowPlanIterator i = op->beginFlowPlans(); 00160 i != op->endFlowPlans(); ++i) 00161 { 00162 // We're interested in producing flowplans of an operationplan when 00163 // walking downstream. 00164 if (i->getQuantity()>ROUNDING_ERROR) 00165 { 00166 i->getFlow()->getBuffer()->followPegging(*this, &*i, nextlevel, qty, factor); 00167 noFlowPlans = false; 00168 } 00169 } 00170 else 00171 for (OperationPlan::FlowPlanIterator i = op->beginFlowPlans(); 00172 i != op->endFlowPlans(); ++i) 00173 { 00174 // We're interested in consuming flowplans of an operationplan when 00175 // walking upstream. 00176 if (i->getQuantity()<-ROUNDING_ERROR) 00177 { 00178 i->getFlow()->getBuffer()->followPegging(*this, &*i, nextlevel, qty, factor); 00179 noFlowPlans = false; 00180 } 00181 } 00182 00183 // Special case: the operationplan doesn't have flowplans 00184 // @todo if (noFlowPlans) updateStack(nextlevel, qty, factor, NULL, NULL); 00185 00186 // Recursively call this function for all sub-operationplans. 00187 for (OperationPlan::iterator j(op); j != OperationPlan::end(); ++j) 00188 followPegging(&*j, nextlevel, qty, factor); 00189 } 00190 00191 00192 DECLARE_EXPORT PyObject* PeggingIterator::iternext() 00193 { 00194 if (firstIteration) 00195 firstIteration = false; 00196 else 00197 operator--(); 00198 if (!operator bool()) return NULL; 00199 Py_INCREF(this); 00200 return static_cast<PyObject*>(this); 00201 } 00202 00203 00204 DECLARE_EXPORT PyObject* PeggingIterator::getattro(const Attribute& attr) 00205 { 00206 if (attr.isA(Tags::tag_level)) 00207 return PythonObject(getLevel()); 00208 if (attr.isA(Tags::tag_consuming)) 00209 return PythonObject(getConsumingOperationplan()); 00210 if (attr.isA(Tags::tag_producing)) 00211 return PythonObject(getProducingOperationplan()); 00212 if (attr.isA(Tags::tag_buffer)) 00213 return PythonObject(getBuffer()); 00214 if (attr.isA(Tags::tag_quantity_demand)) 00215 return PythonObject(getQuantityDemand()); 00216 if (attr.isA(Tags::tag_quantity_buffer)) 00217 return PythonObject(getQuantityBuffer()); 00218 if (attr.isA(Tags::tag_pegged)) 00219 return PythonObject(getPegged()); 00220 if (attr.isA(Tags::tag_consuming_date)) 00221 return PythonObject(getConsumingDate()); 00222 if (attr.isA(Tags::tag_producing_date)) 00223 return PythonObject(getProducingDate()); 00224 return NULL; 00225 } 00226 00227 00228 } // End namespace