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

Documentation generated for frePPLe by  doxygen