![]()
Il s'agit de simuler le trafic dans un carrefour giratoire à N voies d'accès. Le carrefour comporte N tronçons d'échange (TE[i]) par où entrent et sortent des voitures, et N tronçons internes (TI[i]) par où transitent les voitures. D'un tronçon interne, une voiture passe obligatoirement au tronçon d'échange du secteur suivant. D'un tronçon d'échange, une voiture peut soit sortir du carrefour, soit passer au tronçon interne du même secteur. Une voiture qui désire sortir par sa voie d'entrée doit faire un tour complet.
Afin d'assurer le bon fonctionnement du carrefour, au plus maxEchange voitures peuvent se trouver dans un même tronçon d'échange, et au plus maxInterne voitures peuvent se trouver dans un même tronçon interne. Les dépassements ne sont donc pas autorisés si maxEchange = 1 ou maxInterne = 1.
Priorité est donnée aux voitures déjà dans le carrefour. Une voiture désirant entrer dans le carrefour par la voie i ne peut le faire que si le tronçon d'échange TE[i] et le tronçon interne TI[i-1] sont libres.
Lorsqu'une condition pour entrer dans le carrefour ou pour y avancer n'est pas satisfaite, cette action est différée. La précondition ne sera examinée à nouveau qu'après un certain délai.
Une voiture arrive sur le carrefour et le quitte sur des voies d'entrée et de sortie aléatoires et indépendantes. L'écart entre deux arrivées varie uniformément entre 0 et intensité secondes. Chaque voiture possède sa propre vitesse, spécifiée par la durée du passage dans un tronçon (d'échange ou interne). Cette durée est choisie aléatoirement (et uniformément) entre 15 et 30 secondes.
Fichier : UserEntity.cc
#include "UserEntity.h" #include "UserConstantDescriptor.h" #include "UserVariableDescriptor.h" #include "UserTypes.h" Car::Car() { SetMetaClass(VOITURE); //SetParentClassId(O_ENTITY); // pour mémoire AddInstanceToClass(); SuperSetClassIds(TRONCON, OUTSIDE); Descriptor* pD; pD = new NumeroEntree(); AddConstantDescriptor(pD); pD = new NumeroSortie(); AddConstantDescriptor(pD); pD = new DureeDansTroncon(); AddConstantDescriptor(pD); pD = new EstDans(); AddVariableDescriptor(pD); }; Carrefour::Carrefour() { SetMetaClass(CARREFOUR, "carrefour"); //SetParentClassId(O_ENTITY); AddInstanceToClass(); ElementClassId(SECTEUR); Descriptor* pD; pD = new NombreSecteurs(); AddConstantDescriptor(pD); pD = new IntensiteArrivees(); AddConstantDescriptor(pD); pD = new DelaiExamen(); AddConstantDescriptor(pD); }; Systeme::Systeme() { SetMetaClass(SYSTEME, "systeme"); //SetParentClassId(O_ENTITY); AddInstanceToClass(); AddComponentClassId(CARREFOUR); AddComponentClassId(OUTSIDE); }; Outside::Outside() { SetMetaClass(OUTSIDE, "outside"); //SetParentClassId(O_ENTITY); AddInstanceToClass(); ElementClassId(VOITURE); }; Secteur::Secteur() { SetMetaClass(SECTEUR, "secteur"); //SetParentClassId(O_ENTITY); AddInstanceToClass(); SuperSetClassId(CARREFOUR); AddComponentClassId(TRONCON_ECHANGE); AddComponentClassId(TRONCON_INTERNE); Descriptor* pD; pD = new Numero(); AddConstantDescriptor(pD); pD = new NombreCar(); AddVariableDescriptor(pD); };
Constructeur d'instances de voitures.
Construction et attribution des descripteurs ... constants (voies d'entrée et de sortie, durée du passage au tronçon suivant). ... et variables (position dans le carrefour).
Constructeur d'instances de carrefours.
Les éléments d'un carrefour sont des secteurs. Construction et attribution des descripteurs constants (nombre de secteurs et intensité des arrivées de voiture, délai de ré-examen des préconditions pour entrer ou pour avancer). Constructeur de l'instance de système. Constructeur de l'instance pour l'environnement. Constructeur d'instances de secteurs. Un secteur est composé d'un tronçon d'échange et d'un tronçon interne. Construction et attribution des descripteurs constants (le numéro).
Fichier : UserEntity.cc (suite)
Troncon::Troncon() { SetMetaClass(TRONCON); //SetParentClassId(O_ENTITY); AddInstanceToClass(); ElementClassId(VOITURE); }; TronconEchange::TronconEchange() { SetMetaClass(TRONCON_ECHANGE); //SetParentClassId(TRONCON); AddInstanceToClass(); Descriptor* pD; pD = new Numero(); AddConstantDescriptor(pD); pD = new NbMaxCar(); AddConstantDescriptor(pD); pD = new NombreCar(); AddVariableDescriptor(pD); }; TronconInterne::TronconInterne() { SetMetaClass(TRONCON_INTERNE); //SetParentClassId(TRONCON); AddInstanceToClass(); Descriptor* pD; pD = new Numero(); AddConstantDescriptor(pD); pD = new NbMaxCar(); AddConstantDescriptor(pD); pD = new NombreCar(); AddVariableDescriptor(pD); };
Constructeur d'instances de tronçons d'échange. Construction et attribution des descripteurs constants (le numéro et le nombre maximum de voitures). Construction et attribution des descripteurs variables (le nombre courant de voitures). Constructeur d'instances de tronçons internes. Construction et attribution des descripteurs constants (le numéro et le nombre maximum de voitures). Construction et attribution des descripteurs variables (le nombre courant de voitures).
Fichier : UserDescValueSpec.cc
#include "UserDescValueSpec.h" DomainNombreSecteurs::DomainNombreSecteurs() : DescIntValueSpec(NOMBRE_SECTEURS, IN) { ClassName("domainNombreSecteurs"); AddSubDomain(1, 4); SortOnLowBound(); ReduceToDisjunction(); };
Construction d'un domaine de valeurs... .. pour le descripteur NombreSecteurs. Le domaine est l'intervalle [1, 4].
Fichier : UserConstantDescriptor.cc
#include "UserConstantDescriptor.h" NumeroEntree::NumeroEntree() : IntConstantDescriptor(NUMERO_ENTREE, "numeroEntree") {}; NumroSortie::NumeroSortie() : IntConstantDescriptor(NUMERO_SORTIE, "numeroSortie") {}; NombreSecteurs::NombreSecteurs() : IntConstantDescriptor(NOMBRE_SECTEURS, "nombreSecteurs") { DomainNombreSecteurs* p = new DomainNombreSecteurs(); SetDomain(p); }; Numero::Numero() : IntConstantDescriptor(NUMERO, "numero") {}; NbMaxCar::NbMaxCar() : IntConstantDescriptor(NB_MAX_CAR, "nbMaxCar") {}; IntensiteArrivees::IntensiteArrivees() : IntConstantDescriptor(INTENSITE_ARRIVEES) { ClassName("intensiteArrivees"); }; DelaiExamen::DelaiExamen() : IntConstantDescriptor(DELAI_EXAMEN, "delaiExamen") {}; DureeDansTroncon::DureeDansTroncon() : IntConstantDescriptor(DUREE_DANS_TRONCON) { ClassName("dureeDansTroncon"); };
Constructeurs des classes de descripteurs constants. On fait appel au constructeur de la classe de base, avec le symbole de classe en argument, ou avec le symbole et le nom de classe. On donne un domaine de valeurs.
Fichier : UserVariableDescriptor.cc
#include "UserVariableDescriptor.h" NombreCar::NombreCar() : IntVariableDescriptor(NOMBRE_CAR, "nombreCar") {}; EstDans::EstDans() : EntityVariableDescriptor(EST_DANS, "estDans") {};
Constructeurs des classes de descripteurs variables.
Fichier : UserFunction.cc
#include "UserFunction.h" int gMyTrace = FALSE; void InitSimulation() { // idem exemple Toboggan } void App_InstallMetaClasses() { App_MakeClassIdToCharTab(); App_MakeDescIdToCharTab(); MetaClass* pMC; pMC = CreateMetaClass(CARREFOUR, "carrefour"); pMC->SetParentClassId(O_ENTITY); pMC = CreateMetaClass(OUTSIDE, "outside"); pMC->SetParentClassId(O_ENTITY); // ... } void App_ParseMainArguments (int argc, char* argv[]) { if (argc < 6) { cerr << "Usage : main paramètres init_Sim spec_sorties structure structure directives\n" << " [-m(émoire)] [-v(erbose)] [-t(race)]\n"; exit(0); }; for (int i=6;i < argc;i++) { if(!strcmp(argv[i],"-v")) gTraceEventMode=TRACE_EVENT_ON; if(!strcmp(argv[i],"-m")) gTraceNewDelMode=TRACE_NEWDEL_ON; if(!strcmp(argv[i],"-t")) gMyTrace = TRUE; }; }; void App_AssignInstantiators() { // idem exemple Toboggan } Entity* App_NewEntityFromString(char* nom) { if (!strcmp(nom, "entreeCarrefour")) return new EntreeCarrefour(); if (!strcmp(nom, "entreeEchange")) return new EntreeEchange(); if (!strcmp(nom, "entreeInterne")) return new EntreeInterne(); if (!strcmp(nom, "sortieCarrefour")) return new SortieCarrefour(); return NULL; }; Process* App_NewProcessFromString(char* nom) { if (!strcmp(nom, "entreeCarrefour")) return new EntreeCarrefour(); if (!strcmp(nom, "entreeEchange")) return new EntreeEchange(); if (!strcmp(nom, "entreeInterne")) return new EntreeInterne(); if (!strcmp(nom, "sortieCarrefour")) return new SortieCarrefour(); return NULL; }; Event* App_NewEventFromString(char* nom) { if (!strcmp(nom, "eventArriveeDansCarrefour")) return new EventArriveeDansCarrefour(); if (!strcmp(nom, "eventAvanceeDansCarrefour")) return new EventAvanceeDansCarrefour(); if (!strcmp(nom, "eventSortieDuCarrefour")) return new EventSortieDuCarrefour(); return NULL; }; Carrefour* GetCarrefour() { Entity* pObj = pCurrentSim->SimulatedEntity(); return (Carrefour*)(pObj->GetComponent(CARREFOUR)); }; ...
La variable gMyTrace est déclarée extern dans UserTypes.h Fonction d'initialisation de la simulation: Réalisation d'une fonction déclarée dans DIESE : initialisation des informations sur les sous-classes d'entités. Définition de la fonction d'interprétation des arguments du programme principal. Réalisation d'une fonction déclarée dans DIESE : déclaration des fonctions d'instanciation d'objets à partir de leur nom ou symbole de classe. Fonction d'instanciation des entités à partir ... ... du nom de classe. Fonction d'instanciation des processus à partir ... ... du nom de classe. Fonction d'instanciation des événements à partir ... ... du nom de classe. Une des fonctions spécifiques de l'application, utilisée dans le code des processus.
Fichier : UserDiscreteProcess.cc
#include "UserDiscreteProcess.h" int entreeCarrefour_processPrecondition_Body(ProcessMethod* pM) { Process* pP = pM->DescribedDiscreteProcess(); Entity* pCarrefour = GetCarrefour(); Entity* pCar = pP->ProcessedEntity(); int numeroSecteur = pCar->GetIntValue(NUMERO_ENTREE); Entity* pSecteur = pCarrefour->GetElement(numeroSecteur); Entity* pTE = pSecteur->GetComponent(TRONCON_ECHANGE); if (pTE->GetIntValue(NOMBRE_CAR) > 0) return 0; else { int nbSecteurs = pCarrefour->GetIntValue(NOMBRE_SECTEURS); int i = (numeroSecteur-1+nbSecteurs)%nbSecteurs; pSecteur = pCarrefour->GetElement(i); Entity* pTI = pSecteur->GetComponent(TRONCON_INTERNE); if (pTI->GetIntValue(NOMBRE_CAR) > 0) return 0; else return 1; }; }; int entreeCarrefour_processPostponementDelay_Body(ProcessMethod* pM) { DiscreteProcess* pDP = pM->DescribedDiscreteProcess(); BasicEntity* pEntreeCarrefour = pDP->ProcessedEntity(); return GetIntParameterValue("voiture", "delaiExamen"); }; void entreeCarrefour_execProcess_Body(ProcessMethod* pM) { Process* pP = pM->DescribedDiscreteProcess(); Entity* pCarrefour = GetCarrefour(); Entity* pOutside = GetOutside(); Entity* pCar = pP->ProcessedEntity(); int numeroSecteur = pCar->GetIntValue(NUMERO_ENTREE); if(gMyTrace) printf("\nt = %d --> ENTREE carrefour, %s (secteur : %d)", pCurrentSim->Clock(), pCar->InstanceName(), numeroSecteur); Entity* pSecteur = pCarrefour->GetElement(numeroSecteur); Entity* pTE = pSecteur->GetComponent(TRONCON_ECHANGE); Entity* pTI = pSecteur->GetComponent(TRONCON_INTERNE); pTE->IncrValue(NOMBRE_CAR); pSecteur->IncrValue(NOMBRE_CAR); pCar->SetEntityValue(EST_DANS, pTE); pOutside->RemoveElement(pCar); pTE->AddElement(pCar); Process* pDP = new EntreeInterne(); pDP->ProcessedEntity(pCar); int date = pCurrentSim->Clock()+pCar->GetIntValue(DUREE_DANS_TRONCON); Event* pEv = new EventAvanceeDansCarrefour(); pEv->SetOccurrenceClockTime(date); pEv->SetPriorityDegree(0); pEv->AddProcessAction(pDP, EXEC); if(! pCurrentSim->InsertInAgendaEvents(pEv)) pEv->DeleteInDepth(); }; EntreeCarrefour::EntreeCarrefour() : DiscreteProcess(ENTREE_CARREFOUR, "entreeCarrefour") { SetPrecondition(entreeCarrefour_processPrecondition_Body); SetPostponementDelay(entreeCarrefour_processPostponementDelay_Body); SetExec(entreeCarrefour_execProcess_Body); };
Précondition pour entrer dans le carrefour. L'entrée est différée s'il y a des voitures dans le tronçon d'échange de la voie d'entrée, ... ou dans le tronçon interne du secteur précédent. Définition du calcul du délai imposé avant de tenter d'entrer à nouveau dans le carrefour Définition du processus d'entrée dans le carrefour. On ajoute une voiture dans le tronçon d'échange, et on dit que la voiture est dans ce tronçon. Création d'un événement d'entrée dans le tronçon interne suivant, après un délai correspondant à la vitesse de la voiture. Constructeur des instances de processus d'entrée dans le carrefour. Le délai de re-examen est une constante caractéristique du carrefour.
Fichier : UserDiscreteProcess.cc (suite 1)
int entreeEchange_processPrecondition_Body(ProcessMethod* pM) { Process* pP = pM->DescribedDiscreteProcess(); Entity* pCarrefour = GetCarrefour(); int nbSecteurs = pCarrefour->GetIntValue(NOMBRE_SECTEURS); Entity* pCar = pP->ProcessedEntity(); Entity* pTI = pCar->GetEntityValue(EST_DANS); int numeroSecteur = (pTI->GetIntValue(NUMERO)+1)%nbSecteurs; Entity* pSecteur = pCarrefour->GetElement(numeroSecteur); Entity* pTE = pSecteur->GetComponent(TRONCON_ECHANGE); if (pTE->GetIntValue(NOMBRE_CAR) < pTE->GetIntValue(NB_MAX_CAR)) return 1; else return 0; }; void entreeEchange_execProcess_Body(ProcessMethod* pM) { Process* pP = pM->DescribedDiscreteProcess(); Entity* pCarrefour = GetCarrefour(); int nbSecteurs = pCarrefour->GetIntValue(NOMBRE_SECTEURS); Entity* pCar = pP->ProcessedEntity(); Entity* pTI = pCar->GetEntityValue(EST_DANS); int numeroOldSecteur = pTI->GetIntValue(NUMERO); Entity* pOldSecteur = pTI->GetSuperEntity(); int numeroNewSecteur = (numeroOldSecteur+1)%nbSecteurs; Entity* pNewSecteur = pCarrefour->GetElement(numeroNewSecteur); if(gMyTrace) printf("\nt = %d --- entrée dans un TE, %s (secteur : %d -> %d)", pCurrentSim->Clock(), pCar->InstanceName(), numeroOldSecteur, numeroNewSecteur); Entity* pTE = pNewSecteur->GetComponent(TRONCON_ECHANGE); pTI->DecrValue(NOMBRE_CAR); pTE->IncrValue(NOMBRE_CAR); pOldSecteur->DecrValue(NOMBRE_CAR); pNewSecteur->IncrValue(NOMBRE_CAR); pCar->SetEntityValue(EST_DANS, pTE); pTI->RemoveElement(pCar); pTE->AddElement(pCar); if (pTE->GetIntValue(NUMERO) == pCar->GetIntValue(NUMERO_SORTIE)) { Process* pDP = new SortieCarrefour(); pDP->ProcessedEntity(pCar); int date = pCurrentSim->Clock()+pCar->GetIntValue(DUREE_DANS_TRONCON); Event* pEv = new EventSortieDuCarrefour(); pEv->SetOccurrenceClockTime(date); pEv->SetPriorityDegree(0); pEv->AddProcessAction(pDP, EXEC); if(! pCurrentSim->InsertInAgendaEvents(pEv)) pEv->DeleteInDepth(); } else { Process* pDP = new EntreeInterne(); pDP->ProcessedEntity(pCar); int date = pCurrentSim->Clock()+pCar->GetIntValue(DUREE_DANS_TRONCON); Event* pEv = new EventAvanceeDansCarrefour(); pEv->SetOccurrenceClockTime(date); pEv->SetPriorityDegree(0); pEv->AddProcessAction(pDP, EXEC); if(! pCurrentSim->InsertInAgendaEvents(pEv)) pEv->DeleteInDepth(); }; }; EntreeEchange::EntreeEchange() : DiscreteProcess(ENTREE_ECHANGE, "entreeEchange") { SetPrecondition(entreeEchange_processPrecondition_Body); SetExec(entreeEchange_execProcess_Body); };
Précondition pour entrer dans un tronçon d'échange. L'entrée est acceptée s'il y a strictement moins de voitures que le maximum autorisé dans le tronçon. Définition du processus d'entrée dans un tronçon d'échange. On enlève une voiture du tronçon interne précédent, on ajoute une voiture dans le tronçon d'échange, et on dit que la voiture est dans ce tronçon. Selon qu'on a atteint ou pas la voie de sortie, création d'un événement de sortie du carrefour après un délai correspondant à la vitesse de la voiture. ou bien création d'un événement d'entrée dans le tronçon interne suivant, après un délai correspondant à la vitesse de la voiture. Constructeur des instances de processus d'entrée dans un tronçon d'échange.
Fichier : UserDiscreteProcess.cc (suite 2)
int entreeInterne_processPrecondition_Body(ProcessMethod* pM) { Process* pP = pM->DescribedDiscreteProcess(); Entity* pCar = pP->ProcessedEntity(); Entity* pTE = pCar->GetEntityValue(EST_DANS); Entity* pSecteur = pTE->GetSuperEntity(); Entity* pTI = pSecteur->GetComponent(TRONCON_INTERNE); if (pTI->GetIntValue(NOMBRE_CAR) < pTI->GetIntValue(NB_MAX_CAR)) return 1; else return 0; }; void entreeInterne_execProcess_Body(ProcessMethod* pM) { Process* pP = pM->DescribedDiscreteProcess(); Entity* pCar = pP->ProcessedEntity(); Entity* pTE = pCar->GetEntityValue(EST_DANS); Entity* pSecteur = pTE->GetSuperEntity(); if(gMyTrace) printf("\nt = %d --- entrée dans un TI, %s (secteur : %d)", pCurrentSim->Clock(), pCar->InstanceName(), pSecteur->GetIntValue(NUMERO)); Entity* pTI = pSecteur->GetComponent(TRONCON_INTERNE); pTE->DecrValue(NOMBRE_CAR); pTI->IncrValue(NOMBRE_CAR); pCar->SetEntityValue(EST_DANS, pTI); pTE->RemoveElement(pCar); pTI->AddElement(pCar); Process* pDP = new EntreeEchange(); pDP->ProcessedEntity(pCar); int date = pCurrentSim->Clock()+pCar->GetIntValue(DUREE_DANS_TRONCON); Event* pEv = new EventAvanceeDansCarrefour(); pEv->SetOccurrenceClockTime(date); pEv->SetPriorityDegree(0); pEv->AddProcessAction(pDP, EXEC); if(! pCurrentSim->InsertInAgendaEvents(pEv)) pEv->DeleteInDepth(); }; EntreeInterne::EntreeInterne() : DiscreteProcess(ENTREE_INTERNE, "entreeInterne") { SetPrecondition(entreeInterne_processPrecondition_Body); SetExec(entreeInterne_execProcess_Body); }; void sortieCarrefour_execProcess_Body(ProcessMethod* pM) { Process* pP = pM->DescribedDiscreteProcess(); Entity* pOutside = GetOutside(); Entity* pCar = pP->ProcessedEntity(); Entity* pTE = pCar->GetEntityValue(EST_DANS); int numeroSecteur = pTE->GetIntValue(NUMERO); Entity* pOldSecteur = pTE->GetSuperEntity(); if(gMyTrace) printf("\nt = %d <-- SORTIE carrefour, %s (secteur : %d)", pCurrentSim->Clock(),pCar->InstanceName(),numeroSecteur); pTE->DecrValue(NOMBRE_CAR); Entity* pSecteur = pTE->GetSuperEntity(); pSecteur->DecrValue(NOMBRE_CAR); pTE->RemoveElement(pCar); pCar->SetEntityValue(EST_DANS, NULL); pOutside->AddElement(pCar); }; SortieCarrefour::SortieCarrefour() : DiscreteProcess(SORTIE_CARREFOUR, "sortieCarrefour") { SetExec(sortieCarrefour_execProcess_Body); };
Précondition pour entrer dans un tronçon interne. L'entrée est acceptée s'il y a strictement moins de voitures que le maximum autorisé. Définition du processus d'entrée dans un tronçon interne. On enlève une voiture du tronçon d'échange précédent, on ajoute une voiture dans le tronçon interne, et on dit que la voiture est dans ce tronçon. Création d'un événement d'entrée dans le tronçon d'échange suivant, après un délai correspondant à la vitesse de la voiture. Constructeur des instances de processus d'entrée dans un tronçon interne. Définition du processus de sortie du carrefour. On enlève une voiture du tronçon d'échange. Constructeur des instances de processus de sortie du carrefour.
Fichier : UserEvent.cc
#include "UserEvent.h" #include "UserEntity.h" #include "UserDiscreteProcess.h" #include "UserTypes.h" #include "UserFunction.h" #include "CoreFunction.h" #include "Simulation.h" bool eventArriveeDansCarrefour_generateNextEvent_Body(EventMethod* pM) { Event* pCurrentEvent = pM->DescribedEvent(); Entity* pCarrefour = GetCarrefour(); int nbEntrees = pCarrefour->GetIntValue(NOMBRE_SECTEURS); int in = RandomInteger(nbEntrees); // entree en 0, 1, ..., nbE-1 int out = RandomInteger(nbEntrees); // sortie en 0, 1, ..., nbE-1 int duree = 15+RandomInteger(16); // entre 15 et 30 secondes Voiture* pCar = new Voiture(); // la prochaine voiture pCar->SetIntValue(NUMERO_ENTREE, in); pCar->SetIntValue(NUMERO_SORTIE, out); pCar->SetIntValue(DUREE_DANS_TRONCON, duree); int intensiteArrivees = pCarrefour->GetIntValue(INTENSITE_ARRIVEES); int delaiArrivee = RandomInteger(intensiteArrivees); Event* pNewEvent = pCurrentEvent->RawCopy(); int laDate = pCurrentSim->Clock()+delaiArrivee; pNewEvent->SetOccurrenceClockTime(laDate); pCurrentEvent->SetNextEvent(pNewEvent); Process* pNewProcess = pNewEvent->FirstProcess(); pNewProcess->ProcessedEntity(pCar); if(gMyTrace) { sprintf(gGlobalString, "***** en t = %d prochaine ARRIVEE %s (in : %d, out : %d, durée : %d)\n", laDate, pCar->InstanceName(), in, out, duree); } return true; }; EventArriveeDansCarrefour::EventArriveeDansCarrefour() { ClassName("eventArriveeDansCarrefour"); ClearListProcessAction (); AddProcessAction("entreeCarrefour", EXEC); HasPostConsequence(FALSE); IsAutoGenerate(TRUE); SetGenerateNextEvent(eventArriveeDansCarrefour_generateNextEvent_Body); }; EventAvanceeDansCarrefour::EventAvanceeDansCarrefour() { ClassName("eventAvanceeDansCarrefour"); ClearListProcessAction (); HasPostConsequence(FALSE); }; EventSortieDuCarrefour::EventSortieDuCarrefour() { ClassName("eventSortieDuCarrefour"); ClearListProcessAction (); HasPostConsequence(TRUE); SetPostConsequence(eventSortieDuCarrefour_eventPostConsequence_Body); };
Définition de la fonction d'autogénération d'un nouvel événement d'entrée dans le carrefour. On tire au hasard les voies d'entrée et de sortie, et la vitesse de la voiture. On construit la voiture et le processus. On tire au hasard la date d'arrivée. On crée le nouvel événement par copie de l'ancien. C'est la nouvelle voiture qui est l'objet du processus. Constructeur de base de l'événement. Affectation de la fonction d'autogénération définie ci-dessus. Constructeur de l'événement d'avancée dans le carrefour. Constructeur de l'événement de sortie du carrefour.
Fichier : UserEntitySpec.cc
#include "UserEntitySpec.h" SecteurSpec::SecteurSpec() : EntitySpec(SECTEUR) { ClassName("secteurSpec"); SetQuantificatorId(ALLENT); SetMode(RETURN_INSTANCES); IntQuantity(-9); AssignSelectorPredicate(secteurSpec_selectorPredicate_Body); }; bool secteurSpec_selectorPredicate_Body(EntitySpecMethod* pM) { bool result = false; Entity* pE = pM->GetEntityArgValue(CANDIDATEENTITY_ARGUMENT); if (pE->GetIntValue(NUMERO) > 0) result = true; else result = false; return result; };
Constructeur d'une spécification d'ensemble d'entités, pour sélectionner des secteurs particuliers (voir la fonction main). La sélection se fait à l'aide du prédicat ci-dessous, affecté ici à la méthode appropriée de la spécification. Corps de la méthode de sélection.
Fichier : UserTypes.h
enum App_ClassId { CARREFOUR = 201, OUTSIDE, SECTEUR, SYSTEME, TRONCON, TRONCON_ECHANGE, TRONCON_INTERNE, VOITURE } enum App_DescriptorId { DELAI_EXAMEN = 201, DUREE_DANS_TRONCON, EST_DANS, INTENSITE_ARRIVEES, NB_MAX_CAR, NOMBRE_CAR, NOMBRE_SECTEURS, NUMERO, NUMERO_ENTREE, NUMERO_SORTIE }; enum App_ProcessId { ENTREE_CARREFOUR = 1, ENTREE_ECHANGE, ENTREE_INTERNE, SORTIE_CARREFOUR };
Déclaration des symboles de classe utilisés dans le programme.
Fichier : sim0.par
// parametres du systeme carrefour ENTITE "carrefour" "nombre_entrees" <- 4; ENTITE "carrefour" "maxCarDansEchange" <- 1; ENTITE "carrefour" "maxCarDansInterne" <- 1; ENTITE "voiture" "intensiteArrivees" <- 60; ENTITE "voiture" "delaiExamen" <- 5;
Fichier : sim0.sim
// initialisation de la simulation du carrefour //TRACE PARSING; INITIALISATION SIMULATION UNITE_TPS SECOND; NB_UNITE_TPS 1; DATE_DEBUT 1 JAN 2000 12 0 0; DATE_FIN 1 JAN 2000 12 4 0; OUT_DIR "/home/durand/DIESE/KBS/bdiese/Carrefour/out/"; ;
Définition de l'unité de temps : toutes les indications de durée et de valeurs d'horloge sont implicitement en secondes. Le trafic est simulé 4 minutes à partir de midi. Si on demandait des sorties (outspec non vide), elles seraient dirigées dans le répertoire désigné ici.
Fichier : sim0.str
{i1} = < pi >< carrefour nombre_entrees >; {i2} = < pi >< carrefour maxCarDansEchange >; {i3} = < pi >< carrefour maxCarDansInterne >; {i4} = < pi >< voiture intensiteArrivees >; {i5} = < pi >< voiture delaiExamen >; + I carrefour grandRond, nombreSecteurs = {i1}; delaiExamen = {i5}; intensiteArrivees = {i4}; POUR i9 = (0) A ({i1} - 1) + E secteur, numero =: {i9}; nombreCar = 0; + C tronconEchange, numero =: {i9}; nombreCar = 0; nbMaxCar = {i2}; ; + C tronconInterne, numero =: {i9}; nombreCar = 0; nbMaxCar = {i3}; ; ; FIN POUR ; {i6} = RANDOM({i1}); {i7} = RANDOM({i1}); {i8} = 15 + RANDOM(16); + I voiture, numeroEntree = {i6}; numeroSortie = {i7}; dureeDansTroncon = {i8}; ; + I outside parc, <- E < I >< voiture, >; ; + I systeme, <- C < I ><, grandRond >; <- C < I ><, parc >; ; ENTITE_SIMULEE < I >< systeme, >; //************************************************************** + P "entreeCarrefour" pP ENTITE = < I >< voiture, >; ; //-------------------------------------------------------------- {i1} = RANDOM({i4}); + V "eventArriveeDansCarrefour" pV DATE_OCCUR = {i1}; PRIORITE = 0; ; //************************************************************** AFFICHER "***** en t = " {i1} " prochaine ARRIVEE " < I >< voiture, > " (in : " {i6} ", out : " {i7} ", duree : " {i8} ")";
Définition de paramètres locaux. Instanciation d'un carrefour, - Affectation de valeurs à ses descripteurs. -Construction de secteurs (nom suffixé par ``_0'', etc...), - Construction d'un seul tronçon d'échange, - Construction d'un seul tronçon interne. Tirage aléatoire des points d'entrée et de sortie, et de la vitesse. Instanciation d'une voiture, - Affectation de valeurs aléatoires ci-dessus. Instanciation de l'environnement du carrefour. Instanciation du système global avec deux composants. Le système est désigné comme l'entité simulée. Création d'un processus d'entrée dans le carrefour, portant sur la seule voiture instanciée. Création de l'événement d'entrée, ... à une date aléatoire, L'attachement d'un processus est réalisé dans lme constructeur. Affichage des informations sur cet événement.
Fichier : sim0.osp
Vide : pas de spécification de sortie.
Fichier : sim0.dir
RUN
Les autres directives sont directement codées dans la fonction main.
Fichier : main.cc
#include#include "B_diese.h" #include "UserTypes.h" #include "UserFunction.h" main (int argc, char* argv[]){ InitChrono(); StartChrono(); App_ParseMainArguments (argc, argv); ParseParameterFile(argv[1]); InitSimulation(); ParseSimulationFile(argv[2]); ParseOutputSpecFile(argv[3]); ParseStructureFile(argv[4]); ParseDirectiveFile(argv[5]); cout << "\n-------------------------"; PauseChrono(); MicroPrintChrono(); cout << "\ndurée exécution : " << gTimeString; CloseChrono(); cout << "\n-------------------------"; EntitySpec* pEntitySpec = new SecteurSpec(); DescIntValueSpec* pInSelector = new DescIntValueSpec(NOMBRE_CAR, IN, 1,2); pEntitySpec->AddDescValueSpec(pInSelector); pEntitySpec->Expand(); pEntityTab* expandedTab = pEntitySpec->GetExpansion(); cout << "\nnb instances = " << expandedTab->size() << endl; for(int i=0;i size();i++) { cout << (*expandedTab)[i]->InstanceName() << endl; } DeleteAll(); }
appel : voir la trace, ci-après. Interprétation des arguments de la ligne de commande. Lecture et exploitation des fichiers : - paramètres du système - initialisation de la simulation - structure du système - spécifications de sortie (vide) - directives (lancement de la simulation) A titre d'exemple de spécification d'ensemble d'entités, définition de l'ensemble des secteurs avec 1 ou 2 voitures. Il s'agit d'instances existantes et on les veut toutes ... ... si elles satisfont ce prédicat défini dans UserFunction. Pas besoin de fonction de calcul de l'effectif retourné. Pas besoin d'entité de référence. Création d'un domaine de valeurs à respecter. Son attachement à la spécification de l'ensemble d'entités. Génération de l'ensemble. Acces à la liste ainsi générée. Récupération de la mémoire non encore desallouée.
Trace d'une exécution :
main sim0.par sim0.sim sim0.osp sim0.str sim0.dir ***** en t = 17 prochaine ARRIVEE voiture_14 (in : 0, out : 0, duree : 15) t = 17 --> ENTREE carrefour, voiture_14 (secteur : 0) ***** en t = 61 prochaine ARRIVEE voiture_17 (in : 1, out : 2, durée : 15) t = 32 --- entrée dans un TI, voiture_14 (secteur : 0) t = 47 --- entrée dans un TE, voiture_14 (secteur : 0 -> 1) t = 62 --- entrée dans un TI, voiture_14 (secteur : 1) t = 66 --> ENTREE carrefour, voiture_17 (secteur : 1) ***** en t = 103 prochaine ARRIVEE voiture_18 (in : 2, out : 0, durée : 20) t = 77 --- entrée dans un TE, voiture_14 (secteur : 1 -> 2) t = 81 --- entrée dans un TI, voiture_17 (secteur : 1) t = 92 --- entrée dans un TI, voiture_14 (secteur : 2) t = 96 --- entrée dans un TE, voiture_17 (secteur : 1 -> 2) t = 107 --- entrée dans un TE, voiture_14 (secteur : 2 -> 3) t = 111 <-- SORTIE carrefour, voiture_17 (secteur : 2) t = 113 --> ENTREE caENTREE carrefour, voiture_19 (secteur : 3) ***** en t = 129 prochaine ARRIVEE voiture_20 (in : 0, out : 3, durée : 30) t = 133 --- entrée dans un TI, voiture_18 (secteur : 2) t = 137 --- entrée dans un TE, voiture_14 (secteur : 3 -> 0) t = 147 --- entrée dans un TI, voiture_19 (secteur : 3) t = 152 <-- SORTIE carrefour, voiture_14 (secteur : 0) t = 153 --- entrée dans un TE, voiture_18 (secteur : 2 -> 3) t = 168 --- entrée dans un TE, voiture_19 (secteur : 3 -> 0) t = 173 --- entrée dans un TI, voiture_18 (secteur : 3) t = 189 --- entrée dans un TI, voiture_19 (secteur : 0) t = 193 --- entrée dans un TE, voiture_18 (secteur : 3 -> 0) t = 210 --- entrée dans un TE, voiture_19 (secteur : 0 -> 1) t = 213 <-- SORTIE carrefour, voiture_18 (secteur : 0) t = 214 --> ENTREE carrefour, voiture_20 (secteur : 0) ***** en t = 226 prochaine ARRIVEE voiture_21 (in : 3, out : 2, durée : 18) t = 226 --> ENTREE carrefour, voiture_21 (secteur : 3) ***** en t = 229 prochaine ARRIVEE voiture_22 (in : 3, out : 0, durée : 29) t = 231 --- entrée dans un TI, voiture_19 (secteur : 1) t = 244 --- entrée dans un TI, voiture_20 (secteur : 0) ------------------------- durée exécution : 0s 016ms 583 ------------------------- nb instances = 2 secteur_5 secteur_11 ossau%