//---------------------------------------------------------------------------- // Copyright (C) 2002, 2003 Humboldt-Universitaet zu Berlin // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //---------------------------------------------------------------------------- #ifdef _MSC_VER #pragma warning(disable:4530) // exception handling disabled #pragma warning(disable:4786) // 255 character truncation of debug information #endif /* // Beispiel 4: Hafenabfertigung mit Gezeiten #include "odem.h" ODEMx requires different include files than ODEM. The most simple solution is to include odemx.h. This file in turn includes other header from ODEMx. All classes of ODEMx are placed in the namespace ODEMx. In this simple example it is safe to use the whole namespace. */ #include <odemx/odemx.h> using namespace odemx; /* #ifdef _USE_GL #include "grtrace.h" #endif ODEMx does not support the GrTrace from ODEM. In ODEMx all model components require a pointer to the simulation. In general a user would provide a class for its special simulation which would inherit the ODEMx Simulation class. But for convenience ODEMx also contains a default simulation class. The function getDefaultSimulation() returns a pointer to an object of this class. */ Simulation* sim = getDefaultSimulation(); /* The names of the following classes have not been changed between ODEM and ODEMx. */ Res *tugs; // Schlepper Res *jetties; // Anlegeplaetze Condq *dockq; Rdist *next, *discharge; /* class Boat : public Discrete { public: int main (); Boat() : Discrete("boat"){} }; The ODEM base class Discrete for active model components has been replaced by the class Process in ODEMx. As in ODEM a user has to provide an implementation of the function virtual int main(). The constructor of Process requires, in addition to a name, a pointer to the simulation class. Another difference between ODEM and ODEMx is, that call-backs used for coding conditions or selections are member-functions (bool cond1()). */ class Boat : public Process { public: int main (); Boat() : Process(sim, "boat"){} bool cond1(); }; /* bool cond1(); */ int Boat::main() { // im Dock jetties->acquire(1); /* dockq->waituntil(cond1); The interface of Condq has changed. In this example we have to use wait(...) instead of waituntil(...). The cast is required because of the decision to use member functions for call-backs. We think the advantages outweigh the disadvantages of this cast. */ dockq->wait((Condition)&Boat::cond1); tugs->acquire(2); /* hold(2.0); Most scheduling functions have been changed between ODEM and ODEMx. hold() for instance is now replaced by a holdFor(). */ holdFor(2.0); tugs->release(2); dockq->signal(); // Loeschen der Ladung /* hold(discharge->sample()); */ holdFor(discharge->sample()); // ablegen tugs->acquire(1); /* hold (2.0); */ holdFor(2.0); tugs->release(1); jetties->release(1); dockq->signal(); return 0; } /* class Tide : public Discrete { public: static bool low; Tide(): Discrete("tide") {} int main (); (see the comments for Boat) }; */ class Tide : public Process { public: static bool low; Tide(): Process(sim, "tide") {} int main (); }; bool Tide::low = false; /* bool cond1() { (see the comments for Boat) */ bool Boat::cond1() { /* return (tugs->avail() >=2) && !Tide::low; The function avail() is replaced by getTokenNumber() in ODEMx. */ return (tugs->getTokenNumber() >=2) && !Tide::low; } int Tide::main() { for (;;) { // low low = true; /* hold(4.0); */ holdFor(4.0); low = false; dockq->signal(); // high /* hold(9.0); */ holdFor(9.0); } return 0; } /* class Arrival : public Discrete { public: Boat *b; Arrival(): Discrete("arrival") {} int main (); }; (see the comments for Boat) */ class Arrival : public Process { public: Boat *b; Arrival(): Process(sim, "arrival") {} int main (); }; int Arrival::main() { for (;;) { b = new Boat; /* b->start(NOW); hold(next->sample()); The function start() is not available in ODEMx. In ODEMx any hold* or activate* function can be used to start a new process. */ b->hold(); holdFor(next->sample()); } return 0; } int main(unsigned int argc, const char* argv[]) { /* InitializeOdemLib(argc, argv); #ifdef _USE_GL trace().addClient(new GrTrace); #endif trace().start(); It is not necessary to initialise ODEMx. The trace system has changed between ODEM and ODEMx. The trace management is done by the simulation class. A new trace is added with the function addConsumer(...). The trace is controlled with startTrace(), stopTrace(), pauseTrace() and continueTrace(). HtmlTrace logs the simulation events in a html file. It also provides a simple filter to reduce the output. Without a filter the ODEMx trace logs much more events than its predecessor in ODEM. In this example the filter is set to produce an ODEM-like output. In ODEMx several reports are available in one simulation to the cost of explicitly creating report objects (the class HtmlReport is provided by ODEMx) and registering model components to the different reports. The results of this simulation can be found in the files 'Port2_Trace.html' and 'Port2_Report.html'. Trace and report of the original ODEM version have been added to the ODEMx package for you to compare output and results. They can be found along with the Port2.cpp file ('Port2_Trace.txt' and 'Port2_Report.txt'). */ HtmlTrace trace(sim, "Port2_Trace.html"); HtmlReport report(sim, "Port2_Report.html"); trace.setFilter("all; mtn:changeState, changeExTime, create, time,\ execute process, init, execute, changeTokenNumber,\ current process, run until, sleep"); sim->addConsumer(&trace); sim->startTrace(); Arrival *a = new Arrival; Tide *t = new Tide; /* next = new Negexp("next boat", 0.1); discharge = new Normal("discharge", 14.0, 3.0); tugs = new Res("tugs", 3); jetties = new Res("jetties", 2); dockq = new Condq("dockq"); As already mentioned, in ODEMx most model components require a pointer to an object of the simulation class. Res in addition does need a maximum token number which can be larger than the initial number of available token. */ next = new Negexp(sim, "next boat", 0.1); discharge = new Normal(sim, "discharge", 14.0, 3.0); tugs = new Res(sim, "tugs", 3, 3); jetties = new Res(sim, "jetties", 2, 2); dockq = new Condq(sim, "dockq"); report.addProducer(next); report.addProducer(discharge); report.addProducer(tugs); report.addProducer(jetties); report.addProducer(dockq); /* a->start(NOW); t->start(DELAY,1); main_Discrete()->hold(50.0); (see Arrival::main comments as well) In ODEMx the global main function is not integrated as a process. The simulation control is instead realised by the functions run(), runUntil(...) and step(). */ a->activate(); t->activateIn(1); sim->runUntil(50.0); /* trace().pause(); */ sim->pauseTrace(); /* main_Discrete()->hold(28.0*24.0-50.0); */ sim->runUntil(28.0*24.0); /* report(); The function generateReport() has to be called for every report. Registered model components mustn't be deleted because generateReport() gathers data from them. */ report.generateReport(); return 0; }