question

Tuan avatar image
0 Likes"
Tuan asked Jeanette F commented

Flexscript for sending the message via socket repeatedly

My flexsim version is 2020

The flexsim file is server

The python file is client


problem.fsm

socket-TCP客戶端.py


At the beginning, the message is sent from the client to the server , and then the server applies the message to the experimenter .

The result is sent to the client , after the experimenter ends .

My purpose is I want the process to be repeated until the result sent from the server is what the client wants

I write a loop.

When the code ends the first loop, it runs the next loop, but loop didn't work.

I think the problem is the need to wait for the result to be send to the client before starting the next loop.

Maybe I can add a trigger(On serversend trigger) via flexscript How to do?

How to modify the flexscript that waits until the server send the result to the client ??

擷取.png


FlexSim 20.0.10
flexscriptsocket
擷取.png (17.2 KiB)
problem.fsm (92.1 KiB)
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Kavika F avatar image
1 Like"
Kavika F answered Jeanette F commented

Hey @Tuan, I think there's an issue with the loop because there isn't enough time for the experimenter to wait before the "serverreceive" command blocks FlexSim until it receives a response. However, you can't respond because you haven't received the results from the Experimenter; thus, it's caught in this deadlock state. Reference Phil's answer above for a good explanation of how script execution works in FlexSim.

· 13
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Tuan avatar image Tuan commented ·

@Kavika F

For the 2020 version

Is there a solution?

0 Likes 0 ·
Tuan avatar image Tuan Tuan commented ·

@Kavika F

Line 17 executes successfully

Why can't lines 18 and 19 be executed?

0 Likes 0 ·
Kavika F avatar image Kavika F ♦ Tuan commented ·

Hey @Tuan, I got it to work with some help from the links that Phil posted above. Here's what I've got. The working files are below. Make sure to run your model's script first and then your python code.


I started by making some User Commands to simplify how the code looks:

// getInput()
return serverreceive(Model.find("Tools/client").value, NULL, 15, 0);
 
// runExperimenter(string input)
string input = param(1);
Model.find("Tools/Experimenter/ExperimentVariables/Inter arrival time/Scenario 1").value = input;
applicationcommand("runexperiment");

In a single script window I used your code (modified slightly for exiting):

endSocket();
startSocket(8888);

string input = getInput();
if (input.toLowerCase() == "exit") {
  return -1;
}
runExperimenter(input);

Once the script ran, it blocked waiting for a connection from the python code. After sending your input, it would run an experiment. When completed, it would run the EndOfExperiment code, which performed the "seversend" function you had before. Instead of running the next blocking input and experimenter inside of the EndOfExperiment trigger, I ran it using a postwindowmessage.

serversend(server, message);
postwindowmessage(systemwindow(8), FLEXSIM_MESSAGE_USER_NODEFUNCTION, Model.find("Tools/test"), 1234);

With these parameters, it ran the Flexscript Node I added called "test" found in the Tools in the tree.

1667335630944.png

That is where I put the getInput and runExperimenter code.

string input = getInput();
if (input == "") {
  return 0;
}
//print("Input:", input);
runExperimenter(input);
return 1;

I'm not sure why it wasn't working before, but the postwindowmessage code seems to fix it.

problem_5.fsm

socket-tcp___.py

0 Likes 0 ·
problem-5.fsm (31.4 KiB)
socket-tcp.py (1002 B)
1667335652728.png (25.2 KiB)
Tuan avatar image Tuan Kavika F ♦ commented ·

@Kavika F

Thank you for your help!!

I have two questions

1. The code in the test If I change it to this, why doesn't it work?

111.PNG

2. If the message sent by the client is 10, 20, 30, 40, how to apply these four values to the experimenter's context

333.PNG

555.PNG

0 Likes 0 ·
111.png (4.3 KiB)
333.png (14.1 KiB)
555.png (90.4 KiB)
Kavika F avatar image Kavika F ♦ Tuan commented ·

1. The reason your changes won't work is because when I check

if (input == "") {...}

I'm checking to see if the connection between FlexSim and your script disconnected. You have to keep that check in there, but you can add your check for "exit" in addition to that one in a separate if-statement.

2. If you want to string multiple inputs together like that, then it will receive it all as one string. You will have to parse the string in the "runExperimenter" user command I made so it will do the parsing and apply the changes to the Experimenter. For example:

string input = param(1); // 10,20,30,40
// parse the string and store results in an array or separate variables
Array inputs;
while (input.length > 0) {
  string myNum = "";
  int commaIndex = input.indexOf(",");
  if (commaIndex == -1) {
    myNum = input;
  }
  else {
    myNum = input.substr(1, commaIndex-1);
  }
  myNum.trim();
  inputs.push(myNum);
  input = input.slice(commaIndex+1);
}

