Version:
This tutorial is presented as Python code running inside a Jupyter Notebook, the recommended way to use Salvus. To run it yourself you can copy/type each individual cell or directly download the full notebook, including all required files.

Diffusion Equation

We consider a spatial domain ΩRd\Omega \subset \mathbf{R}^d (d = 2 or 3), a time interval I=[0,T]I = [0, T], and a diffusion equation of the following form:
m0(x)tu(x,t)(D(x)u(x,t))=0, m_0(\mathbf{x}) \partial_t u(\mathbf{x},t) - \nabla \cdot \big(\mathcal{D}(\mathbf{x}) \nabla u(\mathbf{x},t)\big) = 0,
with initial conditions
u(x,0)=uinit(x)u(\mathbf{x},0) = u_{\text{init}}(\mathbf{x}).
Here, uu denotes the space- and time-dependent diffusive field and uinitu_{\text{init}} are describes external forces. t\partial_t denotes the first time derivative and \nabla the spatial gradient operator. Furthermore, the scalar parameter m0m_0 and the symmetric second-order diffusion tensor D\mathcal{D} are space-dependent coefficients.
D\mathcal{D} can be related to a Wiener process using the relation
\mathcal{D} = \frac{1}{2} \sigma \sigma\,^T,
which direction-dependent smoothing lengths σi\sigma_i.
For the special case of m0=1m_0 = 1 and T=1T = 1, σ\sigma corresponds to the standard deviation of the Gaussian smoothing in meters.
In the isotropic case, D\mathcal{D} simplifies to a scalar value, in which case we may re-write the diffusion equation as
m0(x)tu(x,t)(m1(x)u(x,t))=0, m_0(\mathbf{x}) \partial_t u(\mathbf{x},t) - \nabla \cdot \big(m_1(\mathbf{x}) \nabla u(\mathbf{x},t)\big) = 0,
with m1=0.5σ2m_1 = 0.5 * \sigma^2 and the isotropic smoothing length σ\sigma.
Copy
# Standard Python packages
import matplotlib.pyplot as plt
import numpy as np
import os
import toml

# Salvus imports
import salvus.namespace as sn

SALVUS_FLOW_SITE_NAME = os.environ.get("SITE_NAME", "token")
mesh = sn.simple_mesh.basic_mesh.CartesianHomogeneousAcoustic2D(
    x_max=4.0, y_max=6.0, vp=1000.0, rho=1000.0, max_frequency=5000.0
).create_mesh()

# We don't need any material parameters.
mesh.elemental_fields = {}
input_mesh = mesh.copy()
input_mesh.attach_field("some_field", np.random.randn(mesh.npoint))
input_mesh.map_nodal_fields_to_element_nodal()
input_mesh.write_h5("initial_values.h5")
input_mesh
<salvus.mesh.unstructured_mesh.UnstructuredMesh at 0x7fa585943750>
smoothing_length_in_meters = 0.1

mesh.attach_field("M0", np.ones_like(mesh.get_element_nodes()[:, :, 0]))
mesh.attach_field(
    "M1",
    0.5
    * smoothing_length_in_meters**2
    * np.ones_like(mesh.get_element_nodes()[:, :, 0]),
)
mesh.attach_field("fluid", np.ones(mesh.nelem))
mesh
<salvus.mesh.unstructured_mesh.UnstructuredMesh at 0x7fa5859764d0>
sim = sn.simple_config.simulation.Diffusion(mesh=mesh)

sim.domain.polynomial_order = 1

sim.physics.diffusion_equation.time_step_in_seconds = 1e-3
sim.physics.diffusion_equation.courant_number = 0.06

sim.physics.diffusion_equation.initial_values.filename = "initial_values.h5"
sim.physics.diffusion_equation.initial_values.format = "hdf5"
sim.physics.diffusion_equation.initial_values.field = "some_field"

sim.physics.diffusion_equation.final_values.filename = "out.h5"

sim.output.volume_data.filename = "diffusion.h5"
sim.output.volume_data.format = "hdf5"
sim.output.volume_data.fields = ["phi"]
sim.output.volume_data.sampling_interval_in_time_steps = 10

sim.validate()
sn.api.run(
    site_name=SALVUS_FLOW_SITE_NAME,
    input_file=sim,
    ranks=1,
    output_folder="output",
    get_all=True,
    overwrite=True,
    wall_time_in_seconds=600,
)
SalvusJob `job_2403150930502348_7aaeda8d53` running on `local` with 1 rank(s).
Site information:
  * Salvus version: 0.12.16
  * Floating point size: 32
* Downloaded 8.0 MB of results to `output`.
* Total run time: 1.01 seconds.
* Pure simulation time: 0.71 seconds.
<salvus.flow.sites.salvus_job.SalvusJob at 0x7fa57d6bf150>
mesh = sn.UnstructuredMesh.from_h5(filename="output/out.h5")
mesh
<salvus.mesh.unstructured_mesh.UnstructuredMesh at 0x7fa57d61be90>
PAGE CONTENTS