loadplan.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.8.0/src/model/loadplan.cpp $
00003   version : $LastChangedRevision: 1176 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2010-02-14 22:27:13 +0100 (Sun, 14 Feb 2010) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007 by Johan De Taeye                                    *
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* LoadPlan::metadata;
00035 
00036 
00037 int LoadPlan::initialize()
00038 {
00039   // Initialize the metadata
00040   metadata = new MetaCategory("loadplan", "loadplans");
00041 
00042   // Initialize the Python type
00043   PythonType& x = FreppleCategory<LoadPlan>::getType();
00044   x.setName("loadplan");
00045   x.setDoc("frePPLe loadplan");
00046   x.supportgetattro();
00047   const_cast<MetaCategory*>(metadata)->pythonClass = x.type_object();
00048   return x.typeReady();
00049 }
00050 
00051 
00052 DECLARE_EXPORT LoadPlan::LoadPlan(OperationPlan *o, const Load *r)
00053 {
00054   assert(o);
00055   ld = const_cast<Load*>(r);
00056   oper = o;
00057   start_or_end = START;
00058 
00059   // Add to the operationplan
00060   nextLoadPlan = NULL;
00061   if (o->firstloadplan)
00062   {
00063     // Append to the end
00064     LoadPlan *c = o->firstloadplan;
00065     while (c->nextLoadPlan) c = c->nextLoadPlan;
00066     c->nextLoadPlan = this;
00067   }
00068   else
00069     // First in the list
00070     o->firstloadplan = this;
00071 
00072   // Insert in the resource timeline
00073   r->getResource()->loadplans.insert(
00074     this,
00075     ld->getLoadplanQuantity(this),
00076     ld->getLoadplanDate(this)
00077     );
00078 
00079   // Initialize the Python type
00080   initType(metadata);
00081 
00082   // Create a loadplan to mark the end of the operationplan.
00083   new LoadPlan(o, r, this);
00084 
00085   // Mark the operation and resource as being changed. This will trigger
00086   // the recomputation of their problems
00087   r->getResource()->setChanged();
00088   r->getOperation()->setChanged();
00089 }
00090 
00091 
00092 DECLARE_EXPORT LoadPlan::LoadPlan(OperationPlan *o, const Load *r, LoadPlan *lp)
00093 {
00094   ld = const_cast<Load*>(r);
00095   oper = o;
00096   start_or_end = END;
00097 
00098   // Add to the operationplan
00099   nextLoadPlan = NULL;
00100   if (o->firstloadplan)
00101   {
00102     // Append to the end
00103     LoadPlan *c = o->firstloadplan;
00104     while (c->nextLoadPlan) c = c->nextLoadPlan;
00105     c->nextLoadPlan = this;
00106   }
00107   else
00108     // First in the list
00109     o->firstloadplan = this;
00110 
00111   // Insert in the resource timeline
00112   r->getResource()->loadplans.insert(
00113     this,
00114     ld->getLoadplanQuantity(this),
00115     ld->getLoadplanDate(this)
00116     );
00117 
00118   // Initialize the Python type
00119   initType(metadata);
00120 }
00121 
00122 
00123 DECLARE_EXPORT LoadPlan* LoadPlan::getOtherLoadPlan() const
00124 {
00125   for (LoadPlan *i = oper->firstloadplan; i; i = i->nextLoadPlan)
00126     if (i->ld == ld && i != this) return i;
00127   throw LogicException("No matching loadplan found");
00128 }
00129 
00130 
00131 DECLARE_EXPORT void LoadPlan::update()
00132 {
00133   // Update the timeline data structure
00134   ld->getResource()->getLoadPlans().update(
00135     this,
00136     ld->getLoadplanQuantity(this),
00137     ld->getLoadplanDate(this)
00138     );
00139 
00140   // Review adjacent setups
00141   if (!isStart()) ld->getResource()->updateSetups(this);
00142 
00143   // Mark the operation and resource as being changed. This will trigger
00144   // the recomputation of their problems
00145   ld->getResource()->setChanged();
00146   ld->getOperation()->setChanged();
00147 }
00148 
00149 
00150 DECLARE_EXPORT const string& LoadPlan::getSetup(bool current) const
00151 {
00152   // This resource has no setupmatrix
00153   static string nosetup;
00154   assert(ld);
00155   if (!ld->getResource()->getSetupMatrix()) return nosetup;
00156 
00157   // Current load has a setup
00158   if (!ld->getSetup().empty() && current) return ld->getSetup();
00159 
00160   // Scan earlier setups
00161   for (Resource::loadplanlist::const_iterator i(this); 
00162     i != getResource()->getLoadPlans().end(); --i)
00163   {
00164     const LoadPlan* j = dynamic_cast<const LoadPlan*>(&*i);
00165     if (j && !j->getLoad()->getSetup().empty() && (current || j != this))
00166       return j->getLoad()->getSetup();
00167   }
00168 
00169   // No conversions found - return the original setup
00170   return ld->getResource()->getSetup();
00171 }
00172 
00173 
00174 DECLARE_EXPORT LoadPlan::~LoadPlan()
00175 {
00176   ld->getResource()->setChanged();
00177   LoadPlan *prevldplan = NULL;
00178   if (!isStart() && oper->getOperation() == OperationSetup::setupoperation)
00179   {
00180     for (TimeLine<LoadPlan>::const_iterator i = getResource()->getLoadPlans().begin(isStart() ? getOtherLoadPlan() : this);
00181       i != getResource()->getLoadPlans().end(); --i)
00182     {
00183       const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
00184       if (l && l->getOperationPlan() != getOperationPlan()
00185         && l->getOperationPlan() != getOperationPlan()->getOwner()
00186         && !l->isStart())
00187       {
00188         prevldplan = const_cast<LoadPlan*>(l);
00189         break;
00190       }
00191     }
00192     if (!prevldplan)
00193     {
00194       for (TimeLine<LoadPlan>::const_iterator i = getResource()->getLoadPlans().begin(isStart() ? getOtherLoadPlan() : this);
00195         i != getResource()->getLoadPlans().end(); ++i)
00196       {
00197         const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
00198         if (l && l->getOperationPlan() != getOperationPlan()
00199           && l->getOperationPlan() != getOperationPlan()->getOwner()
00200           && !l->isStart())
00201         {
00202           prevldplan = const_cast<LoadPlan*>(l);
00203           break;
00204         }
00205       }
00206     }    
00207   }
00208   ld->getResource()->loadplans.erase(this);
00209   if (prevldplan) ld->getResource()->updateSetups(prevldplan); 
00210 }
00211 
00212 
00213 DECLARE_EXPORT void LoadPlan::setLoad(const Load* newld)
00214 {
00215   // No change
00216   if (newld == ld) return;
00217 
00218   // Verify the data
00219   if (!newld) throw LogicException("Can't switch to NULL load");
00220   if (ld && ld->getOperation() != newld->getOperation())
00221     throw LogicException("Only switching to a load on the same operation is allowed");
00222 
00223   // Mark entities as changed
00224   if (oper) oper->getOperation()->setChanged();
00225   if (ld) ld->getResource()->setChanged();
00226   newld->getResource()->setChanged();
00227 
00228   // Update also the setup operationplan
00229   if (oper && oper->getOperation() != OperationSetup::setupoperation)
00230   {
00231     bool oldHasSetup = ld && !ld->getSetup().empty() 
00232       && ld->getResource()->getSetupMatrix();
00233     bool newHasSetup = !newld->getSetup().empty() 
00234       && newld->getResource()->getSetupMatrix();
00235     OperationPlan *setupOpplan = NULL;
00236     if (oldHasSetup)
00237     {
00238       for (OperationPlan::iterator i(oper); i != oper->end(); ++i)
00239         if (i->getOperation() == OperationSetup::setupoperation)
00240         {
00241           setupOpplan = &*i;
00242           break;
00243         }
00244       if (!setupOpplan) oldHasSetup = false;
00245     }
00246     if (oldHasSetup)
00247     {
00248       if (newHasSetup)
00249       {
00250         // Case 1: Both the old and new load require a setup
00251         LoadPlan *setupLdplan = NULL;
00252         for (OperationPlan::LoadPlanIterator j = setupOpplan->beginLoadPlans();
00253           j != setupOpplan->endLoadPlans(); ++j)
00254           if (j->getLoad() == ld)
00255           {
00256             setupLdplan = &*j;
00257             break;
00258           }
00259         if (!setupLdplan)
00260           throw LogicException("Can't find loadplan on setup operationplan");
00261         // Update the loadplan
00262         setupLdplan->setLoad(newld);
00263         setupOpplan->setEnd(setupOpplan->getDates().getEnd());
00264       }
00265       else
00266       {
00267         // Case 2: Delete the old setup which is not required any more
00268         oper->eraseSubOperationPlan(setupOpplan);
00269       }
00270     }
00271     else
00272     {
00273       if (newHasSetup)
00274       {
00275         // Case 3: Create a new setup operationplan
00276         OperationSetup::setupoperation->createOperationPlan(
00277           1, Date::infinitePast, oper->getDates().getEnd(), NULL, oper);
00278       }
00279       //else: 
00280       // Case 4: No setup for the old or new load
00281     }
00282   }
00283 
00284   // Find the loadplan before the setup
00285   LoadPlan *prevldplan = NULL;
00286   if (getOperationPlan()->getOperation() == OperationSetup::setupoperation)
00287   {
00288     for (TimeLine<LoadPlan>::const_iterator i = getResource()->getLoadPlans().begin(isStart() ? getOtherLoadPlan() : this);
00289       i != getResource()->getLoadPlans().end(); --i)
00290     {
00291       const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
00292       if (l && l->getOperationPlan() != getOperationPlan()
00293         && l->getOperationPlan() != getOperationPlan()->getOwner()
00294         && !l->isStart())
00295       {
00296         prevldplan = const_cast<LoadPlan*>(l);
00297         break;
00298       }
00299     }
00300     if (!prevldplan)
00301     {
00302       for (TimeLine<LoadPlan>::const_iterator i = getResource()->getLoadPlans().begin(isStart() ? getOtherLoadPlan() : this);
00303         i != getResource()->getLoadPlans().end(); ++i)
00304       {
00305         const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
00306         if (l && l->getOperationPlan() != getOperationPlan()
00307           && l->getOperationPlan() != getOperationPlan()->getOwner()
00308           && !l->isStart())
00309         {
00310           prevldplan = const_cast<LoadPlan*>(l);
00311           break;
00312         }
00313       }
00314     }
00315   }
00316 
00317   // Change this loadplan and its brother
00318   for (LoadPlan *ldplan = getOtherLoadPlan(); true; )
00319   {
00320    // Remove from the old resource, if there is one
00321     if (ldplan->ld)
00322       ldplan->ld->getResource()->loadplans.erase(ldplan);
00323     
00324     // Insert in the new resource
00325     ldplan->ld = newld;
00326     newld->getResource()->loadplans.insert(
00327       ldplan,
00328       newld->getLoadplanQuantity(ldplan),
00329       newld->getLoadplanDate(ldplan)
00330       );
00331 
00332     // Repeat for the brother loadplan or exit
00333     if (ldplan != this) ldplan = this;
00334     else break;
00335   }
00336 
00337   // Update the setups on the old resource
00338   if (prevldplan)
00339     prevldplan->ld->getResource()->updateSetups(prevldplan);
00340 }
00341 
00342 
00343 PyObject* LoadPlan::getattro(const Attribute& attr)
00344 {
00345   if (attr.isA(Tags::tag_operationplan))
00346     return PythonObject(getOperationPlan());
00347   if (attr.isA(Tags::tag_quantity))
00348     return PythonObject(getQuantity());
00349   if (attr.isA(Tags::tag_startdate))
00350     return PythonObject(getDate());
00351   if (attr.isA(Tags::tag_enddate))
00352     return PythonObject(getOtherLoadPlan()->getDate());
00353   if (attr.isA(Tags::tag_resource))
00354     return PythonObject(getLoad()->getResource());
00355   if (attr.isA(Tags::tag_load))
00356     return PythonObject(getLoad());
00357   if (attr.isA(Tags::tag_setup))
00358     return PythonObject(getSetup());
00359   return NULL;
00360 }
00361 
00362 
00363 int LoadPlanIterator::initialize()
00364 {
00365   // Initialize the type
00366   PythonType& x = PythonExtension<LoadPlanIterator>::getType();
00367   x.setName("loadplanIterator");
00368   x.setDoc("frePPLe iterator for loadplan");
00369   x.supportiter();
00370   return x.typeReady();
00371 }
00372 
00373 
00374 PyObject* LoadPlanIterator::iternext()
00375 {
00376   LoadPlan* ld;
00377   if (resource_or_opplan)
00378   {
00379     // Skip zero quantity loadplans and load ends
00380     while (*resiter != res->getLoadPlans().end() && (*resiter)->getQuantity()<=0.0)
00381       ++(*resiter);
00382     if (*resiter == res->getLoadPlans().end()) return NULL;
00383 
00384     // Return result
00385     ld = const_cast<LoadPlan*>(static_cast<const LoadPlan*>(&*((*resiter)++)));
00386   }
00387   else
00388   {
00389     while (*opplaniter != opplan->endLoadPlans() && (*opplaniter)->getQuantity()==0.0)
00390       ++(*opplaniter);
00391     if (*opplaniter == opplan->endLoadPlans()) return NULL;
00392     ld = static_cast<LoadPlan*>(&*((*opplaniter)++));
00393   }
00394   Py_INCREF(ld);
00395   return const_cast<LoadPlan*>(ld);
00396 }
00397 
00398 } // end namespace
Generated by  doxygen 1.6.2-20100208