FLAMEGPU / FLAMEGPU2

FLAME GPU 2 is a GPU accelerated agent based modelling framework for CUDA C++ and Python
https://flamegpu.com
MIT License
99 stars 19 forks source link

Agent Python MsgArray problems #1110

Closed Robadob closed 9 months ago

Robadob commented 9 months ago

Discussed in https://github.com/FLAMEGPU/FLAMEGPU2/discussions/1109

Originally posted by **LangLEvoI** September 20, 2023 Hi there, I'm using `Agent Python` to build a simple model for more understanding of Flame GPU 2, based on the `Circle tutorial`. An agent could randomly pick up another agent, replicating another one's status in my new model. But some errors occurred when I tried to use `MessageArray`. Could I fix it somewhere? First, the definition about 1D message array AND agent functions: ```python message = model.newMessageArray('variant') message.setLength(5) message.newVariableInt('var') @pyflamegpu.agent_function def output_message(message_in: pyflamegpu.MessageNone, message_out: pyflamegpu.MessageArray): message_out.setIndex(pyflamegpu.getID() - 1) message_out.setVariableInt("var", pyflamegpu.getVariableInt("var")) return pyflamegpu.ALIVE @pyflamegpu.agent_function def input_message(message_in: pyflamegpu.MessageArray, message_out: pyflamegpu.MessageNone): interlocutor = pyflamegpu.random.uniformInt(0, 4) msg = message_in.at(interlocutor - 1) pyflamegpu.setVariableInt("var", msg.getVariableInt('var')) return pyflamegpu.ALIVE ``` When I ran the programme, the first error: ``` --------------------------------------------------- --- JIT compile log for input_message_program --- --------------------------------------------------- input_message_impl.cu(7): error: class "flamegpu::MessageArray3D::In::Message" has no member "getVariableInt" 1 error detected in the compilation of "input_message_program". --------------------------------------------------- Traceback (most recent call last): File "/app/lilei/projects/flame/simple.py", line 115, in cuda_model.applyConfig() File "/app/lilei/miniconda3/envs/rapids/lib/python3.8/site-packages/pyflamegpu/pyflamegpu.py", line 7223, in applyConfig return _pyflamegpu.Simulation_applyConfig(self) pyflamegpu.pyflamegpu.FLAMEGPURuntimeException: (InvalidAgentFunc) /__w/FLAMEGPU2/FLAMEGPU2/src/flamegpu/detail/JitifyCache.cu(380): Error compiling runtime agent function (or function condition) ('input_message'): function had compilation errors (see std::cout), in JitifyCache::buildProgram(). ``` When I commented this line in `input_message` function and ran again: ```python # pyflamegpu.setVariableInt("var", msg.getVariableInt('var')) ``` A new error: ``` Traceback (most recent call last): File "/app/lilei/projects/flame/simple.py", line 117, in cuda_model.simulate() File "/app/lilei/miniconda3/envs/rapids/lib/python3.8/site-packages/pyflamegpu/pyflamegpu.py", line 7310, in simulate return _pyflamegpu.CUDASimulation_simulate(self, *args) pyflamegpu.pyflamegpu.FLAMEGPURuntimeException: (DeviceError) Device function 'input_message' reported 2 errors. First error: flamegpu/runtime/messaging/MessageArray/MessageArrayDevice.cuh(564)[0,0,0][0,0,0]: Index is out of bounds for Array messagelist (4294967295 >= 5). ``` The strange thing is that when I changed the `random_seed` from `12` to `112654` by accident, this error disappeared... Another issue is about `cuda_model.CUDAConfig().device`. It didn't work when I set it to other device numbers, it always uses the default device. ```python cuda_model = pyflamegpu.CUDASimulation(model) cuda_model.SimulationConfig().steps = 10 cuda_model.SimulationConfig().random_seed = 112654 cuda_model.CUDAConfig().device = 1 cuda_model.applyConfig() cuda_model.simulate() ``` Thx a lot!

Need to check whether this can be reproduced, but it appears array messages may be being processed wrong.

Robadob commented 9 months ago

With the codegen from current master

@pyflamegpu.agent_function
def input_message(message_in: pyflamegpu.MessageArray, message_out: pyflamegpu.MessageNone):
    interlocutor = pyflamegpu.random.uniformInt(0, 4)
    msg = message_in.at(interlocutor - 1)

    pyflamegpu.setVariableInt("var", msg.getVariableInt('var'))

    return pyflamegpu.ALIVE

Translates to

FLAMEGPU_AGENT_FUNCTION(input_message, flamegpu::MessageArray, flamegpu::MessageNone){
    auto interlocutor = FLAMEGPU->random.uniform<int>(0, 4);
    auto msg = FLAMEGPU->message_in.at((interlocutor - 1));
    FLAMEGPU->setVariable<int>("var", msg.getVariableInt("var"));
    return flamegpu::ALIVE;
}

Hence the incorrect msg.getVariableInt("var").

Obvious bug would be that it only expects message methods inside a message loop when transpiling. Will require some investigation, possibly input from @mondus.

The doc comment of codegen.py::dispatchMemberFunction() seems to confirm this has been overlooked, not immediately clear (to me) the best way to address it though. To do it properly would require some AST magic to track that msg was returns by message_in.at().

Lazy option would just be to regex groups replace all instances of getVariableType, but could break some esoteric cases.