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