Code
import bellhop as bh
import bellhop.plot as bhp
= bh.create_env()
env = bh.compute(env,task=["eigenrays","arrivals"])
output, _
0]['results'])
bhp.plot_rays(output[1]['results']) bhp.plot_arrivals(output[
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.
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 = read_env('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 ?@tbl-tasks. 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=
"rays"
"eigenrays"
"arrivals"
"coherent"
"incoherent"
"semicoherent"
: Values allowed for the task=
option for bellhop.compute
(can be a string or list of strings). {#tbl-tasks}
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 ?@tbl-tasks)'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 bellhop as bh
import pandas.testing as pdt
if "bellhopcuda" not in bh.models():
bh.new_model(name="bellhopcuda",exe="bellhop.exe") # in reality you would of course have a separate binary
env = bh.create_env()
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:
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.