// set the value of each different row/variable and column/scenario
// you could do this with for-loops
int inputIndex = 1;
treenode experimentVariables = Model.find("Tools/Experimenter/ExperimentVariables");
for (int i = 1; i <= experimentVariables.subnodes.length; i++) {
  treenode variable = experimentVariables.subnodes[i];
  for (int j = 2; j <= variable.subnodes.length; j++) {
    variable.subnodes[j].value = inputs[inputIndex];
    inputIndex++;
  }
}

applicationcommand("runexperiment");
0 Likes 0 ·
Tuan avatar image Tuan Kavika F ♦ commented ·

擷取.png

@Kavika F

Is that what you said?

When I type exit it still can't stop

0 Likes 0 ·
擷取.png (5.8 KiB)
Kavika F avatar image Kavika F ♦ Tuan commented ·

Yeah that's what I'm talking about. It works for me when I use it. Are you adding any spaces when you type "exit"? Do you have the same if-statement in your python code?

1667844129973.png

0 Likes 0 ·
1667844129973.png (11.9 KiB)
Tuan avatar image Tuan Kavika F ♦ commented ·

You misunderstand me.

Entering exit on the python side can successfully stop.

111.png

If the code is as above

I can successfully stop by entering a null value

222.png

If the code is as above

I type exit but can't stop successfully

Why doesn't it work?

0 Likes 0 ·
111.png (17.6 KiB)
222.png (16.6 KiB)
Tuan avatar image Tuan Tuan commented ·
0 Likes 0 ·
Kavika F avatar image Kavika F ♦ Tuan commented ·
As I said previously, if you don't have the check
if (input == "") {...}

then it won't check if the connection broke on the FlexSim side. If your python code doesn't have a check for "exit" but your FlexSim code does, then the Python connection will stay open and waiting for FlexSim since FlexSim will not stop the socket connection. Notice how in my previous code, my python code will break from the infinite while-loop if the user puts in "exit". That needs to be there.

0 Likes 0 ·
Tuan avatar image Tuan Kavika F ♦ commented ·

Thanks for your help I solved it.

1 Like 1 ·
Tuan avatar image Tuan Tuan commented ·

@Kavika F

I want to randomly generate 3 values, each value is 1-10,

20 times, each time 3 values are generated

Send 3 values to flexsim. After calculation by flexsim, flexsim send the result to python. At this time, python stores the result. After 20 times, 20 results are stored. Finally, python outputs the minimum value of 20 results in the terminal.

How to modify the python code to achieve the above function??

socket-tcp.py

0 Likes 0 ·
socket-tcp.py (1000 B)
Show more comments
Phil BoBo avatar image
1 Like"
Phil BoBo answered Phil BoBo edited

When FlexSim is executing your script, FlexSim runs the code one line at a time. Within your script, you call a command to tell FlexSim to then execute a bunch of other processing (running the experiment). Your script needs to finish before FlexSim can do that other processing. FlexSim is busy running your script and can't execute other code until your script is done. Calling applicationcommand("runexperiment") gets the experiment started, but you have to let your script finish in order for it to be able to process the experiment.

Instead of a synchronous loop in a single FlexScript script that is processed by the FlexSim application, your loop should be external to FlexSim's processing.

See:

Automatically Configure and Run a FlexSim Model

Using FlexSim with Python/C api

Future Python and FlexSim integration

Launch FlexSim from Python

Reinforcement Learning Using Previous Versions

From an external control loop outside of FlexSim in whatever programming language you want, you should spawn an instance of FlexSim and then have your 1 -> 1000 for() loop there that communicates with the instance of FlexSim to run the experiments. Your loop should not be within FlexSim.

Within FlexSim, it should receive the message to start the experiment and run it. When the experiment ends, you should then receive another message to return the results and determine whether to start another experiment run with different inputs. This logic should not be all within the same function. You should have one function that starts the processing when you spawn an instance of FlexSim (On Model Open) and another function later when the processing ends (On Experiment End).

While the examples above are primarily focused on reinforcement learning with Python, if you understand the concepts of how the communication is happening in those examples, then you can apply them to what you are trying to accomplish regardless of external programming language or overall goal (running many experiments vs. training an AI).

These concepts also apply regardless of the version of FlexSim. You can do this with any version of FlexSim. Newer versions of FlexSim may have code that follows these concepts to make certain things easier and faster for the user, but the underlying concepts will work with any versions of FlexSim.

For examples:

The 22.1 Python Connector makes it easier to control FlexSim from Python. The 22.1 Range-based Experimenter Jobs make specifying a range of inputs for a design-of-experiment easier. The 22.0 Reinforcement Learning tool makes training AIs require less code on the FlexSim side. Etc.

· 1
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Tuan avatar image Tuan commented ·

1667203354202.png

@Phil BoBo Why can't this be successful? thanks!

0 Likes 0 ·
1667203354202.png (191.3 KiB)