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

Documentation generated for frePPLe by  doxygen