the-anylogic-company / AnyLogic-Pypeline

A custom AnyLogic library for running Python inside an AnyLogic model (Java)
https://github.com/the-anylogic-company/AnyLogic-Pypeline/wiki
MIT License
107 stars 27 forks source link

Run Python scripts before each experiment run #43

Closed andreaFrrr closed 1 year ago

andreaFrrr commented 1 year ago

I would like to run an external Python script before each AnyLogic experiment run. I tried to set a PyCommunicator object in the Simulation Experiment page through a variable as explained here ([https://www.anylogic.com/upload/pdf/q-and-a-with-writeups.pdf]). I tried with the different constructors available, but when I run the model the variable is at null value. In order to understand if I made some mistake in the definition the constructors of the PyCommunicator object, in the Main agent I defined a variable of type PyCommunicator copying the parameters of another working PyCommunicator object set by dragging and dropping from palette. Here the code:

//py is the PyCommunicator object created by drag and drop from Palette //py2 is the manually created PyCommunicator object PyCommunicator py2 = new PyCommunicator(py.enable,py.loadLastWorkingConfig,py.pythonCommandType,py.pythonCommand,py.pythonExecPath,py.throwErrorOnFailedAttempt,py.redirectPyOutput);

If I print at console the values of the parameters of the two objects I have this result: Py object: Python 3.11.0 C:\...\python.exe Enable: true Load last config: false Python command type: PYTHON_PATH Python command: null Python executable path: C:\...\python.exe Throw error: false Redirect output: true Py2 object: null

What I am doing wrong?

Thanks

t-wolfeadam commented 1 year ago

I think some of the formatting got messed up so it's hard to tell exactly what the error messages are showing/what's going wrong. If you can provide the model you're using that would be more helpful.

But the current way you can use it in the experiment screen requires the PyCommunicator agent to be created/started via an existing agent. Thus, you need to set it up in the Before simulation run action field using the top-level agent like so:

pyCommunicator = new PyCommunicator(PythonCommandType.PYTHON); // or whatever arguments correspond to your version
pyCommunicator.createAndStart(root);
//pyCommunicator.run("<code>");

This gets called after the root agent is created but before any events happen. For a live example, run this model: Python from experiment screen.zip

t-wolfeadam commented 1 year ago

Feel free to reopen if this problem isn't resolved

andreaFrrr commented 1 year ago

Thank you very much for the first answer to the problem. I tried to do as you suggested but I don't get the result I want. I can correctly set up the PyCommunicator and I can correctly run the python script before the simulation starts. However, I continue to have a problem. This script is intended to update an excel file in the AnyLogic model folder, which is linked with a database table in AnyLogic. I need the contents of this table to set the location of some agents at the beginning of the simulation. The excel file updates, but at the start of the simulation the table in AnyLogic does not update, despite the fact that I have flagged the "update data at model startup" checkbox in the AnyLogic database table. Trivially, if I clear all the data from the excel before running the simulation, run the model, the excel updates again thank to the python script, but the model does not. I think it is a problem related to the fact that AnyLogic loads the data into the database table and then afterwards runs the script and then updates the excel. Is there any way to solve it?

t-wolfeadam commented 1 year ago

You are correct in that the database is being imported before the "Before simulation run". Thus, the updates are being delayed by one run.

Here's two possible solutions:

  1. Add an event + some variables to manage automating a force restart of the experiment whenever a change is made; it should be setup in such a way that during the restart, the code to call Pypeline would not run.
  2. For whatever function you're calling in Python (to modify the excel file), modify it to return the rows to add/update/remove. Use the DB's insertInto / update / deleteFrom to apply these changes to the tables.

I tested both to make sure it would work. Each solution is commented about in the Simulations "Before simulation run" field -- you should only have one enabled at a time. Model294.zip

andreaFrrr commented 1 year ago

Thank you again. I tried with the second solution and it works wonderfully. Is there the possibility to have a similar result also with a parameter variation experiment?

t-wolfeadam commented 1 year ago

Is there the possibility to have a similar result also with a parameter variation experiment?

Yes, it would work the same way, though you may need to turn parallel runs off. See the Python from experiment screen demo model, available by downloading the repo or from the latest release.