model/actions.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.9.1/src/model/actions.cpp $
00003   version : $LastChangedRevision: 1656 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2012-03-27 19:05:34 +0200 (Tue, 27 Mar 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 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 
00039 DECLARE_EXPORT PyObject* readXMLfile(PyObject* self, PyObject* args)
00040 {
00041   // Pick up arguments
00042   char *filename = NULL;
00043   int validate(1), validate_only(0);
00044   int ok = PyArg_ParseTuple(args, "|sii:readXMLfile", &filename, &validate, &validate_only);
00045   if (!ok) return NULL;
00046 
00047   // Execute and catch exceptions
00048   Py_BEGIN_ALLOW_THREADS   // Free Python interpreter for other threads
00049   try
00050   {
00051     if (!filename)
00052     {
00053       // Read from standard input
00054       xercesc::StdInInputSource in;
00055       if (validate_only!=0)
00056         // When no root object is passed, only the input validation happens
00057         XMLInput().parse(in, NULL, true);
00058       else
00059         XMLInput().parse(in, &Plan::instance(), validate!=0);
00060     }
00061     else if (validate_only!=0)
00062       // Read and validate a file
00063       XMLInputFile(filename).parse(NULL, true);
00064     else
00065       // Read, execute and optionally validate a file
00066       XMLInputFile(filename).parse(&Plan::instance(),validate!=0);
00067   }
00068   catch (...)
00069   {
00070     Py_BLOCK_THREADS;
00071     PythonType::evalException();
00072     return NULL;
00073   }
00074   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00075   return Py_BuildValue("");
00076 }
00077 
00078 
00079 //
00080 // READ XML INPUT STRING
00081 //
00082 
00083 
00084 DECLARE_EXPORT PyObject* readXMLdata(PyObject *self, PyObject *args)
00085 {
00086   // Pick up arguments
00087   char *data;
00088   int validate(1), validate_only(0);
00089   int ok = PyArg_ParseTuple(args, "s|ii:readXMLdata", &data, &validate, &validate_only);
00090   if (!ok) return NULL;
00091 
00092   // Free Python interpreter for other threads
00093   Py_BEGIN_ALLOW_THREADS
00094 
00095   // Execute and catch exceptions
00096   try
00097   {
00098     if (!data)
00099       throw DataException("No input data");
00100     else if (validate_only!=0)
00101       XMLInputString(data).parse(NULL, true);
00102     else
00103       XMLInputString(data).parse(&Plan::instance(), validate!=0);
00104   }
00105   catch (...)
00106   {
00107     Py_BLOCK_THREADS;
00108     PythonType::evalException();
00109     return NULL;
00110   }
00111   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00112   return Py_BuildValue("");  // Safer than using Py_None, which is not portable across compilers
00113 }
00114 
00115 
00116 //
00117 // SAVE MODEL TO XML
00118 //
00119 
00120 
00121 PyObject* saveXMLfile(PyObject* self, PyObject* args)
00122 {
00123   // Pick up arguments
00124   char *filename;
00125   char *content = NULL;
00126   int ok = PyArg_ParseTuple(args, "s|s:save", &filename, &content);
00127   if (!ok) return NULL;
00128 
00129   // Execute and catch exceptions
00130   Py_BEGIN_ALLOW_THREADS   // Free Python interpreter for other threads
00131   try
00132   {
00133     XMLOutputFile o(filename);
00134     if (content)
00135     {
00136       if (!strcmp(content,"STANDARD"))
00137         o.setContentType(XMLOutput::STANDARD);
00138       else if (!strcmp(content,"PLAN"))
00139         o.setContentType(XMLOutput::PLAN);
00140       else if (!strcmp(content,"PLANDETAIL"))
00141         o.setContentType(XMLOutput::PLANDETAIL);
00142       else
00143         throw DataException("Invalid content type '" + string(content) + "'");
00144     }
00145     o.writeElementWithHeader(Tags::tag_plan, &Plan::instance());
00146   }
00147   catch (...)
00148   {
00149     Py_BLOCK_THREADS;
00150     PythonType::evalException();
00151     return NULL;
00152   }
00153   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00154   return Py_BuildValue("");
00155 }
00156 
00157 
00158 //
00159 // SAVE PLAN SUMMARY TO TEXT FILE
00160 //
00161 
00162 
00163 DECLARE_EXPORT PyObject* savePlan(PyObject* self, PyObject* args)
00164 {
00165   // Pick up arguments
00166   const char *filename = "plan.out";
00167   int ok = PyArg_ParseTuple(args, "s:saveplan", &filename);
00168   if (!ok) return NULL;
00169 
00170   // Free Python interpreter for other threads
00171   Py_BEGIN_ALLOW_THREADS
00172 
00173   // Execute and catch exceptions
00174   ofstream textoutput;
00175   try
00176   {
00177     // Open the output file
00178     textoutput.open(filename, ios::out);
00179 
00180     // Write the buffer summary
00181     for (Buffer::iterator gbuf = Buffer::begin();
00182         gbuf != Buffer::end(); ++gbuf)
00183     {
00184       if (!gbuf->getHidden())
00185         for (Buffer::flowplanlist::const_iterator
00186             oo=gbuf->getFlowPlans().begin();
00187             oo!=gbuf->getFlowPlans().end();
00188             ++oo)
00189           if (oo->getType() == 1 && oo->getQuantity() != 0.0)
00190           {
00191             textoutput << "BUFFER\t" << *gbuf << '\t'
00192                 << oo->getDate() << '\t'
00193                 << oo->getQuantity() << '\t'
00194                 << oo->getOnhand() << endl;
00195           }
00196     }
00197 
00198     // Write the demand summary
00199     for (Demand::iterator gdem = Demand::begin();
00200         gdem != Demand::end(); ++gdem)
00201     {
00202       if (!gdem->getHidden())
00203       {
00204         for (Demand::OperationPlan_list::const_iterator
00205             pp = gdem->getDelivery().begin();
00206             pp != gdem->getDelivery().end();
00207             ++pp)
00208           textoutput << "DEMAND\t" << (*gdem) << '\t'
00209               << (*pp)->getDates().getEnd() << '\t'
00210               << (*pp)->getQuantity() << endl;
00211       }
00212     }
00213 
00214     // Write the resource summary
00215     for (Resource::iterator gres = Resource::begin();
00216         gres != Resource::end(); ++gres)
00217     {
00218       if (!gres->getHidden())
00219         for (Resource::loadplanlist::const_iterator
00220             qq=gres->getLoadPlans().begin();
00221             qq!=gres->getLoadPlans().end();
00222             ++qq)
00223           if (qq->getType() == 1 && qq->getQuantity() != 0.0)
00224           {
00225             textoutput << "RESOURCE\t" << *gres << '\t'
00226                 << qq->getDate() << '\t'
00227                 << qq->getQuantity() << '\t'
00228                 << qq->getOnhand() << endl;
00229           }
00230     }
00231 
00232     // Write the operationplan summary.
00233     for (OperationPlan::iterator rr = OperationPlan::begin();
00234         rr != OperationPlan::end(); ++rr)
00235     {
00236       if (rr->getOperation()->getHidden()) continue;
00237       textoutput << "OPERATION\t" << rr->getOperation() << '\t'
00238           << rr->getDates().getStart() << '\t'
00239           << rr->getDates().getEnd() << '\t'
00240           << rr->getQuantity() << endl;
00241     }
00242 
00243     // Write the problem summary.
00244     for (Problem::const_iterator gprob = Problem::begin();
00245         gprob != Problem::end(); ++gprob)
00246     {
00247       textoutput << "PROBLEM\t" << gprob->getType().type << '\t'
00248           << gprob->getDescription() << '\t'
00249           << gprob->getDates() << endl;
00250     }
00251 
00252     // Write the constraint summary
00253     for (Demand::iterator gdem = Demand::begin();
00254         gdem != Demand::end(); ++gdem)
00255     {
00256       if (!gdem->getHidden())
00257       {
00258         for (Problem::const_iterator i = gdem->getConstraints().begin();
00259             i != gdem->getConstraints().end();
00260             ++i)
00261           textoutput << "DEMAND CONSTRAINT\t" << (*gdem) << '\t'
00262               << i->getDescription() << '\t'
00263               << i->getDates() << '\t' << endl;
00264       }
00265     }
00266 
00267     // Close the output file
00268     textoutput.close();
00269   }
00270   catch (...)
00271   {
00272     if (textoutput.is_open())
00273       textoutput.close();
00274     Py_BLOCK_THREADS;
00275     PythonType::evalException();
00276     return NULL;
00277   }
00278   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00279   return Py_BuildValue("");
00280 }
00281 
00282 
00283 //
00284 // MOVE OPERATIONPLAN
00285 //
00286 
00287 DECLARE_EXPORT CommandMoveOperationPlan::CommandMoveOperationPlan
00288 (OperationPlan* o) : opplan(o), firstCommand(NULL)
00289 {
00290   if (!o)
00291   {
00292     originalqty = 0;
00293     return;
00294   }
00295   originalqty = opplan->getQuantity();
00296   originaldates = opplan->getDates();
00297 
00298   // Construct a subcommand for all suboperationplans
00299   for (OperationPlan::iterator x(o); x != o->end(); ++x)
00300     if (x->getOperation() != OperationSetup::setupoperation)
00301     {
00302       CommandMoveOperationPlan *n = new CommandMoveOperationPlan(o);
00303       n->owner = this;
00304       if (firstCommand)
00305       {
00306         n->next = firstCommand;
00307         firstCommand->prev = n;
00308       }
00309       firstCommand = n;
00310     }
00311 }
00312 
00313 
00314 DECLARE_EXPORT CommandMoveOperationPlan::CommandMoveOperationPlan
00315 (OperationPlan* o, Date newstart, Date newend, double newQty)
00316   : opplan(o), firstCommand(NULL)
00317 {
00318   if (!opplan) return;
00319 
00320   // Store current settings
00321   originalqty = opplan->getQuantity();
00322   if (newQty == -1.0) newQty = originalqty;
00323   originaldates = opplan->getDates();
00324 
00325   // Update the settings
00326   assert(opplan->getOperation());
00327   opplan->getOperation()->setOperationPlanParameters(
00328     opplan, newQty, newstart, newend
00329   );
00330 
00331   // Construct a subcommand for all suboperationplans
00332   for (OperationPlan::iterator x(o); x != o->end(); ++x)
00333     if (x->getOperation() != OperationSetup::setupoperation)
00334     {
00335       CommandMoveOperationPlan *n = new CommandMoveOperationPlan(o);
00336       n->owner = this;
00337       if (firstCommand)
00338       {
00339         n->next = firstCommand;
00340         firstCommand->prev = n;
00341       }
00342       firstCommand = n;
00343     }
00344 }
00345 
00346 
00347 DECLARE_EXPORT void CommandMoveOperationPlan::redo()  // @todo not implemented
00348 {
00349 }
00350 
00351 
00352 DECLARE_EXPORT void CommandMoveOperationPlan::restore(bool del)
00353 {
00354   // Restore all suboperationplans and (optionally) delete the subcommands
00355   for (Command *c = firstCommand; c; )
00356   {
00357     CommandMoveOperationPlan *tmp = static_cast<CommandMoveOperationPlan*>(c);
00358     tmp->restore(del);
00359     c = c->next;
00360     if (del) delete tmp;
00361   }
00362 
00363   // Restore the original dates
00364   if (!opplan) return;
00365   opplan->getOperation()->setOperationPlanParameters(
00366     opplan, originalqty, originaldates.getStart(), originaldates.getEnd()
00367   );
00368 }
00369 
00370 
00371 //
00372 // DELETE OPERATIONPLAN
00373 //
00374 
00375 DECLARE_EXPORT CommandDeleteOperationPlan::CommandDeleteOperationPlan
00376 (OperationPlan* o) : opplan(o)
00377 {
00378   // Validate input
00379   if (!o) return;
00380 
00381   // Avoid deleting locked operationplans
00382   if (o->getLocked())
00383   {
00384     opplan = NULL;
00385     throw DataException("Can't delete a locked operationplan");
00386   }
00387 
00388   // Delete all flowplans and loadplans, and unregister from operationplan list
00389   redo();
00390 }
00391 
00392 
00393 //
00394 // DELETE MODEL
00395 //
00396 
00397 
00398 DECLARE_EXPORT PyObject* eraseModel(PyObject* self, PyObject* args)
00399 {
00400   // Pick up arguments
00401   PyObject *obj = NULL;
00402   int ok = PyArg_ParseTuple(args, "|O:erase", &obj);
00403   if (!ok) return NULL;
00404 
00405   // Validate the argument
00406   bool deleteStaticModel = false;
00407   if (obj) deleteStaticModel = PythonObject(obj).getBool();
00408 
00409   // Execute and catch exceptions
00410   Py_BEGIN_ALLOW_THREADS   // Free Python interpreter for other threads
00411   try
00412   {
00413     if (deleteStaticModel)
00414     {
00415       // Delete all entities.
00416       // The order is chosen to minimize the work of the individual destructors.
00417       // E.g. the destructor of the item class recurses over all demands and
00418       // all buffers. It is much faster if there are none already.
00419       Demand::clear();
00420       Operation::clear();
00421       Buffer::clear();
00422       Resource::clear();
00423       SetupMatrix::clear();
00424       Location::clear();
00425       Customer::clear();
00426       Calendar::clear();
00427       Solver::clear();
00428       Item::clear();
00429       // The setup operation is a static singleton and should always be around
00430       OperationSetup::setupoperation = Operation::add(new OperationSetup("setup operation"));
00431     }
00432     else
00433       // Delete the operationplans only
00434       for (Operation::iterator gop = Operation::begin();
00435           gop != Operation::end(); ++gop)
00436         gop->deleteOperationPlans();
00437   }
00438   catch (...)
00439   {
00440     Py_BLOCK_THREADS;
00441     PythonType::evalException();
00442     return NULL;
00443   }
00444   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00445   return Py_BuildValue("");
00446 }
00447 
00448 
00449 //
00450 // PRINT MODEL SIZE
00451 //
00452 
00453 
00454 DECLARE_EXPORT PyObject* printModelSize(PyObject* self, PyObject* args)
00455 {
00456   // Free Python interpreter for other threads
00457   Py_BEGIN_ALLOW_THREADS
00458 
00459   // Execute and catch exceptions
00460   size_t count, memsize;
00461   try
00462   {
00463 
00464     // Intro
00465     logger << endl << "Size information of frePPLe " << PACKAGE_VERSION
00466         << " (" << __DATE__ << ")" << endl << endl;
00467 
00468     // Print current locale
00469 #if defined(HAVE_SETLOCALE) || defined(_MSC_VER)
00470     logger << "Locale: " << setlocale(LC_ALL,NULL) << endl << endl;
00471 #else
00472     logger << endl;
00473 #endif
00474 
00475     // Print loaded modules
00476     Environment::printModules();
00477 
00478     // Print the number of clusters
00479     logger << "Clusters: " << HasLevel::getNumberOfClusters()
00480         << " (hanging: " << HasLevel::getNumberOfHangingClusters() << ")"
00481         << endl << endl;
00482 
00483     // Header for memory size
00484     logger << "Memory usage:" << endl;
00485     logger << "Model        \tNumber\tMemory" << endl;
00486     logger << "-----        \t------\t------" << endl;
00487 
00488     // Plan
00489     size_t total = Plan::instance().getSize();
00490     logger << "Plan         \t1\t"<< Plan::instance().getSize() << endl;
00491 
00492     // Locations
00493     memsize = 0;
00494     for (Location::iterator l = Location::begin(); l != Location::end(); ++l)
00495       memsize += l->getSize();
00496     logger << "Location     \t" << Location::size() << "\t" << memsize << endl;
00497     total += memsize;
00498 
00499     // Customers
00500     memsize = 0;
00501     for (Customer::iterator c = Customer::begin(); c != Customer::end(); ++c)
00502       memsize += c->getSize();
00503     logger << "Customer     \t" << Customer::size() << "\t" << memsize << endl;
00504     total += memsize;
00505 
00506     // Buffers
00507     memsize = 0;
00508     for (Buffer::iterator b = Buffer::begin(); b != Buffer::end(); ++b)
00509       memsize += b->getSize();
00510     logger << "Buffer       \t" << Buffer::size() << "\t" << memsize << endl;
00511     total += memsize;
00512 
00513     // Setup matrices
00514     memsize = 0;
00515     for (SetupMatrix::iterator s = SetupMatrix::begin(); s != SetupMatrix::end(); ++s)
00516       memsize += s->getSize();
00517     logger << "Setup matrix \t" << SetupMatrix::size() << "\t" << memsize << endl;
00518     total += memsize;
00519 
00520     // Resources
00521     memsize = 0;
00522     for (Resource::iterator r = Resource::begin(); r != Resource::end(); ++r)
00523       memsize += r->getSize();
00524     logger << "Resource     \t" << Resource::size() << "\t" << memsize << endl;
00525     total += memsize;
00526 
00527     // Operations, flows and loads
00528     size_t countFlows(0), memFlows(0), countLoads(0), memLoads(0);
00529     memsize = 0;
00530     for (Operation::iterator o = Operation::begin(); o != Operation::end(); ++o)
00531     {
00532       memsize += o->getSize();
00533       for (Operation::flowlist::const_iterator fl = o->getFlows().begin();
00534           fl != o->getFlows().end(); ++ fl)
00535       {
00536         ++countFlows;
00537         memFlows += fl->getSize();
00538       }
00539       for (Operation::loadlist::const_iterator ld = o->getLoads().begin();
00540           ld != o->getLoads().end(); ++ ld)
00541       {
00542         ++countLoads;
00543         memLoads += ld->getSize();
00544       }
00545     }
00546     logger << "Operation    \t" << Operation::size() << "\t" << memsize << endl;
00547     logger << "Flow         \t" << countFlows << "\t" << memFlows  << endl;
00548     logger << "Load         \t" << countLoads << "\t" << memLoads  << endl;
00549     total += memsize + memFlows + memLoads;
00550 
00551     // Calendars (which includes the buckets)
00552     memsize = 0;
00553     for (Calendar::iterator cl = Calendar::begin(); cl != Calendar::end(); ++cl)
00554       memsize += cl->getSize();
00555     logger << "Calendar     \t" << Calendar::size() << "\t" << memsize  << endl;
00556     total += memsize;
00557 
00558     // Items
00559     memsize = 0;
00560     for (Item::iterator i = Item::begin(); i != Item::end(); ++i)
00561       memsize += i->getSize();
00562     logger << "Item         \t" << Item::size() << "\t" << memsize  << endl;
00563     total += memsize;
00564 
00565     // Demands
00566     memsize = 0;
00567     for (Demand::iterator dm = Demand::begin(); dm != Demand::end(); ++dm)
00568       memsize += dm->getSize();
00569     logger << "Demand       \t" << Demand::size() << "\t" << memsize  << endl;
00570     total += memsize;
00571 
00572     // Operationplans
00573     size_t countloadplans(0), countflowplans(0);
00574     memsize = count = 0;
00575     for (OperationPlan::iterator j = OperationPlan::begin();
00576         j!=OperationPlan::end(); ++j)
00577     {
00578       ++count;
00579       memsize += sizeof(*j);
00580       countloadplans += j->sizeLoadPlans();
00581       countflowplans += j->sizeFlowPlans();
00582     }
00583     total += memsize;
00584     logger << "OperationPlan\t" << count << "\t" << memsize << endl;
00585 
00586     // Flowplans
00587     memsize = countflowplans * sizeof(FlowPlan);
00588     total +=  memsize;
00589     logger << "FlowPlan     \t" << countflowplans << "\t" << memsize << endl;
00590 
00591     // Loadplans
00592     memsize = countloadplans * sizeof(LoadPlan);
00593     total +=  memsize;
00594     logger << "LoadPlan     \t" << countloadplans << "\t" << memsize << endl;
00595 
00596     // Problems
00597     memsize = count = 0;
00598     for (Problem::const_iterator pr = Problem::begin(); pr!=Problem::end(); ++pr)
00599     {
00600       ++count;
00601       memsize += pr->getSize();
00602     }
00603     total += memsize;
00604     logger << "Problem      \t" << count << "\t" << memsize << endl;
00605 
00606     // TOTAL
00607     logger << "Total        \t\t" << total << endl << endl;
00608   }
00609   catch (...)
00610   {
00611     Py_BLOCK_THREADS;
00612     PythonType::evalException();
00613     return NULL;
00614   }
00615   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00616   return Py_BuildValue("");
00617 }
00618 
00619 } // end namespace

Documentation generated for frePPLe by  doxygen