Commit 39ea2bff authored by ThibautDemare's avatar ThibautDemare

Update the model according to new 'multi-modal' feature

parent 72870c6f
/**
* AwaitingStock
* Author: Thibaut
* Description:
*/
model AwaitingStock
import "./Stock.gaml"
import "Stock.gaml"
species AwaitingStock schedules:[] {
Stock stock;
int stepOrderMade;
int position;
int position;
Building building;
}
\ No newline at end of file
/**
* Batch
* Author: Thibaut Démare
* Description: This agent simulates the real flow of goods. It moves on the physical network and must follow a supply chain. His behavior can be improve.
*/
model Batch
import "./SeineAxisModel.gaml"
import "./Building.gaml"
import "./FinalDestinationManager.gaml"
species Batch skills:[MovingOnNetwork] {
float overallQuantity;
list<Stock> stocks;
point target;
float speed <- 70.0 °km/°h;
int position; // The position allows to make distinction between Batch agents coming from Provider (position = 1), national warehouse (position = 2), or local warehouse (position = 3).
Building dest;
int stepOrderMade;
bool marked <- false;// useful for the Observer in order to avoid to count the batch two times
float pathLength <- -1;
action init_network{
network <- road_network;
}
reflex delete when: target = nil and dest != nil {
do die;
}
reflex move when: target != nil {
if(network = nil){
network <- road_network;
}
do go_to target:target.location length_attribute:"length" speed_attribute:"speed" mark:overallQuantity;
if(location = dest.location){
// The agent is at destination
// We have to transfer its stocks to the building
ask dest {
do receive_stocks(myself);
}
target <- nil;
}
}
aspect base {
string c <- "";
if( position = 1){// The provider must send new stock
c <- "blue";
}
else if( position = 2 ){
c <- "green";
}
else if( position = 3){
c <- "orange";
}
else {
c <- "grey";
}
if(position > 0){
draw shape color: rgb(c) ;
}
}
aspect little_base {
string c <- "";
if( position = 1){// The provider must send new stock
c <- "blue";
}
else if( position = 2 ){
c <- "green";
}
else if( position = 3){
c <- "orange";
}
else {
c <- "grey";
}
if(position > 0){
draw shape color: rgb(c) ;
}
}
}
\ No newline at end of file
/**
* Building
* Author: Thibaut Démare
* Description: It is a physical structure that contains a stock and which has a surface. It can receive some batch and simulate a break bulk mechanism.
*/
model Building
import "./Batch.gaml"
import "./AwaitingStock.gaml"
import "./Stock.gaml"
import "./Order.gaml"
import "./Parameters.gaml"
import "./GraphStreamConnection.gaml"
import "./LogisticProvider.gaml"
import "AwaitingStock.gaml"
species Building {
list<Stock> stocks;
list<AwaitingStock> entering_stocks <- [];
......@@ -24,19 +12,43 @@ species Building {
int maxProcessEnteringGoodsCapacity <- 5;
int timeShifting <- rnd(23);
/*
* Receive a batch
*/
action receive_stocks(Batch batch){
loop st over: batch.stocks {
list<Vehicle> leavingVehicles <- []; // Liste des véhicules au départ
list<Commodity> leavingCommodities <- [];
list<Commodity> comingCommodities <- [];
float handling_time_to_road <- 1;
float handling_time_from_road <- 1;
float colorValue <- -1;
reflex manageRoadComingCommodities {
int i <- 0;
loop while:i<length(comingCommodities) {
if(comingCommodities[i].currentNetwork = 'road' and
comingCommodities[i].incomingDate + handling_time_from_road#hour >= current_date
){
leavingCommodities <+ comingCommodities[i];
remove index:i from:comingCommodities;
}
else{
i <- i + 1;
}
}
}
action receiveCommodity(Commodity c){
if(c.finalDestination = self){
create AwaitingStock number: 1 returns: ast {
self.stepOrderMade <- batch.stepOrderMade;
self.stock <- st;
self.position <- batch.position;
self.location <- batch.location;
self.stepOrderMade <- c.stepOrderMade;
self.stock <- c.stock;
self.location <- myself.location;
self.building <- myself;
}
entering_stocks <- entering_stocks + ast[0];
}
else {
comingCommodities <+ c;
}
}
reflex processEnteringGoods when: length(entering_stocks) > 0 {
......@@ -53,7 +65,7 @@ species Building {
stockBuilding.quantity <- stockBuilding.quantity + entering_stock.stock.quantity;
if(entering_stock.stepOrderMade >= 0){
// Update lists containing the time to deliver some goods in order to measure the efficiency of the actors
(entering_stock.stock.lp as LogisticProvider).timeToDeliver <- (entering_stock.stock.lp as LogisticProvider).timeToDeliver + ((int(time/3600)) - entering_stock.stepOrderMade);
(entering_stock.stock.lp as LogisticsServiceProvider).timeToDeliver <- (entering_stock.stock.lp as LogisticsServiceProvider).timeToDeliver + ((int(time/3600)) - entering_stock.stepOrderMade);
if(stockBuilding.fdm.building = self){ // The average time to be delivered is only useful with the building of the FDM and not for every building of the supply chain
stockBuilding.fdm.timeToBeDelivered <- stockBuilding.fdm.timeToBeDelivered + ((int(time/3600)) - entering_stock.stepOrderMade);
}
......@@ -83,7 +95,7 @@ species Building {
species RestockingBuilding parent: Building {
list<Order> currentOrders <- [];
list<Batch> leavingBatches <- [];
list<Vehicle> leavingVehicles <- [];
int maxProcessOrdersCapacity;
float cost;
......@@ -118,7 +130,7 @@ species RestockingBuilding parent: Building {
int i <- 0;
loop while: i < length(stocks) and !foundStock {
Stock stock <- stocks[i];
// If we find the right stock, we add the corresponding quantity within a batch
// If we find the right stock, we add the corresponding quantity within a vehicle
if stock.fdm = order.fdm and stock.product = order.product {
foundStock <- true;
order.reference.status <- 3;
......@@ -136,14 +148,14 @@ species RestockingBuilding parent: Building {
outflow <- outflow + sendedQuantity;
outflow_updated <- true;
// And create a Stock agent which will move within a Batch
// And create a Stock agent which will move within a Vehicle
create Stock number:1 returns:sendedStock {
self.product <- order.product;
self.quantity <- sendedQuantity;
self.fdm <- order.fdm;
self.lp <- order.logisticProvider;
self.lp <- order.logisticsServiceProvider;
}
do sendStock(sendedStock[0], order.building, order.position, order.stepOrderMade);
do sendStock(sendedStock[0], order);
}
}
i <- i + 1;
......@@ -164,40 +176,18 @@ species RestockingBuilding parent: Building {
remove index: 0 from: currentOrders;
}
currentOrders <- awaitingOrder + currentOrders;
leavingBatches <- [];
}
action sendStock(Stock stockToSend, Building buildingTarget, int pos, int stpOrderMade){
// Looking for a batch which go to the same building
bool foundBatch <- false;
int j <- 0;
loop while: j < length(leavingBatches) and !foundBatch {
if( (leavingBatches[j] as Batch).dest = buildingTarget and pos = (leavingBatches[j] as Batch).position){
foundBatch <- true;
}
else {
j <- j + 1;
}
}
Batch lb <- nil;
// There is such a Batch, we update it
if(foundBatch){
lb <- leavingBatches[j];
action sendStock(Stock stockToSend, Order order){
create Commodity number:1 returns:returnedAgent;
Commodity commodity <- returnedAgent[0];
commodity.stock <- stockToSend;
commodity.volume <- stockToSend.quantity;
commodity.finalDestination <- order.building;
commodity.stepOrderMade <- order.stepOrderMade;
ask forwardingAgent {
commodity.paths <- compute_shortest_path(myself, order.building, order.strategy, commodity);//'financial_costs'//travel_time
}
else {
// else, we create one
create Batch number: 1 returns:rlb {
self.target <- buildingTarget.location;
self.location <- myself.location;
self.position <- pos;
self.dest <- buildingTarget;
self.stepOrderMade <- stpOrderMade;
}
lb <- first(rlb);
leavingBatches <- leavingBatches + lb;
}
lb.overallQuantity <- lb.overallQuantity + stockToSend.quantity;
lb.stocks <- lb.stocks + stockToSend;
leavingCommodities <- leavingCommodities + commodity;
}
}
\ No newline at end of file
model CellsStockShortage
import "Stock.gaml"
grid cell_stock_shortage width:50 height:50 {
rgb color <- rgb(rgb(255,255,255),0.0);
float nb_stock_shortage;
float nb_stock;
list<float> ratios <- [];
reflex coloration {
nb_stock_shortage <- 0;
nb_stock <- 0;
list<Building> buildings <- (Building inside self);// + (Warehouse inside self);
loop b over: buildings {
ask (b as Building).stocks {
myself.nb_stock <- myself.nb_stock + 1;
if(self.quantity = 0){
myself.nb_stock_shortage <- myself.nb_stock_shortage + 1;
}
}
}
float ratio <- 0;
if(nb_stock = 0 or nb_stock_shortage = 0){
ratios <- ratios + 0;
}
else{
ratio <- nb_stock_shortage/nb_stock;
ratios <- ratios + ratio;
}
if(length(ratios) > 72) { // 168 = 7 days
remove index: 0 from: ratios;
}
int i <- 0;
float sum <- 0.0;
loop while: i < length(ratios) {
sum <- sum + ratios[i];
i <- i + 1;
}
ratio <- sum / length(ratios);
if(ratio = 0){
color <- rgb(rgb(255,255,255),0.1);
}
else if(ratio < 0.025){
color <- rgb(rgb(102,194,164),0.5);
}
else if(ratio < 0.07){
color <- rgb(rgb(65,174,118),0.8);
}
else if(ratio < 0.15){
color <- rgb(rgb(35,139,69),0.8);
}
else{
color <- rgb(rgb(0,88,36),0.8);
}
}
}
\ No newline at end of file
model Commodity
import "Building.gaml"
species Commodity {
float volume;
Building finalDestination;
list<Building> paths;
date incomingDate;
string currentNetwork;
Stock stock;
int stepOrderMade;
}
\ No newline at end of file
/**
* Experiments
* Author: Thibaut
* Description:
*/
model Experiments
import "./Observer.gaml"
import "./Road.gaml"
import "./Warehouse.gaml"
import "./LogisticProvider.gaml"
import "./Provider.gaml"
import "./FinalDestinationManager.gaml"
import "./Batch.gaml"
import "Parameters.gaml"
import "Networks.gaml"
import "Perturbator.gaml"
import "CellsStockShortage.gaml"
experiment 'No ouput' type: gui {
}
experiment 'traffic' type: gui {
output {
display 'traffic' autosave: false refresh:every(1) {
species Road aspect: geom;
species MaritimeLine aspect: geom;
species RiverLine aspect: geom;
species Vehicle aspect: base;
}
}
}
experiment 'No output but save results' type: gui {
parameter "saver" var: saveObservations <- true;
}
......@@ -31,6 +31,8 @@ experiment 'Scenario: block roads' type: gui {
output {
display display_warehouse autosave: true refresh:every(1) {
species Road aspect: geom;
species MaritimeLine aspect: geom;
species RiverLine aspect: geom;
event [mouse_down] action: block_one_road;
}
}
......@@ -46,7 +48,9 @@ experiment 'Scenario: update attractiveness' type: gui {
output {
display display_lp autosave: true refresh:every(1) {
species Road aspect: geom;
species LogisticProvider aspect: base;
species MaritimeLine aspect: geom;
species RiverLine aspect: geom;
species LogisticsServiceProvider aspect: base;
}
}
}
......@@ -58,26 +62,52 @@ experiment 'Every output' type: gui {
user_command Update_Ports_Attractiveness action:update_proba_to_choose_provider;
output {
display 'All agents' autosave: false refresh:every(1) {
species Road aspect: geom;
species MaritimeLine aspect: geom;
species RiverLine aspect: geom;
species Warehouse aspect: base;
species FinalDestinationManager aspect: base;
species Provider aspect: base;
species LogisticsServiceProvider aspect: simple_base;
species Vehicle aspect: base;
}
display 'FC and LSP' autosave: false refresh:every(1) {
species Road aspect: geom;
species MaritimeLine aspect: geom;
species RiverLine aspect: geom;
species Warehouse aspect: base;
species FinalDestinationManager aspect: base;
species Provider aspect: base;
}
display 'Ports attractiveness and LSP' autosave: false refresh:every(1) {
species Road aspect: geom;
species LogisticProvider aspect: base;
species MaritimeLine aspect: geom;
species RiverLine aspect: geom;
species LogisticsServiceProvider aspect: base;
}/**/
display 'Grid with stock shortages' autosave: false refresh:every(1) {
species Road aspect: geom;
species MaritimeLine aspect: geom;
species RiverLine aspect: geom;
species Warehouse aspect: base_condition;
species FinalDestinationManager aspect: base;
species Provider aspect: base;
grid cell_stock_shortage;
species Batch aspect: little_base;
species Vehicle aspect: base;
}
display 'Traffic' autosave: true refresh:every(1) {
species Road aspect: geom;
species MaritimeLine aspect: geom;
species RiverLine aspect: geom;
event [mouse_down] action: block_one_road;
}
display 'Number of Vehicles' refresh:every(1) {
/*display 'Number of Vehicles' refresh:every(1) {
chart "Number of batches" type: series {
data "Total number of batch" value: totalNumberOfBatch color: rgb('purple') ;
data "Number of batch going from the provider to a large warehouse" value: numberOfBatchProviderToLarge color: rgb('blue') ;
......@@ -86,7 +116,7 @@ experiment 'Every output' type: gui {
}
}/**/
display 'Cumulative number of Vehicles' refresh:every(1) {
/*display 'Cumulative number of Vehicles' refresh:every(1) {
chart "Cumulative number of batches" type: series {
data "Cumulative number of batch" value: cumulativeNumberOfBatch color: rgb('blue') ;
data "Cumulative number of batch going from the provider to a large warehouse" value: cumulativeNumberOfBatchProviderToLarge color: rgb('blue') ;
......@@ -95,7 +125,7 @@ experiment 'Every output' type: gui {
}
}/**/
display 'Stocks in transportation' refresh:every(1) {
/*display 'Stocks in transportation' refresh:every(1) {
chart "Stock quantity within batches" type: series {
data "Total quantity of goods within batches" value: stockOnRoads color: rgb('purple') ;
data "Quantity of goods within batches going from the provider to a large warehouse" value: stockOnRoadsProviderToLarge color: rgb('blue') ;
......@@ -104,7 +134,7 @@ experiment 'Every output' type: gui {
}
}/**/
display 'Cumulative stocks in transportation' refresh:every(1) {
/*display 'Cumulative stocks in transportation' refresh:every(1) {
chart "Cumulative stock quantity within batches" type: series {
data "Cumulative quantity of goods within batches" value: cumulativeStockOnRoads color: rgb('blue') ;
data "Cumulative quantity of goods within batches going from the provider to a large warehouse" value: cumulativeStockOnRoadsProviderToLarge color: rgb('blue') ;
......
/**
* FinalDestinationManager
* Author: Thibaut Démare
* Description: This agent sells his stock and then must order a restock to his logistic provider.
*/
model FinalDestinationManager
import "./LogisticProvider.gaml"
import "./SeineAxisModel.gaml"
import "./Warehouse.gaml"
import "./Batch.gaml"
import "./Building.gaml"
import "./Order.gaml"
import "./Stock.gaml"
import "./TransferredStocks.gaml"
import "./GraphStreamConnection.gaml"
import "./Parameters.gaml"
import "Building.gaml"
import "Observer.gaml"
species FinalDestinationManager {
int timeShifting <- rnd(23);
LogisticProvider logisticProvider;
LogisticsServiceProvider logisticsServiceProvider;
list<float> localLPEfficiencies <- [];
float localAverageLPEfficiency <- 0.0;
int numberOfHoursOfContract <- rnd(336) - 100;
......@@ -45,7 +31,7 @@ species FinalDestinationManager {
// Add new node/edge events for corresponding sender
if(use_r1){
gs_add_node gs_sender_id:"actor" gs_node_id:name;
gs_add_edge gs_sender_id:"actor" gs_edge_id:(name + logisticProvider.name) gs_node_id_from:name gs_node_id_to:logisticProvider.name gs_is_directed:false;
gs_add_edge gs_sender_id:"actor" gs_edge_id:(name + logisticsServiceProvider.name) gs_node_id_from:name gs_node_id_to:logisticsServiceProvider.name gs_is_directed:false;
}
if(use_r2){
gs_add_node gs_sender_id:"neighborhood_all" gs_node_id:name;
......@@ -75,12 +61,12 @@ species FinalDestinationManager {
//do buildOneStock;
//do buildFourStock;
do buildTwoToSixStock;
logisticProvider <- chooseLogisticProvider();
ask logisticProvider {
logisticsServiceProvider <- chooseLogisticProvider();
ask logisticsServiceProvider {
do getNewCustomer(myself, nil, nil);
}
loop stock over: building.stocks {
stock.lp <- logisticProvider;
stock.lp <- logisticsServiceProvider;
}
}
......@@ -113,14 +99,14 @@ species FinalDestinationManager {
// the logsitic provider is not efficient enough. He must be replaced by another one.
// Inform the current logistic provider that he losts a customer
TransferredStocks stocksRemoved;
ask logisticProvider {
ask logisticsServiceProvider {
stocksRemoved <- lostCustomer(myself);
}
// Choose a new one
logisticProvider <- chooseLogisticProvider();
logisticsServiceProvider <- chooseLogisticProvider();
// Inform him that he gets a new customer
ask logisticProvider {
ask logisticsServiceProvider {
do getNewCustomer(myself, stocksRemoved.stocksLvl1, stocksRemoved.stocksLvl2);
}
......@@ -132,7 +118,7 @@ species FinalDestinationManager {
int i <- 0;
loop while: i < length(building.stocks) {
building.stocks[i].status <- 0;
building.stocks[i].lp <- logisticProvider;
building.stocks[i].lp <- logisticsServiceProvider;
i <- i + 1;
}
......@@ -149,8 +135,8 @@ species FinalDestinationManager {
/**
* The more the logistic provider is close, the more he has a chance to be selected.
*/
LogisticProvider chooseLogisticProvider {
list<LogisticProvider> llp <- LogisticProvider sort_by (self distance_to each);
LogisticsServiceProvider chooseLogisticProvider {
list<LogisticsServiceProvider> llp <- LogisticsServiceProvider sort_by (self distance_to each);
// int i <- 0;
// bool notfound <- true;
// loop while: notfound {
......@@ -174,7 +160,7 @@ species FinalDestinationManager {
}
action manageLostStock(AwaitingStock aws) {
ask logisticProvider {
ask logisticsServiceProvider {
do manageLostStock(aws);
}
}
......
/**
* Name: ForwardingAgent
* Author: Thibaut
*/
model ForwardingAgent
species ForwardingAgent {
// TODO
import "Transporters.gaml"
import "Experiments.gaml"
species ForwardingAgent skills:[TransportOrganizer]{
Transporter transporter_road;
Transporter transporter_maritime;
Transporter transporter_river;
float colorValue <- -1;
init {
transporter_road <- RoadTransporter[0];
transporter_river <- RiverTransporter[0];
transporter_maritime <- MaritimeTransporter[0];
}
aspect geom {
if(colorValue = -1){
string col <- "grey";
draw shape + 2°px color: rgb(col) border: rgb(col);
}
else {
draw shape + 2°px color: rgb(255, colorValue, 0) border:rgb(255, colorValue, 0);
}
}
}
\ No newline at end of file
/**
* GraphStreamConnection
* Author: Thibaut
* Description:
*/