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

Documentation generated for frePPLe by  doxygen