|
|
Les agents `prestataires logistiques` sont définis dans le fichier `LogisticsServiceProvider.gaml`. Leur but principal est de gérer le réapprovisionnement de leurs clients. Puisqu'ils sont choisis par des agents destinataires, il est possible qu'un agent prestataire n'ait pas de client du tout, ou au contraire en ait plusieurs. De plus, ils peuvent gagner ou perdre des clients au cours de la simulation. Ils doivent donc gérer plusieurs situations : l'ajout d'un nouveau client, la perte d'un client existant, et le réapprovisionnement des bâtiments dont un prestataire a la charge (les entrepôts et les bâtiments associés aux clients).
|
|
|
Les agents `prestataires logistiques` sont définis dans le fichier `🆃 LogisticsServiceProvider.gaml`. Leur but principal est de gérer le réapprovisionnement de leurs clients. Puisqu'ils sont choisis par des agents destinataires, il est possible qu'un agent prestataire n'ait pas de client du tout, ou au contraire en ait plusieurs. De plus, ils peuvent gagner ou perdre des clients au cours de la simulation. Ils doivent donc gérer plusieurs situations : l'ajout d'un nouveau client, la perte d'un client existant, et le réapprovisionnement des bâtiments dont un prestataire a la charge (les entrepôts et les bâtiments associés aux clients).
|
|
|
|
|
|
# Ajout d'un nouveau client
|
|
|
|
|
|
Chaque prestataire gère un réseau d'approvisionnement. Ce réseau est constitué d'un, et un seul, fournisseur, d'un ou plusieurs entrepôt(s) de niveau national, d'un ou plusieurs entrepôt(s) de niveau local, et enfin du (ou des) bâtiment(s) associé(s) à son (ou ses) client(s). Ce réseau d'approvisionnement correspond à la variable `supplyChain`. Au sein de ce réseau, le fournisseur du prestataire est connecté aux entrepôts nationaux, eux-même connectés aux entrepôts locaux, eux-même connectés aux bâtiments des destinataires.
|
|
|
Chaque prestataire gère un réseau d'approvisionnement. Ce réseau est constitué d'un, et un seul, fournisseur, d'un ou plusieurs entrepôt(s) de niveau national, d'un ou plusieurs entrepôt(s) de niveau local, et enfin du (ou des) bâtiment(s) associé(s) à son (ou ses) client(s). Ce réseau d'approvisionnement correspond à la variable `🆅 supplyChain`. Au sein de ce réseau, le fournisseur du prestataire est connecté aux entrepôts nationaux, eux-même connectés aux entrepôts locaux, eux-même connectés aux bâtiments des destinataires.
|
|
|
|
|
|
L'ajout d'un nouveau client s'effectue via la fonction `getNewCustomer`. Cette fonction permet de créer (ou de mettre à jour) la variable `supplyChain`.
|
|
|
L'ajout d'un nouveau client s'effectue via la fonction `🅵 getNewCustomer`. Cette fonction permet de créer (ou de mettre à jour) la variable `🆅 supplyChain`.
|
|
|
|
|
|
Cette variable est du type `SupplyChain`. Il s'agit d'un graphe dont la structure est quasiment arborescente (mais pas nécessairement car on peut observer des cycles). Les nœuds de ce graphe sont du type `SupplyChainElement`. Une `SupplyChain` possède un élément racine et chaque `SupplyChainElement` possède zéro ou plusieurs "père(s)" (la liste`fathers` dans le fichier `SupplyChain.gaml`), et zéro ou plusieurs "fils" (la liste `sons` dans `SupplyChain.gaml`).
|
|
|
Cette variable est du type `🆃 SupplyChain`. Il s'agit d'un graphe dont la structure est quasiment arborescente (mais pas nécessairement car on peut observer des cycles). Les nœuds de ce graphe sont du type `🆃 SupplyChainElement`. Une `🆃 SupplyChain` possède un élément racine et chaque `🆃 SupplyChainElement` possède zéro ou plusieurs "père(s)" (la liste`🆅 fathers` dans le fichier `SupplyChain.gaml`), et zéro ou plusieurs "fils" (la liste `🆅 sons` dans `SupplyChain.gaml`).
|
|
|
|
|
|
À l'initialisation, on commence par créer un agent `SupplyChainElement` (SCE) qui correspond à l'élément racine et on lui assigne le fournisseur associé au prestataire.
|
|
|
À l'initialisation, on commence par créer un agent `🆃 SupplyChainElement` (SCE) qui correspond à l'élément racine et on lui assigne le fournisseur associé au prestataire.
|
|
|
|
|
|
Ensuite on crée 3 autres agents SCE auquel on leur associe, en fonction du SCE, soit :
|
|
|
|
... | ... | @@ -16,11 +16,11 @@ Ensuite on crée 3 autres agents SCE auquel on leur associe, en fonction du SCE, |
|
|
* l'entrepôt de niveau local que l'on a sélectionné
|
|
|
* le bâtiment associé au destinataire final
|
|
|
|
|
|
Enfin on connecte (via les listes `fathers` et `sons`) le SCE fournisseur avec le SCE national, lui-même connecté avec le SCE local, lui-même connecté avec le SCE destinataire.
|
|
|
Enfin on connecte (via les listes `🆅 fathers` et `🆅 sons`) le SCE fournisseur avec le SCE national, lui-même connecté avec le SCE local, lui-même connecté avec le SCE destinataire.
|
|
|
|
|
|
Une `SupplyChain` possède également des "feuilles" : il s'agit de la liste `leafs` qui contient l'ensemble des SCE correspondant aux destinataires finaux gérés par le prestataire.
|
|
|
Une `🆃 SupplyChain` possède également des "feuilles" : il s'agit de la liste `🆅 leafs` qui contient l'ensemble des SCE correspondant aux destinataires finaux gérés par le prestataire.
|
|
|
|
|
|
La manière de sélectionner les entrepôts dépend de la stratégie définie. Plusieurs cas sont possibles. L'utilisateur peut indiquer que tous les prestataires partagent la même stratégie (via la variable booléenne `isLocalSelectingWarehouseStrategies` du fichier `Parameters.gaml`). Si tel est la cas, les prestataires utiliseront la stratégie définie dans `globalSelectingWarehouseStrategies` de `Parameters.gaml`. Sinon, les prestataires choisiront, lors de leur initialisation, l'une des stratégies proposées dans la variable `possibleSelectingWarehouseStrategies` de `Parameters.gaml`. Une fois qu'un prestataire a choisi une stratégie, il n'en changera pas pendant toute la durée de la simulation.
|
|
|
La manière de sélectionner les entrepôts dépend de la stratégie définie. Plusieurs cas sont possibles. L'utilisateur peut indiquer que tous les prestataires partagent la même stratégie (via la variable booléenne `🅿 isLocalSelectingWarehouseStrategies` du fichier `🅶 Parameters.gaml`). Si tel est la cas, les prestataires utiliseront la stratégie définie dans `🅿 globalSelectingWarehouseStrategies` de `🅶 Parameters.gaml`. Sinon, les prestataires choisiront, lors de leur initialisation, l'une des stratégies proposées dans le paramètre `🅿 possibleSelectingWarehouseStrategies` de `🅶 Parameters.gaml`. Une fois qu'un prestataire a choisi une stratégie, il n'en changera pas pendant toute la durée de la simulation.
|
|
|
|
|
|
Ci-dessous, voici une description des quatre stratégies possibles. On notera toutefois auparavant que toutes les stratégies présentées filtrent toutes les entrepôts en disqualifiant systématiquement les entrepôts n'ayant pas la capacité d'entreposage nécessaire. De plus, pour les entrepôts nationaux, on en choisit un nouveau uniquement si on ne peut trouver un entrepôt national ayant assez de place disponible parmi les entrepôts nationaux faisant déjà parti du réseau d'approvisionnement.
|
|
|
|
... | ... | @@ -45,27 +45,27 @@ Puis on tire un nombre aléatoire entre 0 et 1, et on biaise celui-ci à l'aide |
|
|
|
|
|
En réalité, cette stratégie est inutile aujourd'hui, et ne devrait plus être utilisée. En effet, les résultats montrent qu'elle est aussi mauvaise que la stratégie de sélection aléatoire pure.
|
|
|
|
|
|
Cette stratégie commence par ne conserver que les `numberWarehouseSelected` entrepôts les plus proches (pour les locaux) ou les plus grands (pour les nationaux) puis retourne l'entrepôt qui est le plus accessible (au sens de l'indice de Shimbel). `numberWarehouseSelected` est un paramètre défini globalement dans `Parameters.gaml` (en général on utilise la valeur 15).
|
|
|
Cette stratégie commence par ne conserver que les `🅿 numberWarehouseSelected` entrepôts les plus proches (pour les locaux) ou les plus grands (pour les nationaux) puis retourne l'entrepôt qui est le plus accessible (au sens de l'indice de Shimbel). `🅿 numberWarehouseSelected` est un paramètre défini globalement dans `🅶 Parameters.gaml` (en général on utilise la valeur 15).
|
|
|
|
|
|
# Réapprovisionnement des stocks
|
|
|
|
|
|
Je n'évoque dans cette partie que la vérification des stocks et la création des commandes. Je parle du mécanisme de traitement des commandes dans les pages [bâtiments logistiques](Buildings) et [fournisseur](Provider).
|
|
|
|
|
|
Le reflex `testRestockNeeded` se charge de démarrer régulièrement le processus de contrôle de stocks du réseau d'approvisionnement du prestataire.
|
|
|
Le reflex `🅵 testRestockNeeded` se charge de démarrer régulièrement le processus de contrôle de stocks du réseau d'approvisionnement du prestataire.
|
|
|
|
|
|
Ce reflex ne s'exécute que tous les `nbStepsbetweenTRN` cycles. `nbStepsbetweenTRN` est un paramètre défini globalement dans `Parameters.gaml` (en général on utilise la valeur 24). Pour éviter des phénomènes de synchronisation entre les prestataires, on répartit les différents appels sur un journée grâce à la variable `timeShifting` définie aléatoirement à l'initialisation entre 0 et 23 inclus au sein de chaque prestataire.
|
|
|
Ce reflex ne s'exécute que tous les `🅿 nbStepsbetweenTRN` cycles. `🅿 nbStepsbetweenTRN` est un paramètre défini globalement dans `🅶 Parameters.gaml` (en général on utilise la valeur 24). Pour éviter des phénomènes de synchronisation entre les prestataires, on répartit les différents appels sur un journée grâce à la variable `🆅 timeShifting` définie aléatoirement à l'initialisation entre 0 et 23 inclus au sein de chaque prestataire.
|
|
|
|
|
|
Le reflex `testRestockNeeded` se contente de faire appeler la fonction `recursiveTests` par chacune des "feuilles" du réseau d'approvisionnement (c'est à dire chaque SCE associé à un destinataire).
|
|
|
Le reflex `🅵 testRestockNeeded` se contente de faire appeler la fonction `🅵 recursiveTests` par chacune des "feuilles" du réseau d'approvisionnement (c'est à dire chaque SCE associé à un destinataire).
|
|
|
|
|
|
Cette fonction `recursiveTests` va vérifier l'état des stocks du SCE appelant. Si le niveau d'un stock est trop faible, alors, le SCE crée un objet `Order` correspondant à une commande de marchandise. Un stock est jugé trop faible si : `la quantité du stock < (sa quantité maximale * le seuil de réapprovisionnement du prestataire)`. Lorsqu'une commande est passée, le stock est marqué afin qu'on ne passe pas plusieurs commandes avant la réception du réapprovisionnement.
|
|
|
Cette fonction `🅵 recursiveTests` va vérifier l'état des stocks du SCE appelant. Si le niveau d'un stock est trop faible, alors, le SCE crée un objet `🆃 Order` correspondant à une commande de marchandise. Un stock est jugé trop faible si : `la quantité du stock < (sa quantité maximale * le seuil de réapprovisionnement du prestataire)`. Lorsqu'une commande est passée, le stock est marqué afin qu'on ne passe pas plusieurs commandes avant la réception du réapprovisionnement.
|
|
|
|
|
|
On précise néanmoins qu'il n'est pas possible de passer une commande dont la quantité est supérieur à la quantité maximale transportable par un camion. Cette quantité maximale est définie par la variable `maximalTransportedVolume` dans le fichier `Transporters.gaml` au sein du type agent `RoadTransporter`. Si un stock nécessite une quantité plus importante pour être réapprovisionné, alors on décompose la commande en créant plusieurs objets `Order`.
|
|
|
On précise néanmoins qu'il n'est pas possible de passer une commande dont la quantité est supérieur à la quantité maximale transportable par un camion. Cette quantité maximale est définie par le paramètre `🅿 maximalTransportedVolume` dans le fichier `🅶 Transporters.gaml` au sein du type agent `🆃 RoadTransporter`. Si un stock nécessite une quantité plus importante pour être réapprovisionné, alors on décompose la commande en créant plusieurs objets `🆃 Order`.
|
|
|
|
|
|
Le seuil de réapprovisionnement est une variable sous la forme d'un pourcentage que possède localement chaque prestataire. Néanmoins, l'utilisateur peut choisir si les prestataires doivent partager la même valeur de seuil via le booléen `localThreshold`. S'il est vrai, alors, à l'initialisation, chaque prestataire choisit une valeur comprise entre `minlocalThreshold` et `maxlocalThreshold` (en général valant respectivement 5% et 20%). S'il est faux, alors les prestataires choisissent tous la valeur définie par `globalThreshold`.
|
|
|
Le seuil de réapprovisionnement `🆅 threshold` est une variable sous la forme d'un pourcentage que possède localement chaque prestataire. Néanmoins, l'utilisateur peut choisir si les prestataires doivent partager la même valeur de seuil via le booléen `🅿 localThreshold`. S'il est vrai, alors, à l'initialisation, chaque prestataire choisit une valeur comprise entre `🅿 minlocalThreshold` et `🅿 maxlocalThreshold` (en général valant respectivement 5% et 20%). S'il est faux, alors les prestataires choisissent tous la valeur définie par `🅿 globalThreshold`.
|
|
|
|
|
|
`localThreshold`, `minlocalThreshold`, `maxlocalThreshold` et `globalThreshold` sont tous des paramètres globaux définis dans `Parameters.gaml`.
|
|
|
`🅿 localThreshold`, `🅿 minlocalThreshold`, `🅿 maxlocalThreshold` et `🅿 globalThreshold` sont tous des paramètres globaux définis dans `🅶 Parameters.gaml`.
|
|
|
|
|
|
Une fois qu'un SCE a vérifié l'ensemble de ses stocks et créé les objets `Order` associés à ses éventuelles commandes, alors il fait appeler la fonction `recursiveTests` à chacun des SCE contenus dans sa liste `fathers`. Le SCE transmet par la même occasion la liste de ses commandes (liste d'objet `Order`) à ses "pères". Chaque `Order` transmis par un fils est confié au bâtiment auquel le SCE "père" est rattaché grâce à la fonction `addOrder` d'un `RestockingBuilding` (voir [Building](Building#processOrders) pour plus d'informations). C'est le bâtiment qui va ensuite vérifier que c'est bien à lui de traiter la commande.
|
|
|
Une fois qu'un SCE a vérifié l'ensemble de ses stocks et créé les objets `🆃 Order` associés à ses éventuelles commandes, alors il fait appeler la fonction `🅵 recursiveTests` à chacun des SCE contenus dans sa liste `🆅 fathers`. Le SCE transmet par la même occasion la liste de ses commandes (liste d'objet `🆃 Order`) à ses "pères". Chaque `🆃 Order` transmis par un fils est confié au bâtiment auquel le SCE "père" est rattaché grâce à la fonction `🅵 addOrder` d'un `🆃 RestockingBuilding` (voir [Building](Building#processOrders) pour plus d'informations). C'est le bâtiment qui va ensuite vérifier que c'est bien à lui de traiter la commande.
|
|
|
|
|
|
Ce processus récursif s'arrête lorsqu'il atteint l'élément racine du réseau d'approvisionnement. Puisque l'élément racine est le fournisseur, il n'a pas besoin de passer de commandes mais est capable de générer de nouvelles quantités de marchandises.
|
|
|
|
... | ... | @@ -73,6 +73,18 @@ Ce processus récursif s'arrête lorsqu'il atteint l'élément racine du réseau |
|
|
|
|
|
Lorsqu'un destinataire final informe un prestataire qu'il vient de perdre un client, le prestataire doit effectuer plusieurs opérations pour mettre à jour son réseau d'approvisionnement.
|
|
|
|
|
|
En effet, il doit d'abord parcourir l'ensemble des entrepôts dont il a la charge et retrouver les stocks appartenant au destinataire afin des les retirer de ces entrepôts. Les stocks du client sont temporairement placés dans un objet de type `TransferredStocks`. Cet objet est ensuite transmis au client afin que les stocks soient transférés au prochain prestataire du destinataire.
|
|
|
En effet, il doit d'abord parcourir l'ensemble des entrepôts dont il a la charge et retrouver les stocks appartenant au destinataire afin des les retirer de ces entrepôts. Les stocks du client sont temporairement placés dans un objet de type `🆃 TransferredStocks`. Cet objet est ensuite transmis au client afin que les stocks soient transférés au prochain prestataire du destinataire.
|
|
|
|
|
|
L'ancien prestataire doit également vérifier si la perte de son client nécessite de supprimer un ou plusieurs entrepôt(s) de son réseau d'approvisionnement. Il doit donc supprimer au sein de `supplyChain` le SCE associé à son ancien client ainsi que les éventuels SCE associés aux entrepôts qui doivent être retirés. |
|
|
\ No newline at end of file |
|
|
L'ancien prestataire doit également vérifier si la perte de son client nécessite de supprimer un ou plusieurs entrepôt(s) de son réseau d'approvisionnement. Il doit donc supprimer au sein de `🆅 supplyChain` le SCE associé à son ancien client ainsi que les éventuels SCE associés aux entrepôts qui doivent être retirés.
|
|
|
|
|
|
# Légende
|
|
|
|
|
|
`🅵 fonctions`
|
|
|
|
|
|
`🅿 paramètre du modèle`
|
|
|
|
|
|
`🆃 type d'agent`
|
|
|
|
|
|
`🆅 variable`
|
|
|
|
|
|
`🅶 Fichier contenant des variables et/ou des fonctions globales` |
|
|
\ No newline at end of file |