resource.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/src/model/resource.cpp $
00003   version : $LastChangedRevision: 1505 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2011-08-26 18:55:08 +0200 (Fri, 26 Aug 2011) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007-2011 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 template<class Resource> DECLARE_EXPORT Tree utils::HasName<Resource>::st;
00035 DECLARE_EXPORT const MetaCategory* Resource::metadata;
00036 DECLARE_EXPORT const MetaClass* ResourceDefault::metadata;
00037 DECLARE_EXPORT const MetaClass* ResourceInfinite::metadata;
00038 
00039 
00040 int Resource::initialize()
00041 {
00042   // Initialize the metadata
00043   metadata = new MetaCategory("resource", "resources", reader, writer);
00044 
00045   // Initialize the Python class
00046   return FreppleCategory<Resource>::initialize();
00047 }
00048 
00049 
00050 int ResourceDefault::initialize()
00051 {
00052   // Initialize the metadata
00053   ResourceDefault::metadata = new MetaClass(
00054     "resource",
00055     "resource_default",
00056     Object::createString<ResourceDefault>,
00057     true);
00058 
00059   // Initialize the Python class
00060   return FreppleClass<ResourceDefault,Resource>::initialize();
00061 }
00062 
00063 
00064 int ResourceInfinite::initialize()
00065 {
00066   // Initialize the metadata
00067   ResourceInfinite::metadata = new MetaClass(
00068     "resource",
00069     "resource_infinite",
00070     Object::createString<ResourceInfinite>);
00071 
00072   // Initialize the Python class
00073   return FreppleClass<ResourceInfinite,Resource>::initialize();
00074 }
00075 
00076 
00077 DECLARE_EXPORT void Resource::setMaximum(double m)
00078 {
00079   if (m < 0)
00080     throw DataException("Maximum capacity for resource '" + getName() + "' must be postive");
00081 
00082   // There is already a maximum calendar.
00083   if (size_max_cal)
00084   {
00085     // We update the field, but don't use it yet.
00086     size_max = m;
00087     return;
00088   }
00089 
00090   // Mark as changed
00091   setChanged();
00092 
00093   // Set field
00094   size_max = m;
00095 
00096   // Create or update a single timeline max event
00097   for (loadplanlist::iterator oo=loadplans.begin(); oo!=loadplans.end(); oo++)
00098     if (oo->getType() == 4)
00099     {
00100       // Update existing event
00101       static_cast<loadplanlist::EventMaxQuantity *>(&*oo)->setMax(size_max);
00102       return;
00103     }
00104   // Create new event
00105   loadplanlist::EventMaxQuantity *newEvent =
00106     new loadplanlist::EventMaxQuantity(Date::infinitePast, size_max);
00107   loadplans.insert(newEvent);
00108 }
00109 
00110 
00111 DECLARE_EXPORT void Resource::setMaximumCalendar(CalendarDouble* c)
00112 {
00113   // Resetting the same calendar
00114   if (size_max_cal == c) return;
00115 
00116   // Mark as changed
00117   setChanged();
00118 
00119   // Remove the current max events.
00120   for (loadplanlist::iterator oo=loadplans.begin(); oo!=loadplans.end(); )
00121     if (oo->getType() == 4)
00122     {
00123       loadplans.erase(&(*oo));
00124       delete &(*(oo++));
00125     }
00126     else ++oo;
00127 
00128   // Null pointer passed. Change back to time independent maximum size.
00129   if (!c)
00130   {
00131     setMaximum(size_max);
00132     return;
00133   }
00134 
00135   // Create timeline structures for every bucket.
00136   size_max_cal = c;
00137   double curMax = 0.0;
00138   for (CalendarDouble::EventIterator x(size_max_cal); x.getDate()<Date::infiniteFuture; ++x)
00139     if (curMax != x.getValue())
00140     {
00141       curMax = x.getValue();
00142       loadplanlist::EventMaxQuantity *newBucket =
00143         new loadplanlist::EventMaxQuantity(x.getDate(), curMax);
00144       loadplans.insert(newBucket);
00145     }
00146 }
00147 
00148 
00149 DECLARE_EXPORT void Resource::writeElement(XMLOutput *o, const Keyword& tag, mode m) const
00150 {
00151   // Write a reference
00152   if (m == REFERENCE)
00153   {
00154     o->writeElement(tag, Tags::tag_name, getName());
00155     return;
00156   }
00157 
00158   // Write the complete object
00159   if (m != NOHEADER) o->BeginObject(tag, Tags::tag_name, getName());
00160 
00161   // Write my fields
00162   HasDescription::writeElement(o, tag);
00163   HasHierarchy<Resource>::writeElement(o, tag);
00164   if (getMaximum() != 1)
00165     o->writeElement(Tags::tag_maximum, getMaximum());
00166   o->writeElement(Tags::tag_maximum_calendar, size_max_cal);
00167   if (getMaxEarly() != TimePeriod(defaultMaxEarly))
00168     o->writeElement(Tags::tag_maxearly, getMaxEarly());
00169   if (getCost() != 0.0) o->writeElement(Tags::tag_cost, getCost());
00170   o->writeElement(Tags::tag_location, loc);
00171   if (!getSetup().empty()) o->writeElement(Tags::tag_setup, getSetup());
00172   if (getSetupMatrix())
00173     o->writeElement(Tags::tag_setupmatrix, getSetupMatrix());
00174   Plannable::writeElement(o, tag);
00175 
00176   // Write extra plan information
00177   loadplanlist::const_iterator i = loadplans.begin();
00178   if (o->getContentType() == XMLOutput::PLAN  && i!=loadplans.end())
00179   {
00180     o->BeginObject(Tags::tag_loadplans);
00181     for (; i!=loadplans.end(); ++i)
00182       if (i->getType()==1)
00183       {
00184         const LoadPlan *lp = dynamic_cast<const LoadPlan*>(&*i);
00185         o->BeginObject(Tags::tag_loadplan);
00186         o->writeElement(Tags::tag_date, lp->getDate());
00187         o->writeElement(Tags::tag_quantity, lp->getQuantity());
00188         o->writeElement(Tags::tag_onhand, lp->getOnhand());
00189         o->writeElement(Tags::tag_minimum, lp->getMin());
00190         o->writeElement(Tags::tag_maximum, lp->getMax());
00191         o->writeElement(Tags::tag_operationplan, &*(lp->getOperationPlan()), FULL);
00192         o->EndObject(Tags::tag_loadplan);
00193       }
00194     o->EndObject(Tags::tag_loadplans);
00195   }
00196 
00197   // That was it
00198   o->EndObject(tag);
00199 }
00200 
00201 
00202 DECLARE_EXPORT void Resource::beginElement(XMLInput& pIn, const Attribute& pAttr)
00203 {
00204   if (pAttr.isA (Tags::tag_load)
00205       && pIn.getParentElement().first.isA(Tags::tag_loads))
00206   {
00207     Load* l = new Load();
00208     l->setResource(this);
00209     pIn.readto(&*l);
00210   }
00211   else if (pAttr.isA (Tags::tag_maximum_calendar))
00212     pIn.readto( Calendar::reader(Calendar::metadata,pIn.getAttributes()) );
00213   else if (pAttr.isA(Tags::tag_loadplans))
00214     pIn.IgnoreElement();
00215   else if (pAttr.isA(Tags::tag_location))
00216     pIn.readto( Location::reader(Location::metadata,pIn.getAttributes()) );
00217   else if (pAttr.isA(Tags::tag_setupmatrix))
00218     pIn.readto( SetupMatrix::reader(SetupMatrix::metadata,pIn.getAttributes()) );
00219   else
00220     HasHierarchy<Resource>::beginElement(pIn, pAttr);
00221 }
00222 
00223 
00224 DECLARE_EXPORT void Resource::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00225 {
00226   /* Note that while restoring the size, the parent's size is NOT
00227      automatically updated. The getDescription of the 'set_size' function may
00228      suggest this would be the case... */
00229   if (pAttr.isA (Tags::tag_maximum))
00230     setMaximum(pElement.getDouble());
00231   else if (pAttr.isA (Tags::tag_maximum_calendar))
00232   {
00233     CalendarDouble * c = dynamic_cast<CalendarDouble*>(pIn.getPreviousObject());
00234     if (c)
00235       setMaximumCalendar(c);
00236     else
00237     {
00238       Calendar *c = dynamic_cast<Calendar*>(pIn.getPreviousObject());
00239       if (!c)
00240         throw LogicException("Incorrect object type during read operation");
00241       throw DataException("Calendar '" + c->getName() +
00242           "' has invalid type for use as resource max calendar");
00243     }
00244   }
00245   else if (pAttr.isA (Tags::tag_maxearly))
00246     setMaxEarly(pElement.getTimeperiod());
00247   else if (pAttr.isA (Tags::tag_cost))
00248     setCost(pElement.getDouble());
00249   else if (pAttr.isA(Tags::tag_location))
00250   {
00251     Location * d = dynamic_cast<Location*>(pIn.getPreviousObject());
00252     if (d) setLocation(d);
00253     else throw LogicException("Incorrect object type during read operation");
00254   }
00255   else if (pAttr.isA (Tags::tag_setup))
00256     setSetup(pElement.getString());
00257   else if (pAttr.isA(Tags::tag_setupmatrix))
00258   {
00259     SetupMatrix * d = dynamic_cast<SetupMatrix*>(pIn.getPreviousObject());
00260     if (d) setSetupMatrix(d);
00261     else throw LogicException("Incorrect object type during read operation");
00262   }
00263   else
00264   {
00265     Plannable::endElement(pIn, pAttr, pElement);
00266     HasDescription::endElement(pIn, pAttr, pElement);
00267     HasHierarchy<Resource>::endElement (pIn, pAttr, pElement);
00268   }
00269 }
00270 
00271 
00272 DECLARE_EXPORT void Resource::deleteOperationPlans(bool deleteLocked)
00273 {
00274   // Delete the operationplans
00275   for (loadlist::iterator i=loads.begin(); i!=loads.end(); ++i)
00276     OperationPlan::deleteOperationPlans(i->getOperation(),deleteLocked);
00277 
00278   // Mark to recompute the problems
00279   setChanged();
00280 }
00281 
00282 
00283 DECLARE_EXPORT Resource::~Resource()
00284 {
00285   // Delete all operationplans
00286   // An alternative logic would be to delete only the loadplans for this
00287   // resource and leave the rest of the plan untouched. The currently
00288   // implemented method is way more drastic...
00289   deleteOperationPlans(true);
00290 
00291   // The Load objects are automatically deleted by the destructor
00292   // of the Association list class.
00293 }
00294 
00295 
00296 DECLARE_EXPORT void Resource::updateSetups(const LoadPlan* ldplan)
00297 {
00298   // No updating required this resource
00299   if (!getSetupMatrix() || (ldplan && ldplan->getOperationPlan()->getOperation() != OperationSetup::setupoperation))
00300     return;
00301 
00302   // Update later setup opplans
00303   OperationPlan *opplan = ldplan ? ldplan->getOperationPlan() : NULL;
00304   loadplanlist::const_iterator i = ldplan ?
00305     getLoadPlans().begin(ldplan) :
00306     getLoadPlans().begin();
00307   string prevsetup = ldplan ? ldplan->getSetup() : getSetup();
00308   Date latestCheckDate = ldplan ? ldplan->getDate() : Date::infiniteFuture;
00309   for (; i != getLoadPlans().end(); ++i)
00310   {
00311     const LoadPlan* l = dynamic_cast<const LoadPlan*>(&*i);
00312     if (l && !l->getLoad()->getSetup().empty()
00313       && l->getOperationPlan()->getOperation() == OperationSetup::setupoperation
00314       && l->getOperationPlan() != opplan
00315       && !l->isStart())
00316     {
00317       // Next conversion operation
00318       OperationPlanState x = l->getOperationPlan()->getOperation()->setOperationPlanParameters(
00319         l->getOperationPlan(),
00320         l->getOperationPlan()->getQuantity(),
00321         Date::infinitePast,
00322         l->getOperationPlan()->getDates().getEnd(),
00323         true,
00324         false);
00325       if (x.start != l->getOperationPlan()->getDates().getStart())
00326         // We need to change a setup plan
00327         l->getOperationPlan()->restore(x);
00328       else if (ldplan && x.start == l->getOperationPlan()->getDates().getStart())
00329         // We found a setup plan that doesn't need updating. Later setup plans
00330         // won't require updating either
00331         return;
00332     }
00333   }
00334 }
00335 
00336 
00337 DECLARE_EXPORT void ResourceInfinite::writeElement
00338 (XMLOutput *o, const Keyword &tag, mode m) const
00339 {
00340   // Writing a reference
00341   if (m == REFERENCE)
00342   {
00343     o->writeElement
00344       (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00345     return;
00346   }
00347 
00348   // Write the complete object
00349   if (m != NOHEADER) o->BeginObject
00350     (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00351 
00352   // Write the fields
00353   Resource::writeElement(o, tag, NOHEADER);
00354 }
00355 
00356 
00357 DECLARE_EXPORT PyObject* Resource::getattro(const Attribute& attr)
00358 {
00359   if (attr.isA(Tags::tag_name))
00360     return PythonObject(getName());
00361   if (attr.isA(Tags::tag_description))
00362     return PythonObject(getDescription());
00363   if (attr.isA(Tags::tag_category))
00364     return PythonObject(getCategory());
00365   if (attr.isA(Tags::tag_subcategory))
00366     return PythonObject(getSubCategory());
00367   if (attr.isA(Tags::tag_owner))
00368     return PythonObject(getOwner());
00369   if (attr.isA(Tags::tag_location))
00370     return PythonObject(getLocation());
00371   if (attr.isA(Tags::tag_maximum))
00372     return PythonObject(getMaximum());
00373   if (attr.isA(Tags::tag_maximum_calendar))
00374     return PythonObject(getMaximumCalendar());
00375   if (attr.isA(Tags::tag_maxearly))
00376     return PythonObject(getMaxEarly());
00377   if (attr.isA(Tags::tag_cost))
00378     return PythonObject(getCost());
00379   if (attr.isA(Tags::tag_hidden))
00380     return PythonObject(getHidden());
00381   if (attr.isA(Tags::tag_loadplans))
00382     return new LoadPlanIterator(this);
00383   if (attr.isA(Tags::tag_loads))
00384     return new LoadIterator(this);
00385   if (attr.isA(Tags::tag_setup))
00386     return PythonObject(getSetup());
00387   if (attr.isA(Tags::tag_setupmatrix))
00388     return PythonObject(getSetupMatrix());
00389   if (attr.isA(Tags::tag_level))
00390     return PythonObject(getLevel());
00391   if (attr.isA(Tags::tag_cluster))
00392     return PythonObject(getCluster());
00393   if (attr.isA(Tags::tag_members))
00394   return new ResourceIterator(this);
00395   return NULL;
00396 }
00397 
00398 
00399 DECLARE_EXPORT int Resource::setattro(const Attribute& attr, const PythonObject& field)
00400 {
00401   if (attr.isA(Tags::tag_name))
00402     setName(field.getString());
00403   else if (attr.isA(Tags::tag_description))
00404     setDescription(field.getString());
00405   else if (attr.isA(Tags::tag_category))
00406     setCategory(field.getString());
00407   else if (attr.isA(Tags::tag_subcategory))
00408     setSubCategory(field.getString());
00409   else if (attr.isA(Tags::tag_owner))
00410   {
00411     if (!field.check(PythonExtension<Resource>::getType()))
00412     {
00413       PyErr_SetString(PythonDataException, "resource owner must be of type resource");
00414       return -1;
00415     }
00416     Resource* y = static_cast<Resource*>(static_cast<PyObject*>(field));
00417     setOwner(y);
00418   }
00419   else if (attr.isA(Tags::tag_location))
00420   {
00421     if (!field.check(Location::metadata))
00422     {
00423       PyErr_SetString(PythonDataException, "resource location must be of type location");
00424       return -1;
00425     }
00426     Location* y = static_cast<Location*>(static_cast<PyObject*>(field));
00427     setLocation(y);
00428   }
00429   else if (attr.isA(Tags::tag_maximum))
00430     setMaximum(field.getDouble());
00431   else if (attr.isA(Tags::tag_maximum_calendar))
00432   {
00433     if (!field.check(CalendarDouble::metadata))
00434     {
00435       PyErr_SetString(PythonDataException, "resource maximum_calendar must be of type calendar_double");
00436       return -1;
00437     }
00438     CalendarDouble* y = static_cast<CalendarDouble*>(static_cast<PyObject*>(field));
00439     setMaximumCalendar(y);
00440   }
00441   else if (attr.isA(Tags::tag_hidden))
00442     setHidden(field.getBool());
00443   else if (attr.isA(Tags::tag_cost))
00444     setCost(field.getDouble());
00445   else if (attr.isA(Tags::tag_maxearly))
00446     setMaxEarly(field.getTimeperiod());
00447   else if (attr.isA(Tags::tag_setup))
00448     setSetup(field.getString());
00449   else if (attr.isA(Tags::tag_setupmatrix))
00450   {
00451     if (!field.check(SetupMatrix::metadata))
00452     {
00453       PyErr_SetString(PythonDataException, "resource setup_matrix must be of type setup_matrix");
00454       return -1;
00455     }
00456     SetupMatrix* y = static_cast<SetupMatrix*>(static_cast<PyObject*>(field));
00457     setSetupMatrix(y);
00458   }
00459   else
00460     return -1;  // Error
00461   return 0;  // OK
00462 }
00463 
00464 }

Documentation generated for frePPLe by  doxygen