SpECTRE Documentation Coverage Report
Current view: top level - __w/spectre/spectre/build/docs/tmp/notebooks_md - VisualizationWithPython.md Hit Total Coverage
Commit: 1d64892952139ddfbae7cdbdcd87dce73af8d9fe Lines: 0 1 0.0 %
Date: 2025-12-12 21:49:13
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : ## Visualization with Python {#tutorial_vis_python}
       2             : 
       3             : This tutorial shows you how to load 3D volume data in Python and visualize it
       4             : using `matplotlib`.
       5             : 
       6             : First, you need access to the `spectre` Python bindings. A simple way to do this
       7             : is to run a Jupyter server from the build directory:
       8             : 
       9             : ```sh
      10             : ./bin/python-spectre -m jupyterlab
      11             : ```
      12             : 
      13             : You can find detailed instruction in the tutorial on \ref spectre_using_python.
      14             : 
      15             : > Note for VSCode users: You can also select this Jupyter server as kernel for
      16             : > notebooks running in VSCode (see [docs](https://code.visualstudio.com/docs/datascience/jupyter-notebooks#_connect-to-a-remote-jupyter-server)).
      17             : 
      18             : Now we can import modules from the `spectre` Python package.
      19             : 
      20             : 
      21             : ```python
      22             : # Distributed under the MIT License.
      23             : # See LICENSE.txt for details.
      24             : 
      25             : import matplotlib.pyplot as plt
      26             : import numpy as np
      27             : import os
      28             : 
      29             : plt.style.use("../Examples/plots.mplstyle")
      30             : ```
      31             : 
      32             : ## Select an observation
      33             : 
      34             : First, we open the H5 volume data files from a simulation and get a list of all
      35             : available observations and their times:
      36             : 
      37             : 
      38             : ```python
      39             : from spectre.IO.H5 import list_observations, open_volfiles
      40             : import glob
      41             : 
      42             : h5files = glob.glob(
      43             :     # Point this to your volume data files
      44             :     "BbhVolume*.h5"
      45             : )
      46             : subfile_name = "/VolumeData"
      47             : obs_ids, obs_times = list_observations(open_volfiles(h5files, subfile_name))
      48             : ```
      49             : 
      50             : We can also list all available variables in the volume data files:
      51             : 
      52             : 
      53             : ```python
      54             : import rich.columns
      55             : 
      56             : for volfile in open_volfiles(h5files, subfile_name, obs_ids[-1]):
      57             :     all_vars = volfile.list_tensor_components(obs_ids[-1])
      58             :     # Only look into the first file. The other should have the same variables.
      59             :     break
      60             : 
      61             : rich.print(rich.columns.Columns(all_vars))
      62             : ```
      63             : 
      64             : 
      65             : <pre style="white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace">ConformalFactor                 ExtrinsicCurvature_xx           ExtrinsicCurvature_yx          
      66             : ExtrinsicCurvature_yy           ExtrinsicCurvature_zx           ExtrinsicCurvature_zy          
      67             : ExtrinsicCurvature_zz           InertialCoordinates_x           InertialCoordinates_y          
      68             : InertialCoordinates_z           Lapse                           RadiallyCompressedCoordinates_x
      69             : RadiallyCompressedCoordinates_y RadiallyCompressedCoordinates_z ShiftExcess_x                  
      70             : ShiftExcess_y                   ShiftExcess_z                   Shift_x                        
      71             : Shift_y                         Shift_z                         SpatialMetric_xx               
      72             : SpatialMetric_yx                SpatialMetric_yy                SpatialMetric_zx               
      73             : SpatialMetric_zy                SpatialMetric_zz                                               
      74             : </pre>
      75             : 
      76             : 
      77             : 
      78             : ### Interpolate to a slice
      79             : 
      80             : One way of visualizing your 3D volume data in a 2D plot is with a slice. Use
      81             : `interpolate_to_points` to interpolate your volume data to any set of
      82             : coordinates:
      83             : 
      84             : 
      85             : ```python
      86             : from spectre.IO.Exporter import interpolate_to_points
      87             : 
      88             : # Coordinates of a regular grid in the xy plane
      89             : x, y = np.meshgrid(np.linspace(-15, 15, 300), np.linspace(-15, 15, 300))
      90             : z = np.zeros(x.shape)
      91             : 
      92             : # Interpolation can be slow, so it's useful to cache the result. Remember to
      93             : # delete the cache file if you change anything.
      94             : cache_file = "interpolated_data.npy"
      95             : if os.path.isfile(cache_file):
      96             :     lapse = np.load(cache_file)
      97             : else:
      98             :     lapse = np.array(
      99             :         interpolate_to_points(
     100             :             h5files,
     101             :             subfile_name=subfile_name,
     102             :             observation_id=obs_ids[-1],
     103             :             tensor_components=["Lapse"],
     104             :             target_points=[x.flatten(), y.flatten(), z.flatten()],
     105             :         )
     106             :     ).reshape(x.shape)
     107             :     np.save(cache_file, lapse)
     108             : ```
     109             : 
     110             : Now we can plot the 2D slice with `matplotlib`:
     111             : 
     112             : 
     113             : ```python
     114             : # Plot lapse
     115             : plt.contourf(x, y, np.log(1 - lapse))
     116             : 
     117             : # Plot circles for black holes
     118             : ax = plt.gca()
     119             : for bh_pos in [-8, 8]:
     120             :     ax.add_patch(
     121             :         plt.Circle(xy=(bh_pos, 0), radius=0.89, color="black", fill=True)
     122             :     )
     123             : 
     124             : # Make plot square
     125             : ax.set_aspect("equal")
     126             : ```
     127             : 
     128             :     /var/folders/xp/5t2ny359187c4ljckf8sz3m80000gn/T/ipykernel_19858/3375439396.py:2: RuntimeWarning: invalid value encountered in subtract
     129             :       plt.contourf(x, y, np.log(1 - lapse))
     130             : 
     131             : 
     132             : 
     133             :     
     134             : ![png](VisualizationWithPython_files/VisualizationWithPython_9_1.png)
     135             :     
     136             : 
     137             : 
     138             : ### Plot individual elements
     139             : 
     140             : You can also iterate over elements in your volume data to plot things like
     141             : element boundaries, collocation points, etc. Use `iter_elements`:
     142             : 
     143             : 
     144             : ```python
     145             : from spectre.IO.H5.IterElements import iter_elements
     146             : 
     147             : # Create a 3D plot
     148             : ax = plt.gcf().add_subplot(111, projection="3d")
     149             : ax.axis("off")
     150             : 
     151             : # Iterate over elements
     152             : for element in iter_elements(
     153             :     open_volfiles(h5files, subfile_name),
     154             :     obs_ids=obs_ids[0],
     155             :     element_patterns=["B3,*"],  # Only plot elements in block 3
     156             : ):
     157             :     # Draw outline of the element by mapping the edges of the logical cube to
     158             :     # inertial coordinates using the element map
     159             :     for d in range(3):
     160             :         for edge in range(4):
     161             :             line = np.zeros((3, 100))
     162             :             line[d, :] = np.linspace(-1, 1, 100)
     163             :             line[(d + 1) % 3, :] = 2 * (edge % 2) - 1
     164             :             line[(d + 2) % 3, :] = 2 * (edge // 2) - 1
     165             :             x, y, z = element.map(line)
     166             :             ax.plot(x, y, z, color="black")
     167             : 
     168             : # Make plot square
     169             : ax.set_aspect("equal")
     170             : ```
     171             : 
     172             : 
     173             :     
     174             : ![png](VisualizationWithPython_files/VisualizationWithPython_11_0.png)
     175             :     
     176             : 
     177             : 
     178             : ### Transforming volume data
     179             : 
     180             : Often you want to post-process volume data to compute derived quantities from
     181             : the ones the simulation has written out. You can sometimes do this within tools
     182             : like ParaView (e.g. using ParaView's "Calculator" filter) if the computation is
     183             : simple enough and pointwise (i.e., needs no derivatives or other mesh
     184             : information). If you can't get what you need in ParaView, you can use `spectre
     185             : transform-vol`. It takes any Python function (a "kernel"), runs it over your
     186             : volume data, and writes the result back into the files.
     187             : 
     188             : For example, let's add the number of grid points in each element as a field
     189             : that we can visualize:
     190             : 
     191             : ```sh
     192             : spectre transform-vol BbhVolume*.h5 -d VolumeData \
     193             :     -k spectre.Spectral.Mesh3D:extents
     194             : ```
     195             : 
     196             : You will be prompted to select an output dataset name (hit enter to select the
     197             : default "Extents"). The result will be written back into the H5 files. If you
     198             : now regenerate an XDMF file for the volume data you will be able to see the
     199             : output in ParaView.
     200             : 
     201             : The `transform-vol` tool supports arbitrary Python functions as kernels. Many
     202             : Python functions from the `spectre` module are useful kernels. For example,
     203             : here are some useful kernels:
     204             : 
     205             : - p-refinement (number of grid points per dimension):
     206             :   `spectre.Spectral.Mesh3D:extents`
     207             : - Relative/absolute truncation error (from power monitors):
     208             :   `spectre.NumericalAlgorithms.LinearOperators:relative_truncation_error`
     209             :   or `absolute_truncation_error`
     210             : - Coordinates in different frames: `Element:grid_coordinates` or
     211             :   `Element:distorted_coordinates`
     212             : 
     213             : You can find more useful kernels by browsing the `spectre.PointwiseFunctions`
     214             : module: https://spectre-code.org/py/_autosummary/spectre.PointwiseFunctions.html
     215             : 
     216             : You can also write your own kernels. Create a Python file, e.g. `kernel.py`, and
     217             : write a function like this:
     218             : 
     219             : 
     220             : ```python
     221             : %%file kernel.py
     222             : from spectre.DataStructures.Tensor import Scalar, DataVector
     223             : 
     224             : def lapse_squared(lapse: Scalar[DataVector]) -> Scalar[DataVector]:
     225             :     return np.array(lapse)**2
     226             : ```
     227             : 
     228             : Now you can run this kernel over your volume data like this:
     229             : 
     230             : ```sh
     231             : spectre transform-vol BbhVolume*.h5 -d VolumeData \
     232             :     -e kernel.py -k lapse_squared
     233             : ```
     234             : 
     235             : You can find more details by running `spectre transform-vol --help`.
     236             : 
     237             : 

Generated by: LCOV version 1.14