model/actions.cpp
Go to the documentation of this file.00001 /*************************************************************************** 00002 file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/src/model/actions.cpp $ 00003 version : $LastChangedRevision: 1315 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2010-07-17 18:08:53 +0200 (Sat, 17 Jul 2010) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007-2010 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 // 00035 // READ XML INPUT FILE 00036 // 00037 00038 DECLARE_EXPORT void CommandReadXMLFile::execute() 00039 { 00040 // Message 00041 if (getVerbose()) 00042 logger << "Started reading model from file '" << filename 00043 << "' at " << Date::now() << endl; 00044 Timer t; 00045 00046 // Note: Reading the data files can throw exceptions... 00047 if (filename.empty()) 00048 { 00049 // Read from standard input 00050 xercesc::StdInInputSource in; 00051 if (validate_only) 00052 // When no root object is passed, only the input validation happens 00053 XMLInput().parse(in, NULL, true); 00054 else 00055 XMLInput().parse(in, &Plan::instance(), validate); 00056 } 00057 else if (validate_only) 00058 // Read and validate a file 00059 XMLInputFile(filename).parse(NULL, true); 00060 else 00061 // Read, execute and optionally validate a file 00062 XMLInputFile(filename).parse(&Plan::instance(),validate); 00063 00064 // Message 00065 if (getVerbose()) 00066 logger << "Finished reading model at " << Date::now() << " : " << t << endl; 00067 } 00068 00069 00070 DECLARE_EXPORT PyObject* CommandReadXMLFile::executePython(PyObject* self, PyObject* args) 00071 { 00072 // Pick up arguments 00073 char *data; 00074 int i1(1), i2(0); 00075 int ok = PyArg_ParseTuple(args, "s|ii:readXMLfile", &data, &i1, &i2); 00076 if (!ok) return NULL; 00077 00078 // Execute and catch exceptions 00079 Py_BEGIN_ALLOW_THREADS // Free Python interpreter for other threads 00080 try { 00081 CommandReadXMLFile(data, i1!=0, i2!=0).execute(); 00082 } 00083 catch (...) 00084 { 00085 Py_BLOCK_THREADS; 00086 PythonType::evalException(); 00087 return NULL; 00088 } 00089 Py_END_ALLOW_THREADS // Reclaim Python interpreter 00090 return Py_BuildValue(""); 00091 } 00092 00093 00094 // 00095 // READ XML INPUT STRING 00096 // 00097 00098 DECLARE_EXPORT void CommandReadXMLString::execute() 00099 { 00100 // Message 00101 if (getVerbose()) 00102 logger << "Started reading model from string at " << Date::now() << endl; 00103 Timer t; 00104 00105 // Note: Reading the data can throw exceptions... 00106 if (validate_only) 00107 XMLInputString(data).parse(NULL, true); 00108 else 00109 // Locking the plan assures a single read command is running at any time. 00110 XMLInputString(data).parse(&Plan::instance(), validate); 00111 00112 // Message 00113 if (getVerbose()) 00114 logger << "Finished reading model at " << Date::now() << " : " << t << endl; 00115 } 00116 00117 00118 PyObject* CommandReadXMLString::executePython(PyObject *self, PyObject *args) 00119 { 00120 // Pick up arguments 00121 char *data; 00122 int i1(1), i2(0); 00123 int ok = PyArg_ParseTuple(args, "s|ii:readXMLdata", &data, &i1, &i2); 00124 if (!ok) return NULL; 00125 00126 // Execute and catch exceptions 00127 Py_BEGIN_ALLOW_THREADS // Free Python interpreter for other threads 00128 try { 00129 if (data) CommandReadXMLString(string(data), i1!=0, i2!=0).execute(); 00130 } 00131 catch (...) 00132 { 00133 Py_BLOCK_THREADS; 00134 PythonType::evalException(); 00135 return NULL; 00136 } 00137 Py_END_ALLOW_THREADS // Reclaim Python interpreter 00138 return Py_BuildValue(""); // Safer than using Py_None, which is not 00139 // portable across compilers 00140 } 00141 00142 00143 // 00144 // SAVE MODEL TO XML 00145 // 00146 00147 DECLARE_EXPORT void CommandSave::execute() 00148 { 00149 // Message 00150 if (getVerbose()) 00151 logger << "Start saving model to file '" << filename 00152 << "' at " << Date::now() << endl; 00153 Timer t; 00154 00155 // Save the plan 00156 XMLOutputFile o(filename); 00157 if (!headerstart.empty()) o.setHeaderStart(headerstart); 00158 if (!headeratts.empty()) o.setHeaderAtts(headeratts); 00159 o.setContentType(content); 00160 o.writeElementWithHeader(Tags::tag_plan, &Plan::instance()); 00161 00162 // Message 00163 if (getVerbose()) 00164 logger << "Finished saving " << o.countObjects() 00165 << " objects at " << Date::now() << " : " << t << endl; 00166 } 00167 00168 00169 PyObject* CommandSave::executePython(PyObject* self, PyObject* args) 00170 { 00171 // Pick up arguments 00172 char *data; 00173 char *content = NULL; 00174 int ok = PyArg_ParseTuple(args, "s|s:save", &data, &content); 00175 if (!ok) return NULL; 00176 00177 // Execute and catch exceptions 00178 Py_BEGIN_ALLOW_THREADS // Free Python interpreter for other threads 00179 try { 00180 CommandSave cmd(data); 00181 if (content) 00182 { 00183 if (!strcmp(content,"STANDARD")) 00184 cmd.setContent(XMLOutput::STANDARD); 00185 else if (!strcmp(content,"PLAN")) 00186 cmd.setContent(XMLOutput::PLAN); 00187 else if (!strcmp(content,"PLANDETAIL")) 00188 cmd.setContent(XMLOutput::PLANDETAIL); 00189 else 00190 throw DataException("Invalid content type '" + string(content) + "'"); 00191 } 00192 cmd.execute(); 00193 } 00194 catch (...) 00195 { 00196 Py_BLOCK_THREADS; 00197 PythonType::evalException(); 00198 return NULL; 00199 } 00200 Py_END_ALLOW_THREADS // Reclaim Python interpreter 00201 return Py_BuildValue(""); 00202 } 00203 00204 00205 // 00206 // SAVE PLAN SUMMARY TO TEXT FILE 00207 // 00208 00209 DECLARE_EXPORT void CommandSavePlan::execute() 00210 { 00211 // Message 00212 if (getVerbose()) 00213 logger << "Start saving plan to file '" << getFileName() 00214 << "' at " << Date::now() << endl; 00215 Timer t; 00216 00217 // Output steam 00218 if (getFileName().empty()) 00219 throw RuntimeException("No file specified for export"); 00220 ofstream textoutput; 00221 00222 // Open the file, write to it and close it. Catch exceptions all along... 00223 try 00224 { 00225 // Open the output file 00226 textoutput.open(getFileName().c_str(), ios::out); 00227 00228 // Write the buffer summary 00229 for (Buffer::iterator gbuf = Buffer::begin(); 00230 gbuf != Buffer::end(); ++gbuf) 00231 { 00232 if (!gbuf->getHidden()) 00233 for (Buffer::flowplanlist::const_iterator 00234 oo=gbuf->getFlowPlans().begin(); 00235 oo!=gbuf->getFlowPlans().end(); 00236 ++oo) 00237 if (oo->getType() == 1 && oo->getQuantity() != 0.0) 00238 { 00239 textoutput << "BUFFER\t" << *gbuf << '\t' 00240 << oo->getDate() << '\t' 00241 << oo->getQuantity() << '\t' 00242 << oo->getOnhand() << endl; 00243 } 00244 } 00245 00246 // Write the demand summary 00247 for (Demand::iterator gdem = Demand::begin(); 00248 gdem != Demand::end(); ++gdem) 00249 { 00250 if (!gdem->getHidden()) 00251 { 00252 for (Demand::OperationPlan_list::const_iterator 00253 pp = gdem->getDelivery().begin(); 00254 pp != gdem->getDelivery().end(); 00255 ++pp) 00256 textoutput << "DEMAND\t" << (*gdem) << '\t' 00257 << (*pp)->getDates().getEnd() << '\t' 00258 << (*pp)->getQuantity() << endl; 00259 } 00260 } 00261 00262 // Write the resource summary 00263 for (Resource::iterator gres = Resource::begin(); 00264 gres != Resource::end(); ++gres) 00265 { 00266 if (!gres->getHidden()) 00267 for (Resource::loadplanlist::const_iterator 00268 qq=gres->getLoadPlans().begin(); 00269 qq!=gres->getLoadPlans().end(); 00270 ++qq) 00271 if (qq->getType() == 1 && qq->getQuantity() != 0.0) 00272 { 00273 textoutput << "RESOURCE\t" << *gres << '\t' 00274 << qq->getDate() << '\t' 00275 << qq->getQuantity() << '\t' 00276 << qq->getOnhand() << endl; 00277 } 00278 } 00279 00280 // Write the operationplan summary. 00281 for (OperationPlan::iterator rr = OperationPlan::begin(); 00282 rr != OperationPlan::end(); ++rr) 00283 { 00284 if (rr->getOperation()->getHidden()) continue; 00285 textoutput << "OPERATION\t" << rr->getOperation() << '\t' 00286 << rr->getDates().getStart() << '\t' 00287 << rr->getDates().getEnd() << '\t' 00288 << rr->getQuantity() << endl; 00289 } 00290 00291 // Write the problem summary. 00292 for (Problem::const_iterator gprob = Problem::begin(); 00293 gprob != Problem::end(); ++gprob) 00294 { 00295 textoutput << "PROBLEM\t" << gprob->getType().type << '\t' 00296 << gprob->getDescription() << '\t' 00297 << gprob->getDates() << endl; 00298 } 00299 00300 // Write the constraint summary 00301 for (Demand::iterator gdem = Demand::begin(); 00302 gdem != Demand::end(); ++gdem) 00303 { 00304 if (!gdem->getHidden()) 00305 { 00306 for (Problem::const_iterator i = gdem->getConstraints().begin(); 00307 i != gdem->getConstraints().end(); 00308 ++i) 00309 textoutput << "DEMAND CONSTRAINT\t" << (*gdem) << '\t' 00310 << i->getDescription() << '\t' 00311 << i->getDates() << '\t' << endl; 00312 } 00313 } 00314 00315 // Close the output file 00316 textoutput.close(); 00317 } 00318 catch (exception& e) 00319 { 00320 textoutput.close(); 00321 throw RuntimeException("Error writing to file '" 00322 + getFileName() + "':\n" + e.what()); 00323 } 00324 catch (...) 00325 { 00326 textoutput.close(); 00327 throw RuntimeException("Error writing to file '" 00328 + getFileName() + "'"); 00329 } 00330 00331 // Message 00332 if (getVerbose()) 00333 logger << "Finished saving plan at " << Date::now() << " : " << t << endl; 00334 } 00335 00336 00337 PyObject* CommandSavePlan::executePython(PyObject* self, PyObject* args) 00338 { 00339 // Pick up arguments 00340 char *data; 00341 int ok = PyArg_ParseTuple(args, "s:saveplan", &data); 00342 if (!ok) return NULL; 00343 00344 // Execute and catch exceptions 00345 Py_BEGIN_ALLOW_THREADS // Free Python interpreter for other threads 00346 try { 00347 CommandSavePlan(data).execute(); 00348 } 00349 catch (...) 00350 { 00351 Py_BLOCK_THREADS; 00352 PythonType::evalException(); 00353 return NULL; 00354 } 00355 Py_END_ALLOW_THREADS // Reclaim Python interpreter 00356 return Py_BuildValue(""); 00357 } 00358 00359 00360 // 00361 // MOVE OPERATIONPLAN 00362 // 00363 00364 DECLARE_EXPORT CommandMoveOperationPlan::CommandMoveOperationPlan 00365 (OperationPlan* o) : opplan(o), firstCommand(NULL) 00366 { 00367 if (!o) 00368 { 00369 originalqty = 0; 00370 return; 00371 } 00372 originalqty = opplan->getQuantity(); 00373 originaldates = opplan->getDates(); 00374 00375 // Construct a subcommand for all suboperationplans 00376 for (OperationPlan::iterator x(o); x != o->end(); ++x) 00377 if (x->getOperation() != OperationSetup::setupoperation) 00378 { 00379 CommandMoveOperationPlan *n = new CommandMoveOperationPlan(o); 00380 n->owner = this; 00381 if (firstCommand) 00382 { 00383 n->next = firstCommand; 00384 firstCommand->prev = n; 00385 } 00386 firstCommand = n; 00387 } 00388 } 00389 00390 00391 DECLARE_EXPORT CommandMoveOperationPlan::CommandMoveOperationPlan 00392 (OperationPlan* o, Date newstart, Date newend, double newQty) 00393 : opplan(o), firstCommand(NULL) 00394 { 00395 if (!opplan) return; 00396 00397 // Store current settings 00398 originalqty = opplan->getQuantity(); 00399 if (newQty == -1.0) newQty = originalqty; 00400 originaldates = opplan->getDates(); 00401 00402 // Update the settings 00403 assert(opplan->getOperation()); 00404 opplan->getOperation()->setOperationPlanParameters( 00405 opplan, newQty, newstart, newend 00406 ); 00407 00408 // Construct a subcommand for all suboperationplans 00409 for (OperationPlan::iterator x(o); x != o->end(); ++x) 00410 if (x->getOperation() != OperationSetup::setupoperation) 00411 { 00412 CommandMoveOperationPlan *n = new CommandMoveOperationPlan(o); 00413 n->owner = this; 00414 if (firstCommand) 00415 { 00416 n->next = firstCommand; 00417 firstCommand->prev = n; 00418 } 00419 firstCommand = n; 00420 } 00421 } 00422 00423 00424 DECLARE_EXPORT void CommandMoveOperationPlan::restore(bool del) 00425 { 00426 // Restore all suboperationplans and (optionally) delete the subcommands 00427 for (Command *c = firstCommand; c; ) 00428 { 00429 CommandMoveOperationPlan *tmp = static_cast<CommandMoveOperationPlan*>(c); 00430 tmp->restore(del); 00431 c = c->next; 00432 if (del) delete tmp; 00433 } 00434 00435 // Restore the original dates 00436 if (!opplan) return; 00437 opplan->getOperation()->setOperationPlanParameters( 00438 opplan, originalqty, originaldates.getStart(), originaldates.getEnd() 00439 ); 00440 } 00441 00442 00443 // 00444 // DELETE OPERATIONPLAN 00445 // 00446 00447 DECLARE_EXPORT CommandDeleteOperationPlan::CommandDeleteOperationPlan 00448 (OperationPlan* o) 00449 { 00450 // Validate input 00451 if (!o) 00452 { 00453 oper = NULL; 00454 return; 00455 } 00456 00457 // Avoid deleting locked operationplans 00458 if (o->getLocked()) 00459 throw DataException("Can't delete a locked operationplan"); 00460 00461 // Register the fields of the operationplan before deletion 00462 oper = o->getOperation(); 00463 qty = o->getQuantity(); 00464 dates = o->getDates(); 00465 id = o->getIdentifier(); 00466 dmd = o->getDemand(); 00467 ow = &*(o->getOwner()); 00468 00469 // Delete the operationplan 00470 delete o; 00471 } 00472 00473 00474 DECLARE_EXPORT void CommandDeleteOperationPlan::undo() 00475 { 00476 // Already executed, or never initialized completely 00477 if (!oper) return; 00478 00479 // Recreate and register the operationplan. 00480 // Note that the recreated operationplan has the same field values as the 00481 // original one, but has a different memory address. Any pointers to the 00482 // original operationplan are now dangling. 00483 OperationPlan* opplan = oper->createOperationPlan(qty, dates.getStart(), 00484 dates.getEnd(), dmd, const_cast<OperationPlan*>(ow), id); 00485 if (opplan) opplan->instantiate(); 00486 00487 // Avoid undoing multiple times! 00488 oper = NULL; 00489 } 00490 00491 00492 // 00493 // DELETE MODEL 00494 // 00495 00496 00497 DECLARE_EXPORT void CommandErase::execute() 00498 { 00499 // Starting message 00500 if (getVerbose()) 00501 { 00502 if (deleteStaticModel) 00503 logger << "Start model erase command at " << Date::now() << endl; 00504 else 00505 logger << "Start plan erase command at " << Date::now() << endl; 00506 } 00507 Timer t; 00508 00509 if (deleteStaticModel) 00510 { 00511 // Delete all entities. 00512 // The order is chosen to minimize the work of the individual destructors. 00513 // E.g. the destructor of the item class recurses over all demands and 00514 // all buffers. It is much faster if there are none already. 00515 Demand::clear(); 00516 Operation::clear(); 00517 Buffer::clear(); 00518 Resource::clear(); 00519 SetupMatrix::clear(); 00520 Location::clear(); 00521 Customer::clear(); 00522 Calendar::clear(); 00523 Solver::clear(); 00524 Item::clear(); 00525 // The setup operation is a static singleton and should always be around 00526 OperationSetup::setupoperation = Operation::add(new OperationSetup("setup operation")); 00527 } 00528 else 00529 // Delete the operationplans only 00530 for (Operation::iterator gop = Operation::begin(); 00531 gop != Operation::end(); ++gop) 00532 gop->deleteOperationPlans(); 00533 00534 // Ending message 00535 if (getVerbose()) 00536 logger << "Finished erase command at " << Date::now() 00537 << " : " << t << endl; 00538 } 00539 00540 00541 PyObject* CommandErase::executePython(PyObject* self, PyObject* args) 00542 { 00543 // Pick up arguments 00544 PyObject *obj = NULL; 00545 int ok = PyArg_ParseTuple(args, "|O:erase", &obj); 00546 if (!ok) return NULL; 00547 00548 // Validate the argument 00549 bool staticalso = false; 00550 if (obj) staticalso = PythonObject(obj).getBool(); 00551 00552 // Execute and catch exceptions 00553 Py_BEGIN_ALLOW_THREADS // Free Python interpreter for other threads 00554 try { 00555 CommandErase(staticalso).execute(); 00556 } 00557 catch (...) 00558 { 00559 Py_BLOCK_THREADS; 00560 PythonType::evalException(); 00561 return NULL; 00562 } 00563 Py_END_ALLOW_THREADS // Reclaim Python interpreter 00564 return Py_BuildValue(""); 00565 } 00566 00567 } // end namespace
Documentation generated for frePPLe by
