gama-platform / gama.old

Main repository for developing the 1.x versions of GAMA
GNU General Public License v3.0
304 stars 99 forks source link

[GS] Step command causes gs to never return an answer message when sync is true and to sometimes raise exceptions when sync is false #3912

Closed lesquoyb closed 1 year ago

lesquoyb commented 1 year ago

Describe the bug On current git version, I'm trying to run a gama-client, I've noticed that on some client code that used to work, I am now stuck when trying to execute the step command with the sync parameter set to true as no answer message comes back to the client. On the other hand, when I set that parameter to false, in some instances it raises runtime exceptions, which shouldn't be the case.

To Reproduce

here is an example python where the problem arises:

import asyncio
from asyncio import Future
from pathlib import Path
from typing import Dict

from gama_client.base_client import GamaBaseClient
from gama_client.command_types import CommandTypes
from gama_client.message_types import MessageTypes

experiment_future: Future
play_future: Future
pause_future: Future
expression_future: Future
step_future: Future
step_back_future: Future
stop_future: Future

async def message_handler(message: Dict):
    print("received", message)
    if "command" in message:
        if message["command"]["type"] == CommandTypes.Load.value:
            experiment_future.set_result(message)
        elif message["command"]["type"] == CommandTypes.Play.value:
            play_future.set_result(message)
        elif message["command"]["type"] == CommandTypes.Pause.value:
            pause_future.set_result(message)
        elif message["command"]["type"] == CommandTypes.Expression.value:
            expression_future.set_result(message)
        elif message["command"]["type"] == CommandTypes.Step.value:
            step_future.set_result(message)
        elif message["command"]["type"] == CommandTypes.StepBack.value:
            step_back_future.set_result(message)
        elif message["command"]["type"] == CommandTypes.Stop.value:
            stop_future.set_result(message)

async def main():

    global experiment_future
    global play_future
    global pause_future
    global expression_future
    global step_future
    global step_back_future
    global stop_future

    # Experiment and Gama-server constants
    server_url = "localhost"
    server_port = 6868
    gaml_file_path = str(Path(__file__).parents[0] / "predatorPrey.gaml")
    exp_name = "prey_predator"
    exp_init_param = [{"type": "int", "name": "nb_preys_init", "value": 100}]

    client = GamaBaseClient(server_url, server_port, message_handler)

    print("connecting to Gama server")
    await client.connect()

    print("initialize a gaml model")
    experiment_future = asyncio.get_running_loop().create_future()
    await client.load(gaml_file_path, exp_name, True, True, True, True, exp_init_param)
    gama_response = await experiment_future

    try:
        experiment_id = gama_response["content"]
    except Exception as e:
        print("error while initializing", gama_response, e)
        return

    print("initialization successful, running the model")
    play_future = asyncio.get_running_loop().create_future()
    await client.play(experiment_id)
    gama_response = await play_future
    if gama_response["type"] != MessageTypes.CommandExecutedSuccessfully.value:
        print("error while trying to run the experiment", gama_response)
        return

    print("pausing the model")
    pause_future = asyncio.get_running_loop().create_future()
    await client.pause(experiment_id)
    gama_response = await pause_future
    if gama_response["type"] != MessageTypes.CommandExecutedSuccessfully.value:
        print("Unable to pause the experiment", gama_response)
        return

    expression_future = asyncio.get_running_loop().create_future()
    await client.expression(experiment_id, r"cycle")
    gama_response = await expression_future
    print("asking simulation the value of: cycle=", gama_response["content"])

    expression_future = asyncio.get_running_loop().create_future()
    await client.expression(experiment_id, r"nb_preys/nb_preys_init")
    gama_response = await expression_future
    print("asking simulation the value of: nb_preys/nb_preys_init=",  gama_response["content"])

    print("asking gama to run 10 more steps of the experiment")
    step_future = asyncio.get_running_loop().create_future()
    await client.step(experiment_id, 10, True)
    gama_response = await step_future
    if gama_response["type"] != MessageTypes.CommandExecutedSuccessfully.value:
        print("Unable to execute 10 new steps in the experiment", gama_response)
        return

    expression_future = asyncio.get_running_loop().create_future()
    await client.expression(experiment_id, r"cycle")
    gama_response = await expression_future
    print("asking simulation the value of: cycle=", gama_response["content"])

    await asyncio.sleep(1)

    print("asking gama to run 5 steps backwards")
    step_back_future = asyncio.get_running_loop().create_future()
    await client.step_back(experiment_id, 2, True)
    gama_response = await step_back_future
    if gama_response["type"] != MessageTypes.CommandExecutedSuccessfully.value:
        print("Unable to execute 10 new steps in the experiment", gama_response)
        return

