model/actions.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/actions.cpp $
00003   version : $LastChangedRevision: 1145 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2010-01-04 19:24:24 +0100 (Mon, 04 Jan 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 //
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         for (Demand::OperationPlan_list::const_iterator
00252             pp=gdem->getDelivery().begin();
00253             pp!=gdem->getDelivery().end();
00254             ++pp)
00255         {
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->getDateRange() << endl;
00298     }
00299 
00300     // Close the output file
00301     textoutput.close();
00302   }
00303   catch (exception& e)
00304   {
00305     textoutput.close();
00306     throw RuntimeException("Error writing to file '"
00307         + getFileName() + "':\n" + e.what());
00308   }
00309   catch (...)
00310   {
00311     textoutput.close();
00312     throw RuntimeException("Error writing to file '"
00313         + getFileName() + "'");
00314   }
00315 
00316   // Message
00317   if (getVerbose())
00318     logger << "Finished saving plan at " << Date::now() << " : " << t << endl;
00319 }
00320 
00321 
00322 PyObject* CommandSavePlan::executePython(PyObject* self, PyObject* args)
00323 {
00324   // Pick up arguments
00325   char *data;
00326   int ok = PyArg_ParseTuple(args, "s:saveplan", &data);
00327   if (!ok) return NULL;
00328 
00329   // Execute and catch exceptions
00330   Py_BEGIN_ALLOW_THREADS   // Free Python interpreter for other threads
00331   try {
00332     CommandSavePlan(data).execute();
00333   }
00334   catch (...)
00335   {
00336     Py_BLOCK_THREADS;
00337     PythonType::evalException();
00338     return NULL;
00339   }
00340   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00341   return Py_BuildValue("");
00342 }
00343 
00344 
00345 //
00346 // MOVE OPERATIONPLAN
00347 //
00348                
00349 DECLARE_EXPORT CommandMoveOperationPlan::CommandMoveOperationPlan
00350   (OperationPlan* o) : opplan(o), firstCommand(NULL)
00351 {
00352   if (!o) 
00353   {
00354     originalqty = 0;
00355     return;
00356   }
00357   originalqty = opplan->getQuantity();
00358   originaldates = opplan->getDates();
00359 
00360   // Construct a subcommand for all suboperationplans
00361   for (OperationPlan::iterator x(o); x != o->end(); ++x)
00362     if (x->getOperation() != OperationSetup::setupoperation)
00363     {
00364       CommandMoveOperationPlan *n = new CommandMoveOperationPlan(o);
00365       n->owner = this;
00366       if (firstCommand)
00367       {
00368         n->next = firstCommand;
00369         firstCommand->prev = n;
00370       }
00371       firstCommand = n;
00372     }
00373 }
00374 
00375 
00376 DECLARE_EXPORT CommandMoveOperationPlan::CommandMoveOperationPlan
00377 (OperationPlan* o, Date newstart, Date newend, double newQty) 
00378   : opplan(o), firstCommand(NULL)
00379 {
00380   if (!opplan) return;
00381 
00382   // Store current settings
00383   originalqty = opplan->getQuantity();
00384   if (newQty == -1.0) newQty = originalqty;
00385   originaldates = opplan->getDates();
00386 
00387   // Update the settings
00388   assert(opplan->getOperation());
00389   opplan->getOperation()->setOperationPlanParameters(
00390     opplan, newQty, newstart, newend
00391   );
00392 
00393   // Construct a subcommand for all suboperationplans
00394   for (OperationPlan::iterator x(o); x != o->end(); ++x)
00395     if (x->getOperation() != OperationSetup::setupoperation)
00396     {
00397       CommandMoveOperationPlan *n = new CommandMoveOperationPlan(o);
00398       n->owner = this;
00399       if (firstCommand)
00400       {
00401         n->next = firstCommand;
00402         firstCommand->prev = n;
00403       }
00404       firstCommand = n;
00405     }
00406 }
00407 
00408 
00409 DECLARE_EXPORT void CommandMoveOperationPlan::restore(bool del)
00410 {
00411   // Restore all suboperationplans and (optionally) delete the subcommands
00412   for (Command *c = firstCommand; c; )
00413   {
00414     CommandMoveOperationPlan *tmp = static_cast<CommandMoveOperationPlan*>(c);
00415     tmp->restore(del);
00416     c = c->next;
00417     if (del) delete tmp;
00418   }
00419 
00420   // Restore the original dates
00421   if (!opplan) return;
00422   opplan->getOperation()->setOperationPlanParameters(
00423     opplan, originalqty, originaldates.getStart(), originaldates.getEnd()
00424   );
00425 }
00426 
00427 
00428 //
00429 // DELETE OPERATIONPLAN
00430 //
00431 
00432 DECLARE_EXPORT CommandDeleteOperationPlan::CommandDeleteOperationPlan
00433   (OperationPlan* o)
00434 {
00435   // Validate input
00436   if (!o)
00437   {
00438     oper = NULL;
00439     return;
00440   }
00441 
00442   // Avoid deleting locked operationplans
00443   if (o->getLocked())
00444     throw DataException("Can't delete a locked operationplan");
00445 
00446   // Register the fields of the operationplan before deletion
00447   oper = o->getOperation();
00448   qty = o->getQuantity();
00449   dates = o->getDates();
00450   id = o->getIdentifier();
00451   dmd = o->getDemand();
00452   ow = &*(o->getOwner());
00453 
00454   // Delete the operationplan
00455   delete o;
00456 }
00457 
00458 
00459 DECLARE_EXPORT void CommandDeleteOperationPlan::undo()
00460 {
00461   // Already executed, or never initialized completely
00462   if (!oper) return;
00463 
00464   // Recreate and register the operationplan.
00465   // Note that the recreated operationplan has the same field values as the
00466   // original one, but has a different memory address. Any pointers to the
00467   // original operationplan are now dangling.
00468   OperationPlan* opplan = oper->createOperationPlan(qty, dates.getStart(),
00469     dates.getEnd(), dmd, const_cast<OperationPlan*>(ow), id);
00470   if (opplan) opplan->instantiate();
00471 
00472   // Avoid undoing multiple times!
00473   oper = NULL;
00474 }
00475 
00476 
00477 //
00478 // DELETE MODEL
00479 //
00480 
00481 
00482 DECLARE_EXPORT void CommandErase::execute()
00483 {
00484   // Starting message
00485   if (getVerbose())
00486   {
00487     if (deleteStaticModel)
00488       logger << "Start model erase command at " << Date::now() << endl;
00489     else
00490       logger << "Start plan erase command at " << Date::now() << endl;
00491   }
00492   Timer t;
00493 
00494   if (deleteStaticModel)
00495   {
00496     // Delete all entities.
00497     // The order is chosen to minimize the work of the individual destructors.
00498     // E.g. the destructor of the item class recurses over all demands and
00499     // all buffers. It is much faster if there are none already.
00500     Demand::clear();
00501     Operation::clear();  
00502     Buffer::clear();     
00503     Resource::clear();
00504     SetupMatrix::clear();
00505     Location::clear();
00506     Customer::clear();
00507     Calendar::clear();
00508     Solver::clear();
00509     Item::clear();
00510     // The setup operation is a static singleton and should always be around
00511     OperationSetup::setupoperation = Operation::add(new OperationSetup("setup operation"));
00512   }
00513   else
00514     // Delete the operationplans only
00515     for (Operation::iterator gop = Operation::begin();
00516         gop != Operation::end(); ++gop)
00517       gop->deleteOperationPlans();
00518 
00519   // Ending message
00520   if (getVerbose())
00521     logger << "Finished erase command at " << Date::now()
00522     << " : " << t << endl;
00523 }
00524 
00525 
00526 PyObject* CommandErase::executePython(PyObject* self, PyObject* args)
00527 {
00528   // Pick up arguments
00529   PyObject *obj = NULL;
00530   int ok = PyArg_ParseTuple(args, "|O:erase", &obj);
00531   if (!ok) return NULL;
00532 
00533   // Validate the argument
00534   bool staticalso = false;
00535   if (obj) staticalso = PythonObject(obj).getBool();
00536 
00537   // Execute and catch exceptions
00538   Py_BEGIN_ALLOW_THREADS   // Free Python interpreter for other threads
00539   try {
00540     CommandErase(staticalso).execute();
00541   }
00542   catch (...)
00543   {
00544     Py_BLOCK_THREADS;
00545     PythonType::evalException();
00546     return NULL;
00547   }
00548   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00549   return Py_BuildValue("");
00550 }
00551 
00552 } // end namespace
Generated by  doxygen 1.6.2-20100208