import numpy as np
from vivarium import Vivarium
from spatio_flux import PROCESS_DICT, TYPES_DICT, build_path, render_path
Make the initial Vivarium¶
view available types and processes
# TODO -- make a spatio-flux specific Vivarium with the the core preloaded
vi = Vivarium(processes=PROCESS_DICT, types=TYPES_DICT)
# view the available types
vi.get_types()
['', 'length^2*mass/current^2*time^2', 'length^2*mass/current*time^2', 'length^3/mass*time^2', 'current^2*time^3/length^2*mass', 'mass/current*time^2', 'array', 'enum', 'current*time', 'union', 'mass^0_5/length^1_5', 'current^2*time^4/length^2*mass', 'length^2/time^2', 'positive_float', 'composite', 'length/mass', 'mass^0_5/length^0_5*time', 'length^2*mass/temperature*time^2', 'length^2', 'list', 'length*temperature', 'current*length*time', 'mass/length*time^2', 'length*mass/current^2*time^2', 'substance', 'current*length^2*time', 'current*time/substance', 'wires', '/temperature*time', 'particle', 'reaction', 'printing_unit', 'current^2*time^4/length^3*mass', 'boolean', '/printing_unit', 'mass', 'luminosity', 'mass/length^3', 'temperature', 'length^4*mass/time^3', 'path', 'length^2*mass/current*time^3', 'length^1_5*mass^0_5/time', 'boundary_side', 'length*mass/time^2', 'current', 'maybe', 'schema', 'current*time/mass', 'length^3', 'kinetics', 'step', 'luminosity/length^2', 'length^4*mass/current*time^3', 'tree', 'length^1_5*mass^0_5/time^2', 'length/time^2', 'interval', '/length', 'length^2*mass/current^2*time^3', 'time/length', 'emitter_mode', 'string', 'current*length^2', 'number', 'mass/time^3', 'length^0_5*mass^0_5', '/substance', 'map', 'time', 'protocol', 'length*mass/current*time^3', 'length^3*mass/current^2*time^4', 'substance/time', 'mass/length*time', 'substance/length^3', 'time^2/length', 'length/time', 'length*time/mass', 'length^0_5*mass^0_5/time', 'any', '/time', 'edge', 'length', 'process', 'bounds', 'length^2*mass/time^2', 'mass/temperature^4*time^3', 'length^2*mass/time', 'length^3/time', 'integer', 'float', 'printing_unit/length', 'length^2*mass/substance*temperature*time^2', 'length^2*mass/time^3', 'tuple', 'length^2/time', 'mass/length', 'current*time^2/length^2*mass', 'quote', 'mass/time^2', 'substrate_role']
# view the available processes
vi.get_processes()
['composite', 'DiffusionAdvection', 'Particles', 'console-emitter', 'MinimalParticle', 'DynamicFBA', 'json-emitter', 'ram-emitter']
dFBA¶
Dynamic Flux Balance Analysis (dFBA) extends traditional Flux Balance Analysis (FBA) to model the dynamic behavior of metabolic networks over time, allowing for the simulation of growth and substrate consumption in a changing environment.
# inspect the config schema for the 'increase' process
vi.process_config('DynamicFBA')
{'model_file': 'string', 'kinetic_params': 'map[tuple[float,float]]', 'substrate_update_reactions': 'map[string]', 'biomass_identifier': 'string', 'bounds': 'map[bounds]'}
dfba_config = vi.process_config('DynamicFBA', dataclass=True) # TODO -- make this work
Error finding process DynamicFBA: 'type_parameters'
# TODO - enable get_dataclass to work with the new process
# dfba_config = v.get_dataclass('DynamicFBA')
dfba_config = {
"model_file": "textbook",
"kinetic_params": {
"glucose": (0.5, 1),
"acetate": (0.5, 2)},
"substrate_update_reactions": {
"glucose": "EX_glc__D_e",
"acetate": "EX_ac_e"},
"biomass_identifier": "biomass",
"bounds": {
"EX_o2_e": {"lower": -2, "upper": None},
"ATPM": {"lower": 1, "upper": 1}
}
}
# make the vivarium
v = Vivarium(processes=PROCESS_DICT, types=TYPES_DICT)
# add a dynamic FBA process called 'dFBA'
v.add_process(name="dFBA",
process_id="DynamicFBA",
config=dfba_config,
)
v.diagram(dpi='70')
mol_ids = ["glucose", "acetate", "biomass"]
path=["fields"]
for mol_id in mol_ids:
v.add_object(
name=mol_id,
path=path,
value=np.random.rand()
)
v.connect_process(
process_name="dFBA",
inputs={
"substrates": {
mol_id: build_path(path, mol_id)
for mol_id in mol_ids}
},
outputs={
"substrates": {
mol_id: build_path(path, mol_id)
for mol_id in mol_ids}
}
)
# add an emitter to save results
v.add_emitter()
# TODO -- show_values does not work
v.diagram(dpi='70', show_values=True)
v.set_value(path = ['fields', 'glucose'], value=10)
v.set_value(path = ['fields', 'biomass'], value=0.1)
field = v.get_value(['fields'])
print(field)
{'glucose': 10, 'acetate': 0.7037378681382127, 'biomass': 0.1}
# run the simulation for 10 time units
v.run(interval=60)
v.plot_timeseries(
subplot_size=(8, 3),
combined_vars=[
[
'/fields/glucose',
'/fields/acetate',
'/fields/biomass'
]
]
)
Spatial dFBA¶
mol_ids = ["glucose", "acetate", "biomass"]
path=["fields"]
rows = 2
columns = 1
# make the vivarium
v2 = Vivarium(processes=PROCESS_DICT, types=TYPES_DICT)
for mol_id in mol_ids:
v2.add_object(
name=mol_id,
path=path,
value=np.random.rand(rows, columns)
)
# add a dynamic FBA process at every location
for i in range(rows):
for j in range(columns):
dfba_name = f"dFBA[{i},{j}]"
path_name = build_path(path, 'mol_id', i, j)
print(f'Adding {dfba_name} to {path_name}\n')
# add a process for this location
v2.add_process(
name=dfba_name,
process_id="DynamicFBA",
config=dfba_config,
)
v2.connect_process(
process_name=dfba_name,
inputs={"substrates": {
mol_id: build_path(path, mol_id, i, j)
for mol_id in mol_ids}},
outputs={"substrates": {
mol_id: build_path(path, mol_id, i, j)
for mol_id in mol_ids}}
)
# add an emitter to save results
v2.add_emitter()
v2.diagram(dpi='70')
Adding dFBA[0,0] to ['fields', 'mol_id', 0, 0] Adding dFBA[1,0] to ['fields', 'mol_id', 1, 0]
v2
Vivarium( { 'dFBA[0,0]': { 'address': 'local:DynamicFBA', 'config': { 'biomass_identifier': 'biomass', 'bounds': { 'ATPM': {'lower': 1.0, 'upper': 1.0}, 'EX_o2_e': { 'lower': -2.0, 'upper': None}}, 'kinetic_params': { 'acetate': (0.5, 2.0), 'glucose': (0.5, 1.0)}, 'model_file': 'textbook', 'substrate_update_reactions': { 'acetate': 'EX_ac_e', 'glucose': 'EX_glc__D_e'}}, 'inputs': { 'substrates': { 'acetate': [ 'fields', 'acetate', 0, 0], 'biomass': [ 'fields', 'biomass', 0, 0], 'glucose': [ 'fields', 'glucose', 0, 0]}}, 'instance': <spatio_flux.processes.dfba.DynamicFBA object at 0x12803fa10>, 'interval': 1.0, 'outputs': { 'substrates': { 'acetate': [ 'fields', 'acetate', 0, 0], 'biomass': [ 'fields', 'biomass', 0, 0], 'glucose': [ 'fields', 'glucose', 0, 0]}}, 'shared': None}, 'dFBA[1,0]': { 'address': 'local:DynamicFBA', 'config': { 'biomass_identifier': 'biomass', 'bounds': { 'ATPM': {'lower': 1.0, 'upper': 1.0}, 'EX_o2_e': { 'lower': -2.0, 'upper': None}}, 'kinetic_params': { 'acetate': (0.5, 2.0), 'glucose': (0.5, 1.0)}, 'model_file': 'textbook', 'substrate_update_reactions': { 'acetate': 'EX_ac_e', 'glucose': 'EX_glc__D_e'}}, 'inputs': { 'substrates': { 'acetate': [ 'fields', 'acetate', 1, 0], 'biomass': [ 'fields', 'biomass', 1, 0], 'glucose': [ 'fields', 'glucose', 1, 0]}}, 'instance': <spatio_flux.processes.dfba.DynamicFBA object at 0x128068ed0>, 'interval': 1.0, 'outputs': { 'substrates': { 'acetate': [ 'fields', 'acetate', 1, 0], 'biomass': [ 'fields', 'biomass', 1, 0], 'glucose': [ 'fields', 'glucose', 1, 0]}}, 'shared': None}, 'emitter': { 'address': 'local:ram-emitter', 'config': {'emit': {'fields': 'any', 'global_time': 'any'}}, 'inputs': {'fields': ['fields'], 'global_time': ['global_time']}, 'instance': <process_bigraph.emitter.RAMEmitter object at 0x11fbb4ad0>, 'outputs': None}, 'fields': { 'acetate': array([[0.94243295], [0.22249636]]), 'biomass': array([[0.50279638], [0.30531076]]), 'glucose': array([[0.18712085], [0.8048707 ]])}, 'global_time': 0.0})
# change some initial values
v2.set_value(path = ['fields', 'glucose', 0, 0], value=10)
v2.set_value(path = ['fields', 'biomass', 0, 0], value=0.1)
field = v2.get_value(['fields'])
print(field)
{'glucose': array([[10. ], [ 0.8048707]]), 'acetate': array([[0.94243295], [0.22249636]]), 'biomass': array([[0.1 ], [0.30531076]])}
v2.run(60)
v2.get_timeseries(as_dataframe=True)
/global_time | /fields/glucose | /fields/acetate | /fields/biomass | |
---|---|---|---|---|
0 | 0.0 | [[10.0], [0.8048706975269881]] | [[0.9424329478919963], [0.22249635975890014]] | [[0.1], [0.3053107553015897]] |
1 | 1.0 | [[9.904761904761905], [0.6165488346421795]] | [[0.9545410000880855], [0.05491255366842457]] | [[0.1079432568708625], [0.3248588221508157]] |
2 | 2.0 | [[9.80200585245463], [0.43716453723748616]] | [[0.9675168875642264], [0.0]] | [[0.11651530697082768], [0.3411210770331022]] |
3 | 3.0 | [[9.691145527078628], [0.27803982449204534]] | [[0.9814117183137139], [0.0]] | [[0.12576552148631978], [0.35397004919062214]] |
4 | 4.0 | [[9.571550338512791], [0.15154530936018212]] | [[0.99627709547691], [0.0]] | [[0.13574706721093277], [0.36376254935005725]] |
... | ... | ... | ... | ... |
56 | 56.0 | [[0.0], [0.02329114629515195]] | [[0.0], [0.0]] | [[0.9893401479522954], [0.3717590284394552]] |
57 | 57.0 | [[0.0], [0.02329114629515195]] | [[0.0], [0.0]] | [[0.9893401479522954], [0.3717590284394552]] |
58 | 58.0 | [[0.0], [0.02329114629515195]] | [[0.0], [0.0]] | [[0.9893401479522954], [0.3717590284394552]] |
59 | 59.0 | [[0.0], [0.02329114629515195]] | [[0.0], [0.0]] | [[0.9893401479522954], [0.3717590284394552]] |
60 | 60.0 | [[0.0], [0.02329114629515195]] | [[0.0], [0.0]] | [[0.9893401479522954], [0.3717590284394552]] |
61 rows Ć 4 columns
# get a list of all the paths so they can be plotted together in a single graph
all_paths = []
for i in range(rows):
for j in range(columns):
# get the paths for this location
location_path = []
for mol_id in mol_ids:
this_path = build_path(path, mol_id, i, j)
rendered_path = render_path(this_path)
location_path.append(rendered_path)
all_paths.append(location_path)
print(all_paths)
[['/fields/glucose/0/0', '/fields/acetate/0/0', '/fields/biomass/0/0'], ['/fields/glucose/1/0', '/fields/acetate/1/0', '/fields/biomass/1/0']]
v2.plot_timeseries(
subplot_size=(8, 3),
combined_vars=all_paths
)
v2.show_video()
Diffusion/Advection¶
This approach models the physical processes of diffusion and advection in two dimensions, providing a way to simulate how substances spread and are transported across a spatial domain, essential for understanding patterns of concentration over time and space.
bounds = (10.0, 10.0)
n_bins = (10, 10)
mol_ids = [
'glucose',
'acetate',
'biomass'
]
diffusion_rate = 1e-1
diffusion_dt = 1e-1
advection_coeffs = {
'biomass': (0, -0.1)
}
path = ['fields']
v3 = Vivarium(processes=PROCESS_DICT, types=TYPES_DICT)
for mol_id in mol_ids:
v3.add_object(
name=mol_id,
path=path,
value=np.random.rand(n_bins[0], n_bins[1])
)
v3.add_process(name='diffusion_advection',
process_id='DiffusionAdvection',
config={
'n_bins': n_bins,
'bounds': bounds,
'default_diffusion_rate': diffusion_rate,
'default_diffusion_dt': diffusion_dt,
# 'diffusion_coeffs': diffusion_coeffs_all,
'advection_coeffs': advection_coeffs,
},
inputs={'fields': ['fields']},
outputs={'fields': ['fields']}
)
# add an emitter to save results
v3.add_emitter()
v3.diagram(dpi='70')
v3.run(60)
v3.plot_snapshots(n_snapshots=5)
v3.show_video()
COMETS (Computation Of Microbial Ecosystems in Time and Space)¶
COMETS combines dynamic FBA with spatially resolved physical processes (like diffusion and advection) to simulate the growth, metabolism, and interaction of microbial communities within a structured two-dimensional environment, capturing both biological and physical complexities.
bounds = (10.0, 10.0)
n_bins = (10, 10)
mol_ids = [
'glucose',
'acetate',
'biomass'
]
diffusion_rate = 1e-1
diffusion_dt = 1e-1
advection_coeffs = {
'biomass': (0, -0.1)
}
path = ['fields']
v4 = Vivarium(processes=PROCESS_DICT, types=TYPES_DICT)
# create the molecular fields
# for mol_id in mol_ids:
v4.add_object(
name='glucose',
path=path,
value=np.random.rand(n_bins[0], n_bins[1])
)
v4.add_object(
name='biomass',
path=path,
value=np.ones((n_bins[0], n_bins[1])) * 0.01
)
v4.add_object(
name='acetate',
path=path,
value=np.zeros((n_bins[0], n_bins[1]))
)
# add a diffusion/advection process
v4.add_process(name='diffusion_advection',
process_id='DiffusionAdvection',
config={
'n_bins': n_bins,
'bounds': bounds,
'default_diffusion_rate': diffusion_rate,
'default_diffusion_dt': diffusion_dt,
'advection_coeffs': advection_coeffs},
inputs={'fields': ['fields']},
outputs={'fields': ['fields']}
)
# add a dynamic FBA process at every location
for i in range(n_bins[0]):
for j in range(n_bins[1]):
dfba_name = f"dFBA[{i},{j}]"
path_name = build_path(path, 'mol_id', i, j)
print(f'Adding {dfba_name} to {path_name}\n')
# add a process for this location
v4.add_process(
name=dfba_name,
process_id="DynamicFBA",
config=dfba_config,
)
v4.connect_process(
process_name=dfba_name,
inputs={"substrates": {
mol_id: build_path(path, mol_id, i, j)
for mol_id in mol_ids}},
outputs={"substrates": {
mol_id: build_path(path, mol_id, i, j)
for mol_id in mol_ids}}
)
# add an emitter to save results
v4.add_emitter()
v4.diagram(dpi='70')
Adding dFBA[0,0] to ['fields', 'mol_id', 0, 0] Adding dFBA[0,1] to ['fields', 'mol_id', 0, 1] Adding dFBA[0,2] to ['fields', 'mol_id', 0, 2] Adding dFBA[0,3] to ['fields', 'mol_id', 0, 3] Adding dFBA[0,4] to ['fields', 'mol_id', 0, 4] Adding dFBA[0,5] to ['fields', 'mol_id', 0, 5] Adding dFBA[0,6] to ['fields', 'mol_id', 0, 6] Adding dFBA[0,7] to ['fields', 'mol_id', 0, 7] Adding dFBA[0,8] to ['fields', 'mol_id', 0, 8] Adding dFBA[0,9] to ['fields', 'mol_id', 0, 9] Adding dFBA[1,0] to ['fields', 'mol_id', 1, 0] Adding dFBA[1,1] to ['fields', 'mol_id', 1, 1] Adding dFBA[1,2] to ['fields', 'mol_id', 1, 2] Adding dFBA[1,3] to ['fields', 'mol_id', 1, 3] Adding dFBA[1,4] to ['fields', 'mol_id', 1, 4] Adding dFBA[1,5] to ['fields', 'mol_id', 1, 5] Adding dFBA[1,6] to ['fields', 'mol_id', 1, 6] Adding dFBA[1,7] to ['fields', 'mol_id', 1, 7] Adding dFBA[1,8] to ['fields', 'mol_id', 1, 8] Adding dFBA[1,9] to ['fields', 'mol_id', 1, 9] Adding dFBA[2,0] to ['fields', 'mol_id', 2, 0] Adding dFBA[2,1] to ['fields', 'mol_id', 2, 1] Adding dFBA[2,2] to ['fields', 'mol_id', 2, 2] Adding dFBA[2,3] to ['fields', 'mol_id', 2, 3] Adding dFBA[2,4] to ['fields', 'mol_id', 2, 4] Adding dFBA[2,5] to ['fields', 'mol_id', 2, 5] Adding dFBA[2,6] to ['fields', 'mol_id', 2, 6] Adding dFBA[2,7] to ['fields', 'mol_id', 2, 7] Adding dFBA[2,8] to ['fields', 'mol_id', 2, 8] Adding dFBA[2,9] to ['fields', 'mol_id', 2, 9] Adding dFBA[3,0] to ['fields', 'mol_id', 3, 0] Adding dFBA[3,1] to ['fields', 'mol_id', 3, 1] Adding dFBA[3,2] to ['fields', 'mol_id', 3, 2] Adding dFBA[3,3] to ['fields', 'mol_id', 3, 3] Adding dFBA[3,4] to ['fields', 'mol_id', 3, 4] Adding dFBA[3,5] to ['fields', 'mol_id', 3, 5] Adding dFBA[3,6] to ['fields', 'mol_id', 3, 6] Adding dFBA[3,7] to ['fields', 'mol_id', 3, 7] Adding dFBA[3,8] to ['fields', 'mol_id', 3, 8] Adding dFBA[3,9] to ['fields', 'mol_id', 3, 9] Adding dFBA[4,0] to ['fields', 'mol_id', 4, 0] Adding dFBA[4,1] to ['fields', 'mol_id', 4, 1] Adding dFBA[4,2] to ['fields', 'mol_id', 4, 2] Adding dFBA[4,3] to ['fields', 'mol_id', 4, 3] Adding dFBA[4,4] to ['fields', 'mol_id', 4, 4] Adding dFBA[4,5] to ['fields', 'mol_id', 4, 5] Adding dFBA[4,6] to ['fields', 'mol_id', 4, 6] Adding dFBA[4,7] to ['fields', 'mol_id', 4, 7] Adding dFBA[4,8] to ['fields', 'mol_id', 4, 8] Adding dFBA[4,9] to ['fields', 'mol_id', 4, 9] Adding dFBA[5,0] to ['fields', 'mol_id', 5, 0] Adding dFBA[5,1] to ['fields', 'mol_id', 5, 1] Adding dFBA[5,2] to ['fields', 'mol_id', 5, 2] Adding dFBA[5,3] to ['fields', 'mol_id', 5, 3] Adding dFBA[5,4] to ['fields', 'mol_id', 5, 4] Adding dFBA[5,5] to ['fields', 'mol_id', 5, 5] Adding dFBA[5,6] to ['fields', 'mol_id', 5, 6] Adding dFBA[5,7] to ['fields', 'mol_id', 5, 7] Adding dFBA[5,8] to ['fields', 'mol_id', 5, 8] Adding dFBA[5,9] to ['fields', 'mol_id', 5, 9] Adding dFBA[6,0] to ['fields', 'mol_id', 6, 0] Adding dFBA[6,1] to ['fields', 'mol_id', 6, 1] Adding dFBA[6,2] to ['fields', 'mol_id', 6, 2] Adding dFBA[6,3] to ['fields', 'mol_id', 6, 3] Adding dFBA[6,4] to ['fields', 'mol_id', 6, 4] Adding dFBA[6,5] to ['fields', 'mol_id', 6, 5] Adding dFBA[6,6] to ['fields', 'mol_id', 6, 6] Adding dFBA[6,7] to ['fields', 'mol_id', 6, 7] Adding dFBA[6,8] to ['fields', 'mol_id', 6, 8] Adding dFBA[6,9] to ['fields', 'mol_id', 6, 9] Adding dFBA[7,0] to ['fields', 'mol_id', 7, 0] Adding dFBA[7,1] to ['fields', 'mol_id', 7, 1] Adding dFBA[7,2] to ['fields', 'mol_id', 7, 2] Adding dFBA[7,3] to ['fields', 'mol_id', 7, 3] Adding dFBA[7,4] to ['fields', 'mol_id', 7, 4] Adding dFBA[7,5] to ['fields', 'mol_id', 7, 5] Adding dFBA[7,6] to ['fields', 'mol_id', 7, 6] Adding dFBA[7,7] to ['fields', 'mol_id', 7, 7] Adding dFBA[7,8] to ['fields', 'mol_id', 7, 8] Adding dFBA[7,9] to ['fields', 'mol_id', 7, 9] Adding dFBA[8,0] to ['fields', 'mol_id', 8, 0] Adding dFBA[8,1] to ['fields', 'mol_id', 8, 1] Adding dFBA[8,2] to ['fields', 'mol_id', 8, 2] Adding dFBA[8,3] to ['fields', 'mol_id', 8, 3] Adding dFBA[8,4] to ['fields', 'mol_id', 8, 4] Adding dFBA[8,5] to ['fields', 'mol_id', 8, 5] Adding dFBA[8,6] to ['fields', 'mol_id', 8, 6] Adding dFBA[8,7] to ['fields', 'mol_id', 8, 7] Adding dFBA[8,8] to ['fields', 'mol_id', 8, 8] Adding dFBA[8,9] to ['fields', 'mol_id', 8, 9] Adding dFBA[9,0] to ['fields', 'mol_id', 9, 0] Adding dFBA[9,1] to ['fields', 'mol_id', 9, 1] Adding dFBA[9,2] to ['fields', 'mol_id', 9, 2] Adding dFBA[9,3] to ['fields', 'mol_id', 9, 3] Adding dFBA[9,4] to ['fields', 'mol_id', 9, 4] Adding dFBA[9,5] to ['fields', 'mol_id', 9, 5] Adding dFBA[9,6] to ['fields', 'mol_id', 9, 6] Adding dFBA[9,7] to ['fields', 'mol_id', 9, 7] Adding dFBA[9,8] to ['fields', 'mol_id', 9, 8] Adding dFBA[9,9] to ['fields', 'mol_id', 9, 9]
v4.run(60)
v4.plot_snapshots(n_snapshots=5)
v4.show_video()
v4.plot_timeseries(
subplot_size=(8, 3),
query=[
'/fields/glucose/0/0',
'/fields/acetate/0/0',
'/fields/biomass/0/0',
'/global_time',
]
)
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[29], line 1 ----> 1 v4.plot_timeseries( 2 subplot_size=(8, 3), 3 query=[ 4 '/fields/glucose/0/0', 5 '/fields/acetate/0/0', 6 '/fields/biomass/0/0', 7 'global_time', 8 ] 9 ) File ~/code/vivarium-interface/vivarium/vivarium.py:664, in Vivarium.plot_timeseries(self, query, significant_digits, subplot_size, ncols, combined_vars) 646 def plot_timeseries(self, 647 query=None, 648 significant_digits=None, (...) 651 combined_vars=None 652 ): 653 """ 654 Plots the timeseries data for all variables using matplotlib. 655 Each variable (or group of variables) gets its own subplot. (...) 662 combined_vars (list of lists, optional): Lists of variables to combine into the same subplot. Default is None. 663 """ --> 664 timeseries = self.get_timeseries(query=query, significant_digits=significant_digits) 665 timeseries = flatten_timeseries_to_scalar_paths(timeseries) 667 # Extract time vector File ~/code/vivarium-interface/vivarium/vivarium.py:615, in Vivarium.get_timeseries(self, query, significant_digits, as_dataframe) 606 def get_timeseries(self, 607 query=None, 608 significant_digits=None, 609 as_dataframe=False, 610 ): 611 """ 612 Gets the results and converts them to timeseries format 613 """ --> 615 emitter_results = self.get_results(query=query, 616 significant_digits=significant_digits) 618 def append_to_timeseries(timeseries, state, path=()): 619 if isinstance(state, dict): File ~/code/vivarium-interface/vivarium/vivarium.py:602, in Vivarium.get_results(self, query, significant_digits) 600 if "emitter" in path: 601 emitter = get_path(self.composite.state, path) --> 602 results.extend(emitter['instance'].query(query)) 604 return round_floats(results, significant_digits=significant_digits) File ~/code/process-bigraph/process_bigraph/emitter.py:248, in RAMEmitter.query(self, query) 246 result = {} 247 for path in query: --> 248 element = get_path(t, path) 249 result = set_path(result, path, element) 250 results.append(result) File ~/code/bigraph-schema/bigraph_schema/utilities.py:200, in get_path(tree, path) 198 return None 199 else: --> 200 return get_path(tree[head], path[1:]) File ~/code/bigraph-schema/bigraph_schema/utilities.py:200, in get_path(tree, path) 198 return None 199 else: --> 200 return get_path(tree[head], path[1:]) File ~/code/bigraph-schema/bigraph_schema/utilities.py:197, in get_path(tree, path) 195 else: 196 head = path[0] --> 197 if not tree or head not in tree: 198 return None 199 else: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()