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 }