# Magic
%matplotlib inline
%config Completer.use_jedi = False
SalvusToolbox
to generate a parameterized model of a building.import os
import matplotlib.pyplot as plt
import numpy as np
import salvus.flow.simple_config as config
import salvus.toolbox.toolbox as st
import salvus.toolbox.toolbox_geotech as st_geo
from salvus.flow import api
SALVUS_FLOW_SITE_NAME = os.environ.get("SITE_NAME", "local")
get_simple_building
function we've imported above. The function takes a variety of values which parameterize how the mesh is generated. The values below produce a 50 "story" building with a basement foundation. As with the rest of Salvus, all units are SI.n_stories = 50
wall_width = 1.0
story_height = 3.0
ceiling_height = 0.3
building_width = 20.0
basement_depth = 20.0
basement_width = 50.0
f_max = 500.0
vs_min = 1500.0
nelem_per_wavelength = 2.0
(mesh, bnd)
. The first entry here is indeed our mesh -- we'll plot it in a few cells -- and the bnd
value represents the minimum distance to which the mesh was extruded to attach absorbing boundary layers. This value will be helpful later when we're setting up the simulation.mesh, bnd = st_geo.get_simple_building(
f_max=f_max,
vs_min=vs_min,
n_stories=n_stories,
wall_width=wall_width,
story_height=story_height,
basement_width=basement_width,
basement_depth=basement_depth,
building_width=building_width,
ceiling_height=ceiling_height,
nelem_per_wavelength=nelem_per_wavelength,
)
vs_min
value we defined above for our shear wave velocity, and use a simple scaling relation such that the p-wave velocity is twice the s-wave velocity. These parameters of course can be changed, and can also be made heterogeneous, but one must always keep in mind the resolution criterion (here: 2 elements per wavelength given a minimum velocity of m/s) in mind.nodes = mesh.get_element_nodes()[:, :, 0]
mesh.attach_field("RHO", np.ones_like(nodes) * 1000)
mesh.attach_field("VS", np.ones_like(nodes) * vs_min)
mesh.attach_field("VP", np.ones_like(nodes) * vs_min * 2)
mesh
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x713d0c4bf2d0>
stf = config.stf.Ricker(center_frequency=f_max / 2)
source = config.source.cartesian.VectorPoint2D(
x=-20, y=0.0, fx=1.0, fy=1.0, source_time_function=stf
)
n_rec = 100
x_rec = np.ones(n_rec) * -building_width / 2
y_rec = np.linspace(0, n_stories * story_height, n_rec)
receivers = [
config.receiver.cartesian.Point2D(
x=x,
y=y,
station_code=f"{_i:03d}",
fields=["velocity", "gradient-of-displacement"],
)
for _i, (x, y) in enumerate(zip(x_rec, y_rec))
]
# Initialize with sources and receivers.
w = config.simulation.Waveform(mesh=mesh, sources=source, receivers=receivers)
# Set end time, start time is automatically determined.
w.physics.wave_equation.end_time_in_seconds = 0.1
# Define and attach our absorbing boundaries.
ab = config.boundary.Absorbing(
side_sets=["x0", "x1", "y0"], width_in_meters=bnd, taper_amplitude=f_max
)
w.physics.wave_equation.boundaries = [ab]
# Use simplified HDF5 source output.
w.output.point_data.format = "hdf5"
# Save the volumetric wavefield for visualization purposes.
# w.output.volume_data.format = "hdf5"
# w.output.volume_data.filename = "output.h5"
# w.output.volume_data.fields = ["displacement"]
# w.output.volume_data.sampling_interval_in_time_steps = 10
# Ensure that Salvus will accept our parameters.
w.validate()
# Plot the mesh with the sources and receivers.
w