Code
import aubellhop as bh
import aubellhop.plot as bhp
env = bh.Environment()
output, _ = bh.compute(env,task=["eigenrays","arrivals"])
bhp.plot_rays(output[0]['results'])
bhp.plot_arrivals(output[1]['results'])In the introduction, the four computation types were introduced: arrivals, rays, eigenrays, and transmission loss. When once-off simulations are being undertaken, the methods compute_arrivals(), compute_rays(), etc., are convenient wrapper functions. For complex scenarios, the more general compute() method allows multiple tasks, environmentals, and even Bellhop executables to be run with a single command.
By default, compute() uses a temporary working directory and deletes all intermediate files after the run. If you want to keep the generated .env and output files, pass debug=True.
If you provide a fname_base, files are written to that base name (for example fname_base="demo" produces demo.env, demo.ray, etc.). In this case:
overwrite=True.debug=True prevents post-run cleanup.One feature of the compute() function is to maintain interface compatibility with the original .env file Bellhop interface. Within a legacy .env file, the task to run is hard-coded and therefore
env = bh.Environment.from_file('myenv.env')
print(f"Running task {env['task']}")
results = compute(env)
should return identical results to
> bellhop.exe myenv
The Fortran results file is read into the Python variable results according to which task is specified.
To return results from multiple types of task, pass the name of each desired task in a list via the task=["<task1>", "<task2>"] option. The possible tasks are shown in Table 1. Note that Bellhop runs separately for each one of these computations — it does not provide a feature to re-use data from prior runs (which would seem like it should).
task= option for bellhop.compute (can be a string or list of strings).
Option task= value |
Description |
|---|---|
"rays" |
All rays from a source |
"eigenrays" |
All rays between a source and one receiver |
"arrivals" |
All arrival data from the eigenrays |
"coherent" |
Transmission loss from a source to a grid of receivers (coherent superposition) |
"incoherent" |
(incoherent superposition) |
"semicoherent" |
(semicoherent superposition) |
When more than one task is provided, the output data is returned as a list of dictionaries:
Each dictionary has schema:
'name': the name of the environment configuration (i.e., as produced by env['name'])'task': the name of the task (see Table 1)'model': model name used (matching bellhop.models())'results': the data structure produced by Bellhop for this computationWhen undertaking sensitivity studies it is very common to run multiple Bellhop simulations with varying environment parameters. The compute() function allows multiple environments to be passsed directly to do this automatically:
Where there are multiple tasks and multiple environments, every combination is calculated; for instance env=[env1, env2] and task=["arrivals","eigenrays"] would result in four outputs. (The order is likely implementation-dependent so shouldn’t be relied upon.)
For researchers developing new Bellhop variants (for instance, bellhopcuda), it can be important for testing purposes to be able to run back-to-back simulations with different Bellhop implementations.
This style of execution is harder to demonstrate in a minimal example, but would be constructed with an approach such as:
import aubellhop as bh
import pandas.testing as pdt
if "bellhopcuda" not in bh.Models.supported():
bh.Models.new(name="bellhopcuda",exe="bellhop.exe") # in reality you would of course have a separate binary
env = bh.Environment()
output, _ = bh.compute(env,task="arrivals",model=["bellhop", "bellhopcuda"])
pdt.assert_frame_equal(output[0]['results'], output[1]['results'])
print("[no output to compare, both sets of results are identical]")[no output to compare, both sets of results are identical]
Once again, you can define multiple models, environments, and tasks, and bellhop will automatically execute each combination.
Because the ordering is potentially uncertain, compute also returns a DataFrame of result indices:
import aubellhop as bh
import aubellhop.plot as bhp
env = bh.Environment()
output, ind_df = bh.compute(env,task=["arrivals", "eigenrays"])
print(ind_df)
arr_ind = ind_df[ind_df["task"]=="arrivals"].index[0]
# [0] => first one / only one in this case
arr = output[arr_ind]
bhp.plot_arrivals(arr['results'] ) name model task
i
0 bellhop/python default None arrivals
1 bellhop/python default None eigenrays
This DataFrame can be queried, filtered, etc., to extract results of interest rather than hard-coding numerical outputs.