if __name__ == "__main__":
    asyncio.run(main())

It requires the python plugins gama-client and asyncio. the gaml model is this one:

/**
* Name: Breeding of prey and predator agents
* Author:
* Description: 6th part of the tutorial : Predator Prey
* Tags: reproduce, myself, self
*/
model prey_predator

global {
    int nb_preys_init <- 200;
    int nb_predators_init <- 20;
    float prey_max_energy <- 1.0;
    float prey_max_transfer <- 0.1;
    float prey_energy_consum <- 0.05;
    float predator_max_energy <- 1.0;
    float predator_energy_transfer <- 0.5;
    float predator_energy_consum <- 0.02;
    float prey_proba_reproduce <- 0.01;
    int prey_nb_max_offsprings <- 5;
    float prey_energy_reproduce <- 0.5;
    float predator_proba_reproduce <- 0.01;
    int predator_nb_max_offsprings <- 3;
    float predator_energy_reproduce <- 0.5;
    int nb_preys -> {length(prey)};
    int nb_predators -> {length(predator)};
    bool is_batch <- false;

    init {
        create prey number: nb_preys_init;
        create predator number: nb_predators_init;
        write(self);
    }   

    reflex stop_simulation when: ((nb_preys = 0) or (nb_predators = 0)) and !is_batch {
        do pause;
    } 

    reflex coucou {
    //  int i <- save_simulation("haha.gsim");
    }
}

species generic_species {
    float size <- 1.0;
    rgb color;
    float max_energy;
    float max_transfer;
    float energy_consum;
    float proba_reproduce;
    int nb_max_offsprings;
    float energy_reproduce;
    vegetation_cell my_cell <- one_of(vegetation_cell);
    float energy <- rnd(max_energy) update: energy - energy_consum max: max_energy;

    init {
        location <- my_cell.location;
    }

    reflex basic_move {
        my_cell <- one_of(my_cell.neighbors2);
        location <- my_cell.location;
    }

    reflex eat {
        energy <- energy + energy_from_eat();
    }

    reflex die when: energy <= 0 {
        do die;
    }

    reflex reproduce when: (energy >= energy_reproduce) and (flip(proba_reproduce)) {
        int nb_offsprings <- rnd(1, nb_max_offsprings);
        create species(self) number: nb_offsprings {
            my_cell <- myself.my_cell;
            location <- my_cell.location;
            energy <- myself.energy / nb_offsprings;
        }

        energy <- energy / nb_offsprings;
    }

    float energy_from_eat {
        return 0.0;
    }

    aspect base {
        draw circle(size) color: color;
    }
}

species prey parent: generic_species  {
    rgb color <- #blue;
    float max_energy <- prey_max_energy;
    float max_transfer <- prey_max_transfer;
    float energy_consum <- prey_energy_consum;
    float proba_reproduce <- prey_proba_reproduce;
    int nb_max_offsprings <- prey_nb_max_offsprings;
    float energy_reproduce <- prey_energy_reproduce;

    float energy_from_eat {
        float energy_transfer <- 0.0;
        if(my_cell.food > 0) {
            energy_transfer <- min([max_transfer, my_cell.food]);
            my_cell.food <- my_cell.food - energy_transfer;
        }           
        return energy_transfer;
    }

}

