signetlabdei/sem

Run simulation with couple of parameters

matbord opened this issue · 4 comments

Hi,
I would like to run a simulation without running all the possible simulations but some parameters are used as couple. Here's an example:

params = { 'nWifi': [1, 2, 3], 'distance': [1 ,5 ,10], 'simTime': [15], } runs=2

If I run this I obtain 3 * 3 * 1 * 2=18 simulations because the campaign is performing all the possible simulations. I would like to run 3 * 1 * 2=6 simulations where

  • the first one is using nWifi=1 and distance=1
  • the second one nWifi=2 and distance=5
  • the third one nWifi=3 and distance=10
  • 4,5,6 is repeating the same three but with a different value for runs

Is it possible?

Hi @matbord , you can run three separate simulations with three parameter sets, `i.e.,

params1 = { 'nWifi': [1], 'distance': [1], 'simTime': [15], } runs=2
params2 = { 'nWifi': [2], 'distance': [5], 'simTime': [15], } runs=2
params3 = { 'nWifi': [3], 'distance': [10], 'simTime': [15], } runs=2

You can then query the three results separately and aggregate them manually for plotting purposes.
One option is to get results as xarrays, convert them to dataframes, and concatenate them.
You can then use matplotlib, or even better seaborn to plot your results in an easy and elegant way.

@mattia-lecci's solution is correct - note that you can also pass a list of dictionaries to run_missing_simulations, so something like the following should also work:

params1 = { 'nWifi': [1], 'distance': [1], 'simulationTime': [15], channelWidth: [20]}
params2 = { 'nWifi': [2], 'distance': [5], 'simulationTime': [15], channelWidth: [20]}
params3 = { 'nWifi': [3], 'distance': [10], 'simulationTime': [15], channelWidth: [20]}

params = [params1, params2, params3]

campaign.run_missing_simulations(params, runs=2)

If you want something that is a bit more concise and easier to maintain, you can also do this:

nwifi_to_distance = {1: 1, 2: 5, 3: 10}

params = {
  'nWifi': [1, 2, 3],
  'distance': lambda p: nwifi_to_distance[p['nWifi']],
  'simulationTime': 15,
  'channelWidth': [20]
}

campaign.run_missing_simulations(params, runs=2)

In other words, you define a dictionary that specifies the value (or values, if you enter a list) of distance that you want for each value of nWifi, and use a lambda function in the parameter definition. When SEM expands the parameter definition, if one of the parameter values is a function, it will call that function with the current parameter dictionary as an argument to obtain the values for that key. Since in this case distance comes after nWifi in the order of parameters, you can assume that the argument of the lambda function will be a dictionary that only has a single value for the nWifi, as that key was already expanded.

Without lambda functions, the previous code block is equivalent to:

distance_from_nwifi = {1: 1, 2: 5, 3: 10}

def get_distance_from_nwifi(param):
  return nwifi_to_distance[param['nWifi']]

params = {
  'nWifi': [1, 2, 3],
  'distance': get_distance_from_nwifi,
  'simulationTime': [15],
  'channelWidth': [20]
}

campaign.run_missing_simulations(params, runs=2)

All code blocks above should give the following output:

print(["nWifi: %s, distance: %s, RngRun: %s" % (r['params']['nWifi'], r['params']['distance'], r['params']['RngRun']) for r in campaign.db.get_results()])

['nWifi: 1, distance: 1, RngRun: 1',
 'nWifi: 1, distance: 1, RngRun: 0',
 'nWifi: 2, distance: 5, RngRun: 3',
 'nWifi: 2, distance: 5, RngRun: 2',
 'nWifi: 3, distance: 10, RngRun: 5',
 'nWifi: 3, distance: 10, RngRun: 4']

Note that I just now pushed a small change to make run_missing_simulations more robust when a list of parameter combinations is passed to it - please consider updating!

I just realized that there is no mention of using lambda functions for parameter space definition in the examples, as of now. I'll address this by next week.

Perfect thank you for all your support! using lambda is very useful but @mattia-lecci's solution is the best one for me since I would have duplicates values for the key if I used the dictionary