Note
Click here to download the full example code
RunSimulator: Ravaflow24 Mixture Model
This example shows how to run multiple Ravaflow24Mixture simulations in serial
and parallelly using RunSimulator
.
First, we import the class Ravaflow24Mixture
.
from psimpy.simulator import Ravaflow24Mixture
To create an instance of this class, we must specify the parameter dir_sim
.
It represents the directory in which output files generated by r.avaflow will be
saved.
import os
# Here we create a folder called `temp1_run_Ravaflow24Mixture_example` to save
# output files generated by r.avaflow
cwd = os.getcwd()
if not os.path.exists('temp1_run_Ravaflow24Mixture_example'):
os.mkdir('temp1_run_Ravaflow24Mixture_example')
dir_sim = os.path.join(cwd, 'temp1_run_Ravaflow24Mixture_example')
Given dir_sim
, we can create an instance of Ravaflow24Mixture
.
To reduce simulation time, we set time_end
to \(50\). Other parameters
are set to their default values.
voellmy_model = Ravaflow24Mixture(dir_sim, time_end=50)
The simulator in this example is defined based on voellmy_model
as follows.
It takes required inputs and returns the overall impact area.
import numpy as np
def simulator(prefix, elevation, hrelease, basal_friction, turbulent_friction, EPSG):
"""Preprocess required inputs, run simulation, and return output as a numpy array."""
grass_location, sh_file = voellmy_model.preprocess(prefix=prefix, elevation=elevation,
hrelease=hrelease, basal_friction=basal_friction, turbulent_friction=turbulent_friction, EPSG=EPSG)
voellmy_model.run(grass_location, sh_file) # run this line, r.avaflow will write outputs to dir_sim
impact_area = voellmy_model.extract_impact_area(prefix)
return np.array([impact_area]) # define dir_out and set save_out to True, returned numpy array will be saved to dir_out
To demonstrate how to run multiple simulations using RunSimulator
,
we choose basal_friction
and turbulent_friction
as variable input
parameters. Each has two different values, leading to four simulations.
import itertools
var_inp_parameter = ['basal_friction', 'turbulent_friction']
basal_friction = [20, 30]
turbulent_friction = [3, 4]
var_samples = np.array(
[x for x in itertools.product(basal_friction, turbulent_friction)])
Other parameters of the simulator, including elevation
, hrelease
, and
EPSG
are treated as fixed input. It means that their values are the same in
all simulations.
dir_data = os.path.abspath('../../../tests/data/')
elevation = os.path.join(dir_data, 'synthetic_topo.tif')
hrelease = os.path.join(dir_data, 'synthetic_rel.tif')
fix_inp = {'elevation': elevation, 'hrelease': hrelease, 'EPSG': '2326'}
The parameter prefix
of the simulator is special. It is not involved in
the computational model, but only used to name output files generated by r.avaflow.
Such parameter is not defined in var_inp_parameter
or fix_inp
of
RunSimulator
. Instead, we use a seperate parameter, called o_parameter
for this purpose.
o_parameter = 'prefix'
We may want to save outputs returned by the simulator at each simulation for
later inspection or processing. In that case, we need to define dir_out
and
set save_out
as True.
import os
cwd = os.getcwd()
if not os.path.exists('temp2_run_Ravaflow24Mixture_example'):
os.mkdir('temp2_run_Ravaflow24Mixture_example')
dir_out = os.path.join(cwd, 'temp2_run_Ravaflow24Mixture_example')
Note
Please note that dir_out
and dir_sim
are two different
parameters for different purposes.
dir_out
is a parameter ofRunSimulator
. The simulator returns output of interest as a numpy array for each simulation. If we want to save this returned output of interest (here impact area) to our local machine, we need to specify the value ofdir_out
which represents the directory in which output of interest will be saved and setsave_out
to True. Otherwise, we do not needdir_out
and leavesave_out
to False.
dir_sim
is a parameter ofRavaflow24Mixture
.Ravaflow24Mixture
relies on the third party software r.avaflow 2.4. When we callRavaflow24Mixture.run()
in the function body of above simulator, r.avaflow 2.4 will be run and it generates output files. The value ofdir_sim
specifies the directory in which output files generated by r.avaflow 2.4 are going to be saved.
The value of dir_out
and dir_sim
can be the same if file names
have no conflict. We recommend to keep them seperate. In addition, if the function
body of the simulator does not write files to disk, dir_sim
is not required. Our
MassPointModel
is an example. Similarly, if we do not want to save
returned numpy array of the simulator, dir_out
is not needed.
Now we can define an object of RunSimulator
by
from psimpy.simulator import RunSimulator
run_simulator = RunSimulator(simulator, var_inp_parameter, fix_inp, o_parameter,
dir_out, save_out=True)
Before running simulations, we need to specify values of prefixes
which
will be used to name files generated by each r.avaflow simulation and
each returned numpy array of simulator.
serial_prefixes = ["serial"+str(i) for i in range(len(var_samples))]
parallel_prefixes = ["parallel"+str(i) for i in range(len(var_samples))]
Now we can use RunSimulator.serial_run()
method or
RunSimulator.parallel_run()
method to run the simulations
in serial or parallelly.
import time
start = time.time()
run_simulator.serial_run(var_samples=var_samples, prefixes=serial_prefixes)
serial_time = time.time() - start
serial_output = run_simulator.outputs
print(f"serial_output: {serial_output}")
start = time.time()
# append setting to True means that simulation outputs of parallel run will be
# appended to above serial run outputs
run_simulator.parallel_run(var_samples, prefixes=parallel_prefixes,
max_workers=2, append=True)
parallel_time = time.time() - start
parallel_output = run_simulator.outputs[len(var_samples):]
print(f"parallel_output: {parallel_output}")
print("Serial run time: ", serial_time)
print("Parallel run time: ", parallel_time)
serial_output: [array([1008000.]), array([1520800.]), array([674000.]), array([869600.])]
parallel_output: [array([1008000.]), array([1520800.]), array([674000.]), array([869600.])]
Serial run time: 110.85352993011475
Parallel run time: 62.39644193649292
All output files returned by the simulator are
os.listdir(dir_out)
['serial0_output.npy', 'parallel0_output.npy', 'serial1_output.npy', 'parallel2_output.npy', 'serial3_output.npy', 'parallel3_output.npy', 'serial2_output.npy', 'parallel1_output.npy']
All output files/directories generated by r.avaflow simulations (including files/directories generated during preprocessing) are
os.listdir(dir_sim)
['serial0_glocation', 'parallel3_results', 'parallel2_glocation', 'serial3_shell.sh', 'parallel1_results', 'serial3_glocation', 'serial1_shell.sh', 'parallel2_results', 'serial0_shell.sh', 'parallel1_glocation', 'parallel3_shell.sh', 'parallel0_shell.sh', 'serial1_glocation', 'parallel1_shell.sh', 'parallel2_shell.sh', 'serial0_results', 'serial1_results', 'serial2_shell.sh', 'serial2_glocation', 'serial2_results', 'parallel3_glocation', 'parallel0_glocation', 'serial3_results', 'parallel0_results']
Warning
If one simulation failed due to whatever reason, the error massage
will be printed to the screen but other simulations will continue. In that
case, the output file of failed simulation will not be writted to dir_out
.
Also, the element of RunSimulator.outputs
corresponding to that
simulation will be a string representing the error message, instead of a
numpy array.
In the end, we delete the folder temp1_run_Ravaflow24Mixture_example and temp2_run_Ravaflow24Mixture_example and all files therein.
import shutil
shutil.rmtree(dir_sim)
shutil.rmtree(dir_out)
Total running time of the script: ( 2 minutes 53.318 seconds)