species predator parent: generic_species {
    rgb color <- #red;
    float max_energy <- predator_max_energy;
    float energy_transfer <- predator_energy_transfer;
    float energy_consum <- predator_energy_consum;
    float proba_reproduce <- predator_proba_reproduce;
    int nb_max_offsprings <- predator_nb_max_offsprings;
    float energy_reproduce <- predator_energy_reproduce;

    float energy_from_eat {
        list<prey> reachable_preys <- prey inside (my_cell);
        if(! empty(reachable_preys)) {
            ask one_of (reachable_preys) {
                do die;
            }
            return energy_transfer;
        }
        return 0.0;
    }
}

grid vegetation_cell width: 50 height: 50 neighbors: 4 {
    float max_food <- 1.0;
    float food_prod <- rnd(0.01);
    float food <- rnd(1.0) max: max_food update: food + food_prod;
    rgb color <- rgb(int(255 * (1 - food)), 255, int(255 * (1 - food))) update: rgb(int(255 * (1 - food)), 255, int(255 * (1 - food)));
    list<vegetation_cell> neighbors2 <- (self neighbors_at 2);
}

experiment prey_predator type: gui record:true{
    parameter "Initial number of preys: " var: nb_preys_init min: 0 max: 1000 category: "Prey";
    parameter "Prey max energy: " var: prey_max_energy category: "Prey";
    parameter "Prey max transfer: " var: prey_max_transfer category: "Prey";
    parameter "Prey energy consumption: " var: prey_energy_consum category: "Prey";
    parameter "Initial number of predators: " var: nb_predators_init min: 0 max: 200 category: "Predator";
    parameter "Predator max energy: " var: predator_max_energy category: "Predator";
    parameter "Predator energy transfer: " var: predator_energy_transfer category: "Predator";
    parameter "Predator energy consumption: " var: predator_energy_consum category: "Predator";
    parameter 'Prey probability reproduce: ' var: prey_proba_reproduce category: 'Prey';
    parameter 'Prey nb max offsprings: ' var: prey_nb_max_offsprings category: 'Prey';
    parameter 'Prey energy reproduce: ' var: prey_energy_reproduce category: 'Prey';
    parameter 'Predator probability reproduce: ' var: predator_proba_reproduce category: 'Predator';
    parameter 'Predator nb max offsprings: ' var: predator_nb_max_offsprings category: 'Predator';
    parameter 'Predator energy reproduce: ' var: predator_energy_reproduce category: 'Predator';

    output {
        display main_display {
            grid vegetation_cell border: #black;
            species prey aspect: base;
            species predator aspect: base;
        }

        monitor "Number of preys" value: nb_preys;
        monitor "Number of predators" value: nb_predators;
    }
}

experiment Optimization type: batch repeat: 2 keep_seed: true until: ( time > 200 ) {
    parameter "Predator energy reproduce:" var: predator_energy_reproduce min: 0.25 max: 1.0 step: 0.25;
    parameter "Batch mode:" var: is_batch <- true;

    method tabu maximize: nb_preys + nb_predators iter_max: 10 tabu_list_size: 3;

    reflex save_results_explo {
        ask simulations {
            save [int(self),prey_max_transfer,prey_energy_reproduce,predator_energy_transfer,predator_energy_reproduce,self.nb_predators,self.nb_preys] 
                to: "results.csv" format:"csv" rewrite: (int(self) = 0) ? true : false header: true;
        }       
    }
}

in that case it got stuck just after the asking gama to run 10 more steps of the experiment line in the client

Expected behavior The answer message is sent, as it used to be

Additional context I looked up on wireshark what were the messages exchanged and the return message really is never present on the network so it's not a problem of the client's code not handling it correctly

AlexisDrogoul commented 1 year ago

What are the exceptions raised ? @hqnghi88 we have more work to do on testing !

lesquoyb commented 1 year ago

It solved both problems of the step command