Exemple 2 : le carrefour



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;isize();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 ca ENTREE 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%