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