# maximum element size
hmax = min(solid_vs, fluid_vp) / fmax / elements_per_wavelength
# compute number of elements
nelemx = int(lx / hmax) + 1
nelemy = int(ly / hmax) + 1
# generate rectilinear grid
sg = mesh_block.generators.cartesian.rectangle_2d(
nelemx, nelemy, max_x=lx, max_y=ly
)
# create unstructured mesh
m = sg.get_unstructured_mesh()
# make fluid blocks
fluid = np.zeros((nelemx, nelemy), dtype="bool")
for i in range(block_size):
for j in range(block_size):
fluid[i :: block_size * 2, j :: block_size * 2] = True
fluid[
i + block_size :: block_size * 2, j + block_size :: block_size * 2
] = True
fluid = fluid.ravel()
# a mask for the solid elements
nfluid = np.logical_not(fluid)
# attach material properties
vpa = nfluid * solid_vp + fluid * fluid_vp
vsa = nfluid * solid_vs
rhoa = nfluid * solid_rho + fluid * fluid_rho
m.attach_field("fluid", fluid.astype("int"))
m.attach_field("VP", np.outer(vpa, np.ones(m.nodes_per_element)))
m.attach_field("VS", np.outer(vsa, np.ones(m.nodes_per_element)))
m.attach_field("RHO", np.outer(rhoa, np.ones(m.nodes_per_element)))
# define outer boundaries
m.find_side_sets(mode="cartesian")
# compute time step
dt, dt_elem = m.compute_dt(vpa, courant_number, fast=False)
m.attach_global_variable("dt", dt)
m.attach_field("dt", dt_elem) # this is mainly for visualization
print("================")
print("nelem = %d" % m.nelem)
print("dt = %e" % dt)
print("================")