compression-safeguards
  • Home
  • Try the safeguards

API Reference

  • Overview
  • compression_safeguards
    • api
    • safeguards
      • abc
      • combinators
        • all
        • any
        • assume_safe
        • select
      • eb
      • pointwise
        • abc
        • eb
        • lossless
        • qoi
          • eb
        • same
        • sign
      • qois
      • stencil
        • abc
        • qoi
          • eb
    • utils
      • bindings
      • cast
      • error
      • intervals
      • typing
  • numcodecs_safeguards
    • checksum
    • compute
    • lossless
  • xarray_safeguards

Examples

  • Datasets
  • Special values
    • NaN values
    • Missing values
  • Regions of Interest (RoIs)
    • Latent Heat Flux
  • Quantities of Interest (QoIs)
    • Pointwise: Log-scale Specific Humidity
    • Semi-Pointwise: Kinetic energy
    • Higher-order derivatives
      • Example 1: $u(x, y) = {(x^2 + y^2)}^{3 \mathbin{/} 2} \mathbin{/} 9$
        • Lossless compression
        • Compressing u with lossy compressors
        • Compressing u using the safeguarded lossy compressors
        • Compressing u with OptZConfig
        • Visual comparison of the compressed Laplacians
      • Example 2: $u(x, y) = e^{4 x + 3 y}$
        • Lossless compression
        • Compressing u with lossy compressors
        • Compressing u using the safeguarded lossy compressors
        • Compressing u with OptZConfig
        • Visual comparison of the compressed natural logarithms of the Laplacians
    • Neighbourhood: Relative Vorticity
    • Bounding the dSSIM metric
  • Topology
    • Precipitation extrema
    • Isosurfaces
  • Error bound distributions
    • Absolute error bound
  • Safeguards on chunked data
    • xarray-safeguards
  • Preview
    • Incremental safeguards

Links

  • GitHub
  • PyPI
    • compression-safeguards
    • numcodecs-safeguards
    • xarray-safeguards
compression-safeguards
  • Examples
  • Quantities of Interest (QoIs)
  • Higher-order derivatives
  • Try     View Source

Preserving spatial derivatives with safeguards¶

In this example, which has been adopted from the ZFP evaluation at https://computing.llnl.gov/projects/zfp/zfp-and-derivatives, we compare how three different lossy compressors (ZFP, SZ3, and SPERR) affect the Laplacian of the data, and apply safeguards to guarantee that the Laplacian is preserved. We also briefly investigate the impact of tuning the error bound for a lossy error-bounded compressor to optimize the compression ratio after applying safeguards. We further compare the safeguards with the compressor configuration auto-tuner OptZConfig.

QPET supports mean error bounds over non-overlapping blocks of data, but not over overlapping windows of data, which are required to preserve an error over a finite-difference approximated spatial derivative. To be safe, QPET would need to be configured with a maximally conservative pointwise error bound, which is no different than configuring SPERR (or SZ3 or ZFP) with this error bound. Therefore, we do not compare with QPET in this example.

Copied!
from pathlib import Path

import humanize
import matplotlib as mpl
import numpy as np
import pandas as pd
from matplotlib import patheffects as PathEffects
from matplotlib import pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from mpl_toolkits.axes_grid1 import make_axes_locatable
from pathlib import Path import humanize import matplotlib as mpl import numpy as np import pandas as pd from matplotlib import patheffects as PathEffects from matplotlib import pyplot as plt from matplotlib.colors import LinearSegmentedColormap from mpl_toolkits.axes_grid1 import make_axes_locatable
Copied!
x = y = np.linspace(-1, 1, 1024)
Y, X = np.meshgrid(y, x, indexing="ij")
x = y = np.linspace(-1, 1, 1024) Y, X = np.meshgrid(y, x, indexing="ij")
Copied!
dx = float(x[1] - x[0])
dy = float(y[1] - y[0])
dy, dx
dx = float(x[1] - x[0]) dy = float(y[1] - y[0]) dy, dx
(0.0019550342130987275, 0.0019550342130987275)
Copied!
def compute_corrections_percentage(my_U: np.ndarray, orig_U: np.ndarray) -> float:
    return np.mean(my_U != orig_U)
def compute_corrections_percentage(my_U: np.ndarray, orig_U: np.ndarray) -> float: return np.mean(my_U != orig_U)
Copied!
# plot the Laplacian DU for a 2D field my_U
def plot_DU(
    compute_DU,
    my_U,
    cr,
    ax,
    title,
    DU_eb_abs,
    transform_symbol=None,
    my_DU=None,
    corr=None,
    my_U_it=None,
    cr_it=None,
    include_boundary=False,
    inset=True,
    inset_offset=(0.05, 0.05),
):
    show_err = my_DU is None

    if my_DU is None:
        my_DU = compute_DU(my_U)

    DU = compute_DU(U)

    vmin = np.nanmin(DU)
    vmax = np.nanmax(DU)

    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", size="5%", pad=0.05)

    ax.set_title(title)

    if show_err:
        err_v = np.mean(~(np.abs(my_DU - DU) <= DU_eb_abs))
        err_v = (
            0
            if err_v == 0
            else np.format_float_positional(100 * err_v, precision=1, min_digits=1)
            + "%"
        )
        if err_v == "0.0%":
            err_v = "<0.05%"

        t = ax.text(
            0.95,
            0.05,
            f"V={err_v}",
            ha="right",
            va="bottom",
            transform=ax.transAxes,
        )
        t.set_bbox(dict(facecolor="white", alpha=0.5, edgecolor="black"))

    # create a colourmap that includes the entire finite range of my_DU but
    #  assigns colours based on the range of DU to ensure consistent colours
    cx = np.linspace(
        (
            np.minimum(np.amin(np.nan_to_num(my_DU, nan=0, posinf=0, neginf=0)), vmin)
            - vmin
        )
        / (vmax - vmin),
        (
            np.maximum(vmax, np.amax(np.nan_to_num(my_DU, nan=0, posinf=0, neginf=0)))
            - vmin
        )
        / (vmax - vmin),
        256,
    )
    cmap = LinearSegmentedColormap.from_list("RdBu_r_ext", plt.get_cmap("RdBu_r")(cx))

    ax.fill_between(
        [0, 1],
        [1, 1],
        hatch="XX",
        edgecolor="magenta",
        facecolor="lavenderblush",
        transform=ax.transAxes,
        zorder=-13,
    )
    im = ax.imshow(my_DU, cmap=cmap, origin="lower", extent=(-1, 1, -1, 1), zorder=-12)

    ax.contour(
        X if include_boundary else X[1:-1, 1:-1],
        Y if include_boundary else Y[1:-1, 1:-1],
        my_DU,
        levels=10,
        colors="lightgrey",
        vmin=vmin,
        vmax=vmax,
        alpha=0.25,
        zorder=-11,
    )

    ax.set_rasterization_zorder(-10)
    ax.set_aspect("equal")

    if show_err:
        if corr is not None:
            da_hatch = my_U == corr

            if my_U_it is None:
                da_corr = da_hatch.astype(float)
            else:
                da_hatch_it = my_U_it == corr
                da_corr = (~da_hatch).astype(float) + (~da_hatch_it).astype(float)

            axin = ax.inset_axes(
                [*inset_offset, 1 / 3, 1 / 3],
                xticks=[],
                yticks=[],
            )
            axin.imshow(
                da_corr,
                cmap=mpl.colors.ListedColormap(["white", "green", "lawngreen"]),
                vmin=0,
                vmax=2,
                origin="lower",
                extent=(-1, 1, -1, 1),
                zorder=-10,
            )
            axin.set_title(
                "Corrections",
                path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")],
            )
        elif inset:
            da_err = ~(np.abs(my_DU - DU) <= DU_eb_abs)

            axin = ax.inset_axes(
                [*inset_offset, 1 / 3, 1 / 3],
                xticks=[],
                yticks=[],
            )
            axin.imshow(
                da_err,
                cmap=mpl.colors.ListedColormap(["white", "red"]),
                vmin=0,
                vmax=1,
                origin="lower",
                extent=(-1, 1, -1, 1),
                zorder=-10,
            )
            axin.set_title(
                "Violations",
                path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")],
            )

    t = ax.text(
        0.95,
        0.95,
        (
            rf"$\times$ {np.round(cr, 2)}"
            + ("" if cr_it is None else rf" ($\times$ {np.round(cr_it, 2)})")
        )
        if show_err
        else humanize.naturalsize(U.nbytes, binary=True),
        ha="right",
        va="top",
        transform=ax.transAxes,
    )
    t.set_bbox(dict(facecolor="white", alpha=0.5, edgecolor="black"))

    cb = ax.get_figure().colorbar(im, cax=cax, orientation="vertical")

    if show_err:
        cb.ax.fill_between(
            cb.ax.get_xlim(),
            cb.ax.get_ylim()[0],
            np.amin(DU),
            hatch="xxx",
            ec="w",
            fc="none",
        )
        cb.ax.fill_between(
            cb.ax.get_xlim(),
            np.amax(DU),
            cb.ax.get_ylim()[1],
            hatch="xxx",
            ec="w",
            fc="none",
        )
# plot the Laplacian DU for a 2D field my_U def plot_DU( compute_DU, my_U, cr, ax, title, DU_eb_abs, transform_symbol=None, my_DU=None, corr=None, my_U_it=None, cr_it=None, include_boundary=False, inset=True, inset_offset=(0.05, 0.05), ): show_err = my_DU is None if my_DU is None: my_DU = compute_DU(my_U) DU = compute_DU(U) vmin = np.nanmin(DU) vmax = np.nanmax(DU) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) ax.set_title(title) if show_err: err_v = np.mean(~(np.abs(my_DU - DU) <= DU_eb_abs)) err_v = ( 0 if err_v == 0 else np.format_float_positional(100 * err_v, precision=1, min_digits=1) + "%" ) if err_v == "0.0%": err_v = "<0.05%" t = ax.text( 0.95, 0.05, f"V={err_v}", ha="right", va="bottom", transform=ax.transAxes, ) t.set_bbox(dict(facecolor="white", alpha=0.5, edgecolor="black")) # create a colourmap that includes the entire finite range of my_DU but # assigns colours based on the range of DU to ensure consistent colours cx = np.linspace( ( np.minimum(np.amin(np.nan_to_num(my_DU, nan=0, posinf=0, neginf=0)), vmin) - vmin ) / (vmax - vmin), ( np.maximum(vmax, np.amax(np.nan_to_num(my_DU, nan=0, posinf=0, neginf=0))) - vmin ) / (vmax - vmin), 256, ) cmap = LinearSegmentedColormap.from_list("RdBu_r_ext", plt.get_cmap("RdBu_r")(cx)) ax.fill_between( [0, 1], [1, 1], hatch="XX", edgecolor="magenta", facecolor="lavenderblush", transform=ax.transAxes, zorder=-13, ) im = ax.imshow(my_DU, cmap=cmap, origin="lower", extent=(-1, 1, -1, 1), zorder=-12) ax.contour( X if include_boundary else X[1:-1, 1:-1], Y if include_boundary else Y[1:-1, 1:-1], my_DU, levels=10, colors="lightgrey", vmin=vmin, vmax=vmax, alpha=0.25, zorder=-11, ) ax.set_rasterization_zorder(-10) ax.set_aspect("equal") if show_err: if corr is not None: da_hatch = my_U == corr if my_U_it is None: da_corr = da_hatch.astype(float) else: da_hatch_it = my_U_it == corr da_corr = (~da_hatch).astype(float) + (~da_hatch_it).astype(float) axin = ax.inset_axes( [*inset_offset, 1 / 3, 1 / 3], xticks=[], yticks=[], ) axin.imshow( da_corr, cmap=mpl.colors.ListedColormap(["white", "green", "lawngreen"]), vmin=0, vmax=2, origin="lower", extent=(-1, 1, -1, 1), zorder=-10, ) axin.set_title( "Corrections", path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")], ) elif inset: da_err = ~(np.abs(my_DU - DU) <= DU_eb_abs) axin = ax.inset_axes( [*inset_offset, 1 / 3, 1 / 3], xticks=[], yticks=[], ) axin.imshow( da_err, cmap=mpl.colors.ListedColormap(["white", "red"]), vmin=0, vmax=1, origin="lower", extent=(-1, 1, -1, 1), zorder=-10, ) axin.set_title( "Violations", path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")], ) t = ax.text( 0.95, 0.95, ( rf"$\times$ {np.round(cr, 2)}" + ("" if cr_it is None else rf" ($\times$ {np.round(cr_it, 2)})") ) if show_err else humanize.naturalsize(U.nbytes, binary=True), ha="right", va="top", transform=ax.transAxes, ) t.set_bbox(dict(facecolor="white", alpha=0.5, edgecolor="black")) cb = ax.get_figure().colorbar(im, cax=cax, orientation="vertical") if show_err: cb.ax.fill_between( cb.ax.get_xlim(), cb.ax.get_ylim()[0], np.amin(DU), hatch="xxx", ec="w", fc="none", ) cb.ax.fill_between( cb.ax.get_xlim(), np.amax(DU), cb.ax.get_ylim()[1], hatch="xxx", ec="w", fc="none", )
Copied!
def table_DU(
    compute_DU,
    my_U,
    cr,
    title,
    DU_eb_abs,
    corr,
) -> pd.DataFrame:
    DU = compute_DU(U)
    my_DU = compute_DU(my_U)

    err_U_inf = np.amax(np.abs(my_U - U))
    err_DU_inf = np.amax(np.abs(my_DU - DU))
    err_DU_inf_fin = np.nanmax(
        np.nan_to_num(
            np.abs(my_DU - DU),
            nan=np.nan,
            posinf=np.nan,
            neginf=np.nan,
        )
    )
    err_DU_2 = np.sqrt(np.mean(np.square(my_DU - DU)))
    err_DU_2_fin = np.sqrt(
        np.nanmean(
            np.nan_to_num(
                np.square(my_DU - DU),
                nan=np.nan,
                posinf=np.nan,
                neginf=np.nan,
            )
        )
    )

    err_v = np.mean(~(np.abs(my_DU - DU) <= DU_eb_abs))
    err_v = (
        0
        if err_v == 0
        else np.format_float_positional(100 * err_v, precision=1, min_digits=1) + "%"
    )
    if err_v == "0.0%":
        err_v = "<0.05%"

    corr = None if corr is None else compute_corrections_percentage(my_U, corr)
    corr = (
        ""
        if corr is None
        else (
            0
            if corr == 0
            else np.format_float_positional(100 * corr, precision=1, min_digits=1) + "%"
        )
    )
    if corr == "0.0%":
        corr = "<0.05%"

    return pd.DataFrame(
        {
            "Compressor": [title[0]],
            r"$\epsilon_{abs}$": [title[1]],
            "Safeguarded": [title[2]],
            "Corrections": [title[3]],
            r"$L_{\infty}(\hat{u})$": [f"{err_U_inf:.02}"],
            r"$L_{\infty}(\Delta \hat{u})$": [
                f"{err_DU_inf:.02}".replace("nan", "NaN")
                + ("" if np.isfinite(err_DU_inf) else f" ({err_DU_inf_fin:.02})"),
            ],
            r"$L_{2}(\Delta \hat{u})$": [
                f"{err_DU_2:.02}".replace("nan", "NaN")
                + ("" if np.isfinite(err_DU_2) else f" ({err_DU_2_fin:.02})"),
            ],
            "V": [err_v],
            "C": [corr],
            "CR": [rf"$\times$ {np.round(cr, 2)}"],
        }
    )
def table_DU( compute_DU, my_U, cr, title, DU_eb_abs, corr, ) -> pd.DataFrame: DU = compute_DU(U) my_DU = compute_DU(my_U) err_U_inf = np.amax(np.abs(my_U - U)) err_DU_inf = np.amax(np.abs(my_DU - DU)) err_DU_inf_fin = np.nanmax( np.nan_to_num( np.abs(my_DU - DU), nan=np.nan, posinf=np.nan, neginf=np.nan, ) ) err_DU_2 = np.sqrt(np.mean(np.square(my_DU - DU))) err_DU_2_fin = np.sqrt( np.nanmean( np.nan_to_num( np.square(my_DU - DU), nan=np.nan, posinf=np.nan, neginf=np.nan, ) ) ) err_v = np.mean(~(np.abs(my_DU - DU) <= DU_eb_abs)) err_v = ( 0 if err_v == 0 else np.format_float_positional(100 * err_v, precision=1, min_digits=1) + "%" ) if err_v == "0.0%": err_v = "<0.05%" corr = None if corr is None else compute_corrections_percentage(my_U, corr) corr = ( "" if corr is None else ( 0 if corr == 0 else np.format_float_positional(100 * corr, precision=1, min_digits=1) + "%" ) ) if corr == "0.0%": corr = "<0.05%" return pd.DataFrame( { "Compressor": [title[0]], r"$\epsilon_{abs}$": [title[1]], "Safeguarded": [title[2]], "Corrections": [title[3]], r"$L_{\infty}(\hat{u})$": [f"{err_U_inf:.02}"], r"$L_{\infty}(\Delta \hat{u})$": [ f"{err_DU_inf:.02}".replace("nan", "NaN") + ("" if np.isfinite(err_DU_inf) else f" ({err_DU_inf_fin:.02})"), ], r"$L_{2}(\Delta \hat{u})$": [ f"{err_DU_2:.02}".replace("nan", "NaN") + ("" if np.isfinite(err_DU_2) else f" ({err_DU_2_fin:.02})"), ], "V": [err_v], "C": [corr], "CR": [rf"$\times$ {np.round(cr, 2)}"], } )

Example 1: $u(x, y) = {(x^2 + y^2)}^{3 \mathbin{/} 2} \mathbin{/} 9$¶

The Laplacian of $u$ is $\Delta u = \sqrt{x^2 + y^2}$.

We evaluate the Laplacian numerically on the original $u$ and the compressed $\hat{u}$ by using the second-order central difference approximation.

Copied!
U = np.power(X**2 + Y**2, 3 / 2) / 9
U = np.power(X**2 + Y**2, 3 / 2) / 9
Copied!
# analytical Laplacian on uncompressed
DU = np.sqrt(X**2 + Y**2)
# analytical Laplacian on uncompressed DU = np.sqrt(X**2 + Y**2)
Copied!
# absolute error bound on the Laplacian, around 1% of the range
DU_eb_abs = 0.01
# absolute error bound on the Laplacian, around 1% of the range DU_eb_abs = 0.01
Copied!
from compression_safeguards import SafeguardKind
from compression_safeguards.utils.bindings import Bindings

# we use a constant grid spacing and the valid boundary condition to preserve
#  an absolute error bound over the Laplacian, but not on the data boundaries
#  where data points do not have a left, right, upper, and lower neighbour
qoi_eb_stencil = SafeguardKind.qoi_eb_stencil.value(
    qoi="""
    (
        finite_difference(x, order=2, accuracy=2, type=0, axis=0, grid_spacing=c["dy"]) +
        finite_difference(x, order=2, accuracy=2, type=0, axis=1, grid_spacing=c["dx"])
    )
    """,
    neighbourhood=[
        dict(axis=0, before=1, after=1, boundary="valid"),
        dict(axis=1, before=1, after=1, boundary="valid"),
    ],
    type="abs",
    eb=DU_eb_abs,
)


# evaluate the Laplacian numerically by evaluating the quantity of interest
def compute_DU(U):
    return qoi_eb_stencil.evaluate_qoi(U, late_bound=Bindings(dx=dx, dy=dy))
from compression_safeguards import SafeguardKind from compression_safeguards.utils.bindings import Bindings # we use a constant grid spacing and the valid boundary condition to preserve # an absolute error bound over the Laplacian, but not on the data boundaries # where data points do not have a left, right, upper, and lower neighbour qoi_eb_stencil = SafeguardKind.qoi_eb_stencil.value( qoi=""" ( finite_difference(x, order=2, accuracy=2, type=0, axis=0, grid_spacing=c["dy"]) + finite_difference(x, order=2, accuracy=2, type=0, axis=1, grid_spacing=c["dx"]) ) """, neighbourhood=[ dict(axis=0, before=1, after=1, boundary="valid"), dict(axis=1, before=1, after=1, boundary="valid"), ], type="abs", eb=DU_eb_abs, ) # evaluate the Laplacian numerically by evaluating the quantity of interest def compute_DU(U): return qoi_eb_stencil.evaluate_qoi(U, late_bound=Bindings(dx=dx, dy=dy))
Copied!
import observe

observations = []
import observe observations = []

Lossless compression¶

We first compress the data losslessly with ZStandard at level 22, which gives maximum compression, to provide a baseline.

Copied!
# compressed with Zstdandard
from numcodecs_wasm_zstd import Zstd

zstd = Zstd(level=22)

with observe.observe(zstd, observations):
    U_zstd_enc = zstd.encode(U)
    U_zstd = zstd.decode(U_zstd_enc)
U_zstd_cr = U.nbytes / U_zstd_enc.nbytes
# compressed with Zstdandard from numcodecs_wasm_zstd import Zstd zstd = Zstd(level=22) with observe.observe(zstd, observations): U_zstd_enc = zstd.encode(U) U_zstd = zstd.decode(U_zstd_enc) U_zstd_cr = U.nbytes / U_zstd_enc.nbytes

Compressing u with lossy compressors¶

We configure each compressor with an absolute error bound of $1 \cdot 10^{-7}$ over the u array. For each compressor, we also test two more error bounds to investigate the impact of tuning: one that produces around 1% of violations for the absolute error bound over the Laplacian, and one that produces no violations.

Copied!
# absolute error bound for error-bounded lossy compression
eb_abs = 1e-7
# absolute error bound for error-bounded lossy compression eb_abs = 1e-7
Copied!
# we test several error bounds to showcase the impact of tuning
# - eb_abs: common error bound
# - tuned to get ~1% violations
# - tuned to get 0 violations
eb_abs_zfps = [eb_abs, 5e-8, 2e-8]
# we test several error bounds to showcase the impact of tuning # - eb_abs: common error bound # - tuned to get ~1% violations # - tuned to get 0 violations eb_abs_zfps = [eb_abs, 5e-8, 2e-8]
Copied!
# compressed with ZFP
from numcodecs_wasm_zfp import Zfp

zfp = dict()
U_zfp = dict()
U_zfp_cr = dict()

for eb_abs_zfp in eb_abs_zfps:
    zfp[eb_abs_zfp] = Zfp(mode="fixed-accuracy", tolerance=eb_abs_zfp)

    with observe.observe(zfp[eb_abs_zfp], observations):
        U_zfp_enc = zfp[eb_abs_zfp].encode(U)
        U_zfp[eb_abs_zfp] = zfp[eb_abs_zfp].decode(U_zfp_enc)
    U_zfp_cr[eb_abs_zfp] = U.nbytes / U_zfp_enc.nbytes
# compressed with ZFP from numcodecs_wasm_zfp import Zfp zfp = dict() U_zfp = dict() U_zfp_cr = dict() for eb_abs_zfp in eb_abs_zfps: zfp[eb_abs_zfp] = Zfp(mode="fixed-accuracy", tolerance=eb_abs_zfp) with observe.observe(zfp[eb_abs_zfp], observations): U_zfp_enc = zfp[eb_abs_zfp].encode(U) U_zfp[eb_abs_zfp] = zfp[eb_abs_zfp].decode(U_zfp_enc) U_zfp_cr[eb_abs_zfp] = U.nbytes / U_zfp_enc.nbytes
Copied!
eb_abs_sz3s = [eb_abs, 1.5e-7, 5e-9]
eb_abs_sz3s = [eb_abs, 1.5e-7, 5e-9]
Copied!
# compressed with SZ3
from numcodecs_wasm_sz3 import Sz3

sz3 = dict()
U_sz3 = dict()
U_sz3_cr = dict()

for eb_abs_sz3 in eb_abs_sz3s:
    sz3[eb_abs_sz3] = Sz3(eb_mode="abs", eb_abs=eb_abs_sz3)

    with observe.observe(sz3[eb_abs_sz3], observations):
        U_sz3_enc = sz3[eb_abs_sz3].encode(U)
        U_sz3[eb_abs_sz3] = sz3[eb_abs_sz3].decode(U_sz3_enc)
    U_sz3_cr[eb_abs_sz3] = U.nbytes / U_sz3_enc.nbytes
# compressed with SZ3 from numcodecs_wasm_sz3 import Sz3 sz3 = dict() U_sz3 = dict() U_sz3_cr = dict() for eb_abs_sz3 in eb_abs_sz3s: sz3[eb_abs_sz3] = Sz3(eb_mode="abs", eb_abs=eb_abs_sz3) with observe.observe(sz3[eb_abs_sz3], observations): U_sz3_enc = sz3[eb_abs_sz3].encode(U) U_sz3[eb_abs_sz3] = sz3[eb_abs_sz3].decode(U_sz3_enc) U_sz3_cr[eb_abs_sz3] = U.nbytes / U_sz3_enc.nbytes
Copied!
eb_abs_sperrs = [eb_abs, 3.5e-8, 8e-9]
eb_abs_sperrs = [eb_abs, 3.5e-8, 8e-9]
Copied!
# compressed with SPERR
from numcodecs_wasm_sperr import Sperr

sperr = dict()
U_sperr = dict()
U_sperr_cr = dict()

for eb_abs_sperr in eb_abs_sperrs:
    sperr[eb_abs_sperr] = Sperr(mode="pwe", pwe=eb_abs_sperr)

    with observe.observe(sperr[eb_abs_sperr], observations):
        U_sperr_enc = sperr[eb_abs_sperr].encode(U)
        U_sperr[eb_abs_sperr] = sperr[eb_abs_sperr].decode(U_sperr_enc)
    U_sperr_cr[eb_abs_sperr] = U.nbytes / U_sperr_enc.nbytes
# compressed with SPERR from numcodecs_wasm_sperr import Sperr sperr = dict() U_sperr = dict() U_sperr_cr = dict() for eb_abs_sperr in eb_abs_sperrs: sperr[eb_abs_sperr] = Sperr(mode="pwe", pwe=eb_abs_sperr) with observe.observe(sperr[eb_abs_sperr], observations): U_sperr_enc = sperr[eb_abs_sperr].encode(U) U_sperr[eb_abs_sperr] = sperr[eb_abs_sperr].decode(U_sperr_enc) U_sperr_cr[eb_abs_sperr] = U.nbytes / U_sperr_enc.nbytes
Copied!
# compressed to constant zero
from numcodecs_zero import ZeroCodec

zero = ZeroCodec()

with observe.observe(zero, observations):
    U_zero_enc = zero.encode(U)
    U_zero = zero.decode(U_zero_enc)
# compressed to constant zero from numcodecs_zero import ZeroCodec zero = ZeroCodec() with observe.observe(zero, observations): U_zero_enc = zero.encode(U) U_zero = zero.decode(U_zero_enc)

Compressing u using the safeguarded lossy compressors¶

We configure the safeguards to bound the pointwise absolute error on the derived Laplacian.

For this first example, we only evaluate the Laplacian numerically on non-boundary points, allowing us to only use second-order central finite differences.

Copied!
from numcodecs_safeguards import SafeguardedCodec

U_sg_qoi = dict()
U_sg_qoi_cr = dict()

# compressed with the safeguards with an absolute error bound over the Laplacian
for codecs in [zfp, sz3, sperr, {0: zero}]:
    U_sg_qoi_codec = dict()
    U_sg_qoi_codec_cr = dict()

    for eb_abs_codec, codec in codecs.items():
        codec_sg_qoi = SafeguardedCodec(
            codec=codec,
            safeguards=[qoi_eb_stencil],
            fixed_constants=dict(dx=dx, dy=dy),
        )

        with observe.observe(codec_sg_qoi, observations):
            U_sg_qoi_enc = codec_sg_qoi.encode(U)
            U_sg_qoi_codec[eb_abs_codec] = codec_sg_qoi.decode(U_sg_qoi_enc)
        U_sg_qoi_codec_cr[eb_abs_codec] = U.nbytes / np.asarray(U_sg_qoi_enc).nbytes

    U_sg_qoi[codec.codec_id] = U_sg_qoi_codec
    U_sg_qoi_cr[codec.codec_id] = U_sg_qoi_codec_cr
from numcodecs_safeguards import SafeguardedCodec U_sg_qoi = dict() U_sg_qoi_cr = dict() # compressed with the safeguards with an absolute error bound over the Laplacian for codecs in [zfp, sz3, sperr, {0: zero}]: U_sg_qoi_codec = dict() U_sg_qoi_codec_cr = dict() for eb_abs_codec, codec in codecs.items(): codec_sg_qoi = SafeguardedCodec( codec=codec, safeguards=[qoi_eb_stencil], fixed_constants=dict(dx=dx, dy=dy), ) with observe.observe(codec_sg_qoi, observations): U_sg_qoi_enc = codec_sg_qoi.encode(U) U_sg_qoi_codec[eb_abs_codec] = codec_sg_qoi.decode(U_sg_qoi_enc) U_sg_qoi_codec_cr[eb_abs_codec] = U.nbytes / np.asarray(U_sg_qoi_enc).nbytes U_sg_qoi[codec.codec_id] = U_sg_qoi_codec U_sg_qoi_cr[codec.codec_id] = U_sg_qoi_codec_cr
Copied!
U_sg_it_qoi = dict()
U_sg_it_qoi_cr = dict()

# compressed with the safeguards with an absolute error bound over the Laplacian
for codecs in [zfp, sz3, sperr, {0: zero}]:
    U_sg_it_qoi_codec = dict()
    U_sg_it_qoi_codec_cr = dict()

    for eb_abs_codec, codec in codecs.items():
        codec_sg_it_qoi = SafeguardedCodec(
            codec=codec,
            safeguards=[qoi_eb_stencil],
            fixed_constants=dict(dx=dx, dy=dy),
            # use iteration to refine the corrections
            compute=dict(unstable_iterative=True),
        )

        with observe.observe(codec_sg_it_qoi, observations):
            U_sg_it_qoi_enc = codec_sg_it_qoi.encode(U)
            U_sg_it_qoi_codec[eb_abs_codec] = codec_sg_it_qoi.decode(U_sg_it_qoi_enc)
        U_sg_it_qoi_codec_cr[eb_abs_codec] = (
            U.nbytes / np.asarray(U_sg_it_qoi_enc).nbytes
        )

    U_sg_it_qoi[codec.codec_id] = U_sg_it_qoi_codec
    U_sg_it_qoi_cr[codec.codec_id] = U_sg_it_qoi_codec_cr
U_sg_it_qoi = dict() U_sg_it_qoi_cr = dict() # compressed with the safeguards with an absolute error bound over the Laplacian for codecs in [zfp, sz3, sperr, {0: zero}]: U_sg_it_qoi_codec = dict() U_sg_it_qoi_codec_cr = dict() for eb_abs_codec, codec in codecs.items(): codec_sg_it_qoi = SafeguardedCodec( codec=codec, safeguards=[qoi_eb_stencil], fixed_constants=dict(dx=dx, dy=dy), # use iteration to refine the corrections compute=dict(unstable_iterative=True), ) with observe.observe(codec_sg_it_qoi, observations): U_sg_it_qoi_enc = codec_sg_it_qoi.encode(U) U_sg_it_qoi_codec[eb_abs_codec] = codec_sg_it_qoi.decode(U_sg_it_qoi_enc) U_sg_it_qoi_codec_cr[eb_abs_codec] = ( U.nbytes / np.asarray(U_sg_it_qoi_enc).nbytes ) U_sg_it_qoi[codec.codec_id] = U_sg_it_qoi_codec U_sg_it_qoi_cr[codec.codec_id] = U_sg_it_qoi_codec_cr
Copied!
U_sg_lossless_qoi = dict()
U_sg_lossless_qoi_cr = dict()

# compressed with the safeguards with an absolute error bound over the Laplacian
for codecs in [zfp, sz3, sperr, {0: zero}]:
    U_sg_lossless_qoi_codec = dict()
    U_sg_lossless_qoi_codec_cr = dict()

    for eb_abs_codec, codec in codecs.items():
        codec_sg_lossless_qoi = SafeguardedCodec(
            codec=codec,
            safeguards=[qoi_eb_stencil],
            fixed_constants=dict(dx=dx, dy=dy),
            # produce lossless corrections and refine them with iteration
            compute=dict(unstable_iterative=True, unstable_lossless_corrections=True),
        )

        with observe.observe(codec_sg_lossless_qoi, observations):
            U_sg_lossless_qoi_enc = codec_sg_lossless_qoi.encode(U)
            U_sg_lossless_qoi_codec[eb_abs_codec] = codec_sg_lossless_qoi.decode(
                U_sg_lossless_qoi_enc
            )
        U_sg_lossless_qoi_codec_cr[eb_abs_codec] = (
            U.nbytes / np.asarray(U_sg_lossless_qoi_enc).nbytes
        )

    U_sg_lossless_qoi[codec.codec_id] = U_sg_lossless_qoi_codec
    U_sg_lossless_qoi_cr[codec.codec_id] = U_sg_lossless_qoi_codec_cr
U_sg_lossless_qoi = dict() U_sg_lossless_qoi_cr = dict() # compressed with the safeguards with an absolute error bound over the Laplacian for codecs in [zfp, sz3, sperr, {0: zero}]: U_sg_lossless_qoi_codec = dict() U_sg_lossless_qoi_codec_cr = dict() for eb_abs_codec, codec in codecs.items(): codec_sg_lossless_qoi = SafeguardedCodec( codec=codec, safeguards=[qoi_eb_stencil], fixed_constants=dict(dx=dx, dy=dy), # produce lossless corrections and refine them with iteration compute=dict(unstable_iterative=True, unstable_lossless_corrections=True), ) with observe.observe(codec_sg_lossless_qoi, observations): U_sg_lossless_qoi_enc = codec_sg_lossless_qoi.encode(U) U_sg_lossless_qoi_codec[eb_abs_codec] = codec_sg_lossless_qoi.decode( U_sg_lossless_qoi_enc ) U_sg_lossless_qoi_codec_cr[eb_abs_codec] = ( U.nbytes / np.asarray(U_sg_lossless_qoi_enc).nbytes ) U_sg_lossless_qoi[codec.codec_id] = U_sg_lossless_qoi_codec U_sg_lossless_qoi_cr[codec.codec_id] = U_sg_lossless_qoi_codec_cr

Compressing u with OptZConfig¶

We configure OptZConfig with a custom safety violations metric, implemented in Python, that computes the percentage of violations $V$. We then maximise the score

$$ \textrm{score} = \begin{cases} -\textrm{V} \quad &\text{if } \textrm{V} > 0 \\ \textrm{CR} \quad &\text{otherwise} \end{cases} $$

using the FRAZ search algorithm with 25 iterations, where CR is the achieved compression ratio. Since FRAZ seems to struggle with finding sufficient absolute error bounds spread across several orders of magnitude, we search for bounds in logarithmic space by wrapping each codec in an Exponential<CODEC> meta-codec.

Copied!
import numcodecs


class SafetyViolationsMetric(numcodecs.abc.Codec):
    codec_id = "safety-violations-metric"

    def __init__(self):
        self._data = None

    def encode(self, buf):
        # store the original data for later
        self._data = np.array(buf, copy=True)
        # return no metric
        return np.empty(0, dtype=np.float64)

    def decode(self, buf, out=None):
        # compute the violations
        data_DU = compute_DU(self._data)
        buf_DU = compute_DU(buf)
        violations = np.mean(~(np.abs(buf_DU - data_DU) <= DU_eb_abs))
        self._data = None
        # return the violations score metric
        return numcodecs.compat.ndarray_copy(np.float64(violations), out)


numcodecs.registry.register_codec(SafetyViolationsMetric)
import numcodecs class SafetyViolationsMetric(numcodecs.abc.Codec): codec_id = "safety-violations-metric" def __init__(self): self._data = None def encode(self, buf): # store the original data for later self._data = np.array(buf, copy=True) # return no metric return np.empty(0, dtype=np.float64) def decode(self, buf, out=None): # compute the violations data_DU = compute_DU(self._data) buf_DU = compute_DU(buf) violations = np.mean(~(np.abs(buf_DU - data_DU) <= DU_eb_abs)) self._data = None # return the violations score metric return numcodecs.compat.ndarray_copy(np.float64(violations), out) numcodecs.registry.register_codec(SafetyViolationsMetric)
Copied!
class ExponentialZfp(Zfp):
    codec_id = "e-zfp.rs"

    def __new__(cls, tolerance: float, **kwargs):
        codec = super().__new__(cls, tolerance=np.exp(tolerance), **kwargs)
        codec._tolerance = tolerance
        return codec

    def get_config(self):
        return {
            **super().get_config(),
            "id": type(self).codec_id,
            "tolerance": self._tolerance,
        }


class ExponentialSz3(Sz3):
    codec_id = "e-sz3.rs"

    def __new__(cls, eb_abs: float, **kwargs):
        codec = super().__new__(cls, eb_abs=np.exp(eb_abs), **kwargs)
        codec._eb_abs = eb_abs
        return codec

    def get_config(self):
        return {
            **super().get_config(),
            "id": type(self).codec_id,
            "eb_abs": self._eb_abs,
        }


class ExponentialSperr(Sperr):
    codec_id = "e-sperr.rs"

    def __new__(cls, pwe: float, **kwargs):
        codec = super().__new__(cls, pwe=np.exp(pwe), **kwargs)
        codec._pwe = pwe
        return codec

    def get_config(self):
        return {**super().get_config(), "id": type(self).codec_id, "pwe": self._pwe}


numcodecs.registry.register_codec(ExponentialZfp)
numcodecs.registry.register_codec(ExponentialSz3)
numcodecs.registry.register_codec(ExponentialSperr)
class ExponentialZfp(Zfp): codec_id = "e-zfp.rs" def __new__(cls, tolerance: float, **kwargs): codec = super().__new__(cls, tolerance=np.exp(tolerance), **kwargs) codec._tolerance = tolerance return codec def get_config(self): return { **super().get_config(), "id": type(self).codec_id, "tolerance": self._tolerance, } class ExponentialSz3(Sz3): codec_id = "e-sz3.rs" def __new__(cls, eb_abs: float, **kwargs): codec = super().__new__(cls, eb_abs=np.exp(eb_abs), **kwargs) codec._eb_abs = eb_abs return codec def get_config(self): return { **super().get_config(), "id": type(self).codec_id, "eb_abs": self._eb_abs, } class ExponentialSperr(Sperr): codec_id = "e-sperr.rs" def __new__(cls, pwe: float, **kwargs): codec = super().__new__(cls, pwe=np.exp(pwe), **kwargs) codec._pwe = pwe return codec def get_config(self): return {**super().get_config(), "id": type(self).codec_id, "pwe": self._pwe} numcodecs.registry.register_codec(ExponentialZfp) numcodecs.registry.register_codec(ExponentialSz3) numcodecs.registry.register_codec(ExponentialSperr)
Copied!
from numcodecs_wasm_pressio import Pressio

U_optzconfig = dict()
U_optzconfig_cr = dict()

for codec, parameter, lower_bound in [
    (zfp[eb_abs], "tolerance", 1e-9),  # decent guess
    (sz3[eb_abs], "eb_abs", 1e-9),  # decent guess
    (sperr[eb_abs], "pwe", 1e-9),  # decent guess
]:
    optzconfig = Pressio(
        compressor_id="opt",
        compressor_config={
            "opt:output": ["composite:score"],
            "opt:inputs": [f"numcodecs.rs:{parameter}"],
            "opt:lower_bound": np.log(lower_bound),
            "opt:upper_bound": np.log(eb_abs),
            "opt:max_iterations": 25,
            "opt:objective_mode_name": "max",
        },
        early_config={
            "opt:compressor": "pressio",
            "pressio:compressor": "numcodecs.rs",
            **{
                f"numcodecs.rs:{k}": f"e-{v}" if k == "id" else v
                for k, v in codec.get_config().items()
            },
            "opt:search": "fraz",
            "pressio:metric": "composite",
            "composite:plugins": ["size", "numcodecs.rs-metric"],
            "composite:scripts": [
                """
                violations = metrics["numcodecs.rs-metric:decompression"]
                if violations > 0 then
                    return "score", -violations
                else
                    return "score", metrics["size:compression_ratio"]
                end
                """
            ],
            "numcodecs.rs-metric:id": "safety-violations-metric",
        },
    )

    with observe.observe(optzconfig, observations):
        U_optzconfig_enc = optzconfig.encode(U)
        U_optzconfig[codec.codec_id] = optzconfig.decode(U_optzconfig_enc)
    U_optzconfig_cr[codec.codec_id] = U.nbytes / np.asarray(U_optzconfig_enc).nbytes
from numcodecs_wasm_pressio import Pressio U_optzconfig = dict() U_optzconfig_cr = dict() for codec, parameter, lower_bound in [ (zfp[eb_abs], "tolerance", 1e-9), # decent guess (sz3[eb_abs], "eb_abs", 1e-9), # decent guess (sperr[eb_abs], "pwe", 1e-9), # decent guess ]: optzconfig = Pressio( compressor_id="opt", compressor_config={ "opt:output": ["composite:score"], "opt:inputs": [f"numcodecs.rs:{parameter}"], "opt:lower_bound": np.log(lower_bound), "opt:upper_bound": np.log(eb_abs), "opt:max_iterations": 25, "opt:objective_mode_name": "max", }, early_config={ "opt:compressor": "pressio", "pressio:compressor": "numcodecs.rs", **{ f"numcodecs.rs:{k}": f"e-{v}" if k == "id" else v for k, v in codec.get_config().items() }, "opt:search": "fraz", "pressio:metric": "composite", "composite:plugins": ["size", "numcodecs.rs-metric"], "composite:scripts": [ """ violations = metrics["numcodecs.rs-metric:decompression"] if violations > 0 then return "score", -violations else return "score", metrics["size:compression_ratio"] end """ ], "numcodecs.rs-metric:id": "safety-violations-metric", }, ) with observe.observe(optzconfig, observations): U_optzconfig_enc = optzconfig.encode(U) U_optzconfig[codec.codec_id] = optzconfig.decode(U_optzconfig_enc) U_optzconfig_cr[codec.codec_id] = U.nbytes / np.asarray(U_optzconfig_enc).nbytes
rank={0,1,} iter={0} input={-18.4207,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={1} input={-19.649,} output={5.93138,} objective={5.93138}
rank={0,1,} iter={2} input={-17.2111,} output={-0.0023514,} objective={-0.0023514}
rank={0,1,} iter={3} input={-18.9025,} output={6.3745,} objective={6.3745}
rank={0,1,} iter={4} input={-20.7219,} output={5.61127,} objective={5.61127}
rank={0,1,} iter={5} input={-18.5536,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={6} input={-20.1564,} output={5.61127,} objective={5.61127}
rank={0,1,} iter={7} input={-18.4872,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={8} input={-19.2369,} output={6.3745,} objective={6.3745}
rank={0,1,} iter={9} input={-18.6931,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={10} input={-19.0697,} output={6.3745,} objective={6.3745}
rank={0,1,} iter={11} input={-19.4029,} output={6.3745,} objective={6.3745}
rank={0,1,} iter={12} input={-20.439,} output={5.61127,} objective={5.61127}
rank={0,1,} iter={13} input={-19.8743,} output={5.93138,} objective={5.93138}
rank={0,1,} iter={14} input={-18.7626,} output={6.3745,} objective={6.3745}
rank={0,1,} iter={15} input={-18.6229,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={16} input={-18.6582,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={17} input={-18.5889,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={18} input={-18.5204,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={19} input={-18.4531,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={20} input={-18.6408,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={21} input={-18.5708,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={22} input={-18.6757,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={23} input={-18.6056,} output={6.76896,} objective={6.76896}
rank={0,1,} iter={24} input={-18.4699,} output={6.76896,} objective={6.76896}
final_iter={25} inputs={-18.4207,} output={6.76896,}
rank={0,1,} iter={0} input={-18.4207,} output={-0.00486843,} objective={-0.00486843}
rank={0,1,} iter={1} input={-19.649,} output={118.396,} objective={118.396}
rank={0,1,} iter={2} input={-17.2111,} output={-0.0305634,} objective={-0.0305634}
rank={0,1,} iter={3} input={-20.7233,} output={96.9523,} objective={96.9523}
rank={0,1,} iter={4} input={-20.0749,} output={113.257,} objective={113.257}
rank={0,1,} iter={5} input={-19.3665,} output={157.208,} objective={157.208}
rank={0,1,} iter={6} input={-16.1189,} output={-0.00436483,} objective={-0.00436483}
rank={0,1,} iter={7} input={-17.0505,} output={-0.00902647,} objective={-0.00902647}
rank={0,1,} iter={8} input={-19.3903,} output={152.492,} objective={152.492}
rank={0,1,} iter={9} input={-18.2085,} output={-2.29779e-05,} objective={-2.29779e-05}
rank={0,1,} iter={10} input={-20.349,} output={102.448,} objective={102.448}
rank={0,1,} iter={11} input={-18.7875,} output={-0.000189567,} objective={-0.000189567}
rank={0,1,} iter={12} input={-19.8528,} output={115.113,} objective={115.113}
rank={0,1,} iter={13} input={-19.077,} output={187.589,} objective={187.589}
rank={0,1,} iter={14} input={-17.7089,} output={-0.000787949,} objective={-0.000787949}
rank={0,1,} iter={15} input={-19.1814,} output={154.29,} objective={154.29}
rank={0,1,} iter={16} input={-16.5854,} output={-0.00369273,} objective={-0.00369273}
rank={0,1,} iter={17} input={-18.9322,} output={-0.000220204,} objective={-0.000220204}
rank={0,1,} iter={18} input={-20.535,} output={121.474,} objective={121.474}
rank={0,1,} iter={19} input={-19.1045,} output={177.54,} objective={177.54}
rank={0,1,} iter={20} input={-17.9583,} output={-0.000146484,} objective={-0.000146484}
rank={0,1,} iter={21} input={-19.0408,} output={-1.91482e-06,} objective={-1.91482e-06}
rank={0,1,} iter={22} input={-17.46,} output={-0.0263633,} objective={-0.0263633}
rank={0,1,} iter={23} input={-19.0887,} output={183.723,} objective={183.723}
rank={0,1,} iter={24} input={-16.3531,} output={-0.00672677,} objective={-0.00672677}
final_iter={25} inputs={-19.077,} output={187.589,}
rank={0,1,} iter={0} input={-18.4207,} output={-3.82964e-06,} objective={-3.82964e-06}
rank={0,1,} iter={1} input={-19.649,} output={71.0574,} objective={71.0574}
rank={0,1,} iter={2} input={-17.2111,} output={-0.00825001,} objective={-0.00825001}
rank={0,1,} iter={3} input={-20.7233,} output={62.4901,} objective={62.4901}
rank={0,1,} iter={4} input={-20.1121,} output={67.3265,} objective={67.3265}
rank={0,1,} iter={5} input={-18.491,} output={-2.87223e-06,} objective={-2.87223e-06}
rank={0,1,} iter={6} input={-20.3787,} output={65.0592,} objective={65.0592}
rank={0,1,} iter={7} input={-19.07,} output={76.2878,} objective={76.2878}
rank={0,1,} iter={8} input={-16.1182,} output={-0.0347866,} objective={-0.0347866}
rank={0,1,} iter={9} input={-19.3224,} output={74.183,} objective={74.183}
rank={0,1,} iter={10} input={-19.8669,} output={69.2541,} objective={69.2541}
rank={0,1,} iter={11} input={-18.491,} output={-2.87223e-06,} objective={-2.87223e-06}
rank={0,1,} iter={12} input={-19.4728,} output={72.8241,} objective={72.8241}
rank={0,1,} iter={13} input={-18.7805,} output={79.2125,} objective={79.2125}
rank={0,1,} iter={14} input={-17.8163,} output={-0.000410729,} objective={-0.000410729}
rank={0,1,} iter={15} input={-18.915,} output={77.6241,} objective={77.6241}
rank={0,1,} iter={16} input={-16.6639,} output={-0.0199668,} objective={-0.0199668}
rank={0,1,} iter={17} input={-18.839,} output={78.4327,} objective={78.4327}
rank={0,1,} iter={18} input={-20.5472,} output={63.8359,} objective={63.8359}
rank={0,1,} iter={19} input={-18.6358,} output={80.7404,} objective={80.7404}
rank={0,1,} iter={20} input={-18.1186,} output={-5.93595e-05,} objective={-5.93595e-05}
rank={0,1,} iter={21} input={-18.7805,} output={79.2125,} objective={79.2125}
rank={0,1,} iter={22} input={-17.5143,} output={-0.00333849,} objective={-0.00333849}
rank={0,1,} iter={23} input={-18.7081,} output={80.0096,} objective={80.0096}
rank={0,1,} iter={24} input={-16.938,} output={-0.0139179,} objective={-0.0139179}
final_iter={25} inputs={-18.6358,} output={80.7404,}

Visual comparison of the compressed Laplacians¶

Copied!
fig, axs = plt.subplots(nrows=3, ncols=4, figsize=(16, 12))

plot_DU(
    compute_DU,
    U,
    1.0,
    axs[0, 0],
    "Analytical",
    DU_eb_abs=DU_eb_abs,
    my_DU=DU[1:-1, 1:-1],
)
plot_DU(
    compute_DU,
    U_zfp[eb_abs],
    U_zfp_cr[eb_abs],
    axs[0, 1],
    r"ZFP($\epsilon_{abs}$)",
    DU_eb_abs=DU_eb_abs,
)
plot_DU(
    compute_DU,
    U_sz3[eb_abs],
    U_sz3_cr[eb_abs],
    axs[0, 2],
    r"SZ3($\epsilon_{abs}$)",
    DU_eb_abs=DU_eb_abs,
)
plot_DU(
    compute_DU,
    U_sperr[eb_abs],
    U_sperr_cr[eb_abs],
    axs[0, 3],
    r"SPERR($\epsilon_{abs}$)",
    DU_eb_abs=DU_eb_abs,
)

plot_DU(
    compute_DU,
    U_sg_qoi["zero"][0],
    U_sg_qoi_cr["zero"][0],
    axs[1, 0],
    r"Safeguarded(0, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=DU_eb_abs,
    corr=U_zero,
    my_U_it=U_sg_it_qoi["zero"][0],
    cr_it=U_sg_it_qoi_cr["zero"][0],
)
plot_DU(
    compute_DU,
    U_sg_qoi["zfp.rs"][eb_abs],
    U_sg_qoi_cr["zfp.rs"][eb_abs],
    axs[1, 1],
    r"Safeguarded(ZFP, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=DU_eb_abs,
    corr=U_zfp[eb_abs],
    my_U_it=U_sg_it_qoi["zfp.rs"][eb_abs],
    cr_it=U_sg_it_qoi_cr["zfp.rs"][eb_abs],
)
plot_DU(
    compute_DU,
    U_sg_qoi["sz3.rs"][eb_abs],
    U_sg_qoi_cr["sz3.rs"][eb_abs],
    axs[1, 2],
    r"Safeguarded(SZ3, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=DU_eb_abs,
    corr=U_sz3[eb_abs],
    my_U_it=U_sg_it_qoi["sz3.rs"][eb_abs],
    cr_it=U_sg_it_qoi_cr["sz3.rs"][eb_abs],
)
plot_DU(
    compute_DU,
    U_sg_qoi["sperr.rs"][eb_abs],
    U_sg_qoi_cr["sperr.rs"][eb_abs],
    axs[1, 3],
    r"Safeguarded(SPERR, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=DU_eb_abs,
    corr=U_sperr[eb_abs],
    my_U_it=U_sg_it_qoi["sperr.rs"][eb_abs],
    cr_it=U_sg_it_qoi_cr["sperr.rs"][eb_abs],
)

axs[2, 0].set_axis_off()

plot_DU(
    compute_DU,
    U_optzconfig["zfp.rs"],
    U_optzconfig_cr["zfp.rs"],
    axs[2, 1],
    r"OptZConfig(ZFP, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=DU_eb_abs,
    inset=False,
)
plot_DU(
    compute_DU,
    U_optzconfig["sz3.rs"],
    U_optzconfig_cr["sz3.rs"],
    axs[2, 2],
    r"OptZConfig(SZ3, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=DU_eb_abs,
    inset=False,
)
plot_DU(
    compute_DU,
    U_optzconfig["sperr.rs"],
    U_optzconfig_cr["sperr.rs"],
    axs[2, 3],
    r"OptZConfig(SPERR, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=DU_eb_abs,
    inset=False,
)

plt.tight_layout()

plt.savefig(Path("plots") / "derivative-radial.pdf", dpi=300)

plt.show()
fig, axs = plt.subplots(nrows=3, ncols=4, figsize=(16, 12)) plot_DU( compute_DU, U, 1.0, axs[0, 0], "Analytical", DU_eb_abs=DU_eb_abs, my_DU=DU[1:-1, 1:-1], ) plot_DU( compute_DU, U_zfp[eb_abs], U_zfp_cr[eb_abs], axs[0, 1], r"ZFP($\epsilon_{abs}$)", DU_eb_abs=DU_eb_abs, ) plot_DU( compute_DU, U_sz3[eb_abs], U_sz3_cr[eb_abs], axs[0, 2], r"SZ3($\epsilon_{abs}$)", DU_eb_abs=DU_eb_abs, ) plot_DU( compute_DU, U_sperr[eb_abs], U_sperr_cr[eb_abs], axs[0, 3], r"SPERR($\epsilon_{abs}$)", DU_eb_abs=DU_eb_abs, ) plot_DU( compute_DU, U_sg_qoi["zero"][0], U_sg_qoi_cr["zero"][0], axs[1, 0], r"Safeguarded(0, $\epsilon_{QoI,abs}$)", DU_eb_abs=DU_eb_abs, corr=U_zero, my_U_it=U_sg_it_qoi["zero"][0], cr_it=U_sg_it_qoi_cr["zero"][0], ) plot_DU( compute_DU, U_sg_qoi["zfp.rs"][eb_abs], U_sg_qoi_cr["zfp.rs"][eb_abs], axs[1, 1], r"Safeguarded(ZFP, $\epsilon_{QoI,abs}$)", DU_eb_abs=DU_eb_abs, corr=U_zfp[eb_abs], my_U_it=U_sg_it_qoi["zfp.rs"][eb_abs], cr_it=U_sg_it_qoi_cr["zfp.rs"][eb_abs], ) plot_DU( compute_DU, U_sg_qoi["sz3.rs"][eb_abs], U_sg_qoi_cr["sz3.rs"][eb_abs], axs[1, 2], r"Safeguarded(SZ3, $\epsilon_{QoI,abs}$)", DU_eb_abs=DU_eb_abs, corr=U_sz3[eb_abs], my_U_it=U_sg_it_qoi["sz3.rs"][eb_abs], cr_it=U_sg_it_qoi_cr["sz3.rs"][eb_abs], ) plot_DU( compute_DU, U_sg_qoi["sperr.rs"][eb_abs], U_sg_qoi_cr["sperr.rs"][eb_abs], axs[1, 3], r"Safeguarded(SPERR, $\epsilon_{QoI,abs}$)", DU_eb_abs=DU_eb_abs, corr=U_sperr[eb_abs], my_U_it=U_sg_it_qoi["sperr.rs"][eb_abs], cr_it=U_sg_it_qoi_cr["sperr.rs"][eb_abs], ) axs[2, 0].set_axis_off() plot_DU( compute_DU, U_optzconfig["zfp.rs"], U_optzconfig_cr["zfp.rs"], axs[2, 1], r"OptZConfig(ZFP, $\epsilon_{QoI,abs}$)", DU_eb_abs=DU_eb_abs, inset=False, ) plot_DU( compute_DU, U_optzconfig["sz3.rs"], U_optzconfig_cr["sz3.rs"], axs[2, 2], r"OptZConfig(SZ3, $\epsilon_{QoI,abs}$)", DU_eb_abs=DU_eb_abs, inset=False, ) plot_DU( compute_DU, U_optzconfig["sperr.rs"], U_optzconfig_cr["sperr.rs"], axs[2, 3], r"OptZConfig(SPERR, $\epsilon_{QoI,abs}$)", DU_eb_abs=DU_eb_abs, inset=False, ) plt.tight_layout() plt.savefig(Path("plots") / "derivative-radial.pdf", dpi=300) plt.show()
No description has been provided for this image
Copied!
u_radial_sg_table_a = pd.concat(
    [
        table_DU(
            compute_DU,
            U_sg_lossless_qoi["zero"][0],
            U_sg_lossless_qoi_cr["zero"][0],
            ["0", "", r"$\epsilon_{QoI,abs}$", "lossless"],
            DU_eb_abs,
            U_zero,
        ),
        table_DU(
            compute_DU,
            U_sg_qoi["zero"][0],
            U_sg_qoi_cr["zero"][0],
            ["0", "", r"$\epsilon_{QoI,abs}$", "one-shot"],
            DU_eb_abs,
            U_zero,
        ),
        table_DU(
            compute_DU,
            U_sg_it_qoi["zero"][0],
            U_sg_it_qoi_cr["zero"][0],
            ["0", "", r"$\epsilon_{QoI,abs}$", "iterative"],
            DU_eb_abs,
            U_zero,
        ),
    ]
    + [
        x
        for eb_abs_zfp in eb_abs_zfps
        for x in [
            table_DU(
                compute_DU,
                U_zfp[eb_abs_zfp],
                U_zfp_cr[eb_abs_zfp],
                [r"ZFP($\epsilon_{abs}$)", f"{eb_abs_zfp}", "-", ""],
                DU_eb_abs,
                None,
            ),
            table_DU(
                compute_DU,
                U_sg_lossless_qoi["zfp.rs"][eb_abs_zfp],
                U_sg_lossless_qoi_cr["zfp.rs"][eb_abs_zfp],
                [
                    r"ZFP($\epsilon_{abs}$)",
                    f"{eb_abs_zfp}",
                    r"$\epsilon_{QoI,abs}$",
                    "lossless",
                ],
                DU_eb_abs,
                U_zfp[eb_abs_zfp],
            ),
            table_DU(
                compute_DU,
                U_sg_qoi["zfp.rs"][eb_abs_zfp],
                U_sg_qoi_cr["zfp.rs"][eb_abs_zfp],
                [
                    r"ZFP($\epsilon_{abs}$)",
                    f"{eb_abs_zfp}",
                    r"$\epsilon_{QoI,abs}$",
                    "one-shot",
                ],
                DU_eb_abs,
                U_zfp[eb_abs_zfp],
            ),
            table_DU(
                compute_DU,
                U_sg_it_qoi["zfp.rs"][eb_abs_zfp],
                U_sg_it_qoi_cr["zfp.rs"][eb_abs_zfp],
                [
                    r"ZFP($\epsilon_{abs}$)",
                    f"{eb_abs_zfp}",
                    r"$\epsilon_{QoI,abs}$",
                    "iterative",
                ],
                DU_eb_abs,
                U_zfp[eb_abs_zfp],
            ),
        ]
    ]
    + [
        table_DU(
            compute_DU,
            U_optzconfig["zfp.rs"],
            U_optzconfig_cr["zfp.rs"],
            [
                "OptZConfig(ZFP)",
                "",
                r"$\epsilon_{QoI,abs}$",
                "",
            ],
            DU_eb_abs,
            None,
        ),
    ]
    + [
        x
        for eb_abs_sz3 in eb_abs_sz3s[:2]
        for x in [
            table_DU(
                compute_DU,
                U_sz3[eb_abs_sz3],
                U_sz3_cr[eb_abs_sz3],
                [r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", "-", ""],
                DU_eb_abs,
                None,
            ),
            table_DU(
                compute_DU,
                U_sg_lossless_qoi["sz3.rs"][eb_abs_sz3],
                U_sg_lossless_qoi_cr["sz3.rs"][eb_abs_sz3],
                [
                    r"SZ3($\epsilon_{abs}$)",
                    f"{eb_abs_sz3}",
                    r"$\epsilon_{QoI,abs}$",
                    "lossless",
                ],
                DU_eb_abs,
                U_sz3[eb_abs_sz3],
            ),
            table_DU(
                compute_DU,
                U_sg_qoi["sz3.rs"][eb_abs_sz3],
                U_sg_qoi_cr["sz3.rs"][eb_abs_sz3],
                [
                    r"SZ3($\epsilon_{abs}$)",
                    f"{eb_abs_sz3}",
                    r"$\epsilon_{QoI,abs}$",
                    "one-shot",
                ],
                DU_eb_abs,
                U_sz3[eb_abs_sz3],
            ),
            table_DU(
                compute_DU,
                U_sg_it_qoi["sz3.rs"][eb_abs_sz3],
                U_sg_it_qoi_cr["sz3.rs"][eb_abs_sz3],
                [
                    r"SZ3($\epsilon_{abs}$)",
                    f"{eb_abs_sz3}",
                    r"$\epsilon_{QoI,abs}$",
                    "iterative",
                ],
                DU_eb_abs,
                U_sz3[eb_abs_sz3],
            ),
        ]
    ]
)

u_radial_sg_table_b = pd.concat(
    [
        x
        for eb_abs_sz3 in eb_abs_sz3s[2:]
        for x in [
            table_DU(
                compute_DU,
                U_sz3[eb_abs_sz3],
                U_sz3_cr[eb_abs_sz3],
                [r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", "-", ""],
                DU_eb_abs,
                None,
            ),
            table_DU(
                compute_DU,
                U_sg_lossless_qoi["sz3.rs"][eb_abs_sz3],
                U_sg_lossless_qoi_cr["sz3.rs"][eb_abs_sz3],
                [
                    r"SZ3($\epsilon_{abs}$)",
                    f"{eb_abs_sz3}",
                    r"$\epsilon_{QoI,abs}$",
                    "lossless",
                ],
                DU_eb_abs,
                U_sz3[eb_abs_sz3],
            ),
            table_DU(
                compute_DU,
                U_sg_qoi["sz3.rs"][eb_abs_sz3],
                U_sg_qoi_cr["sz3.rs"][eb_abs_sz3],
                [
                    r"SZ3($\epsilon_{abs}$)",
                    f"{eb_abs_sz3}",
                    r"$\epsilon_{QoI,abs}$",
                    "one-shot",
                ],
                DU_eb_abs,
                U_sz3[eb_abs_sz3],
            ),
            table_DU(
                compute_DU,
                U_sg_it_qoi["sz3.rs"][eb_abs_sz3],
                U_sg_it_qoi_cr["sz3.rs"][eb_abs_sz3],
                [
                    r"SZ3($\epsilon_{abs}$)",
                    f"{eb_abs_sz3}",
                    r"$\epsilon_{QoI,abs}$",
                    "iterative",
                ],
                DU_eb_abs,
                U_sz3[eb_abs_sz3],
            ),
        ]
    ]
    + [
        table_DU(
            compute_DU,
            U_optzconfig["sz3.rs"],
            U_optzconfig_cr["sz3.rs"],
            [
                "OptZConfig(SZ3)",
                "",
                r"$\epsilon_{QoI,abs}$",
                "",
            ],
            DU_eb_abs,
            None,
        ),
    ]
    + [
        x
        for eb_abs_sperr in eb_abs_sperrs
        for x in [
            table_DU(
                compute_DU,
                U_sperr[eb_abs_sperr],
                U_sperr_cr[eb_abs_sperr],
                [r"SPERR($\epsilon_{abs}$)", f"{eb_abs_sperr}", "-", ""],
                DU_eb_abs,
                None,
            ),
            table_DU(
                compute_DU,
                U_sg_lossless_qoi["sperr.rs"][eb_abs_sperr],
                U_sg_lossless_qoi_cr["sperr.rs"][eb_abs_sperr],
                [
                    r"SPERR($\epsilon_{abs}$)",
                    f"{eb_abs_sperr}",
                    r"$\epsilon_{QoI,abs}$",
                    "lossless",
                ],
                DU_eb_abs,
                U_sperr[eb_abs_sperr],
            ),
            table_DU(
                compute_DU,
                U_sg_qoi["sperr.rs"][eb_abs_sperr],
                U_sg_qoi_cr["sperr.rs"][eb_abs_sperr],
                [
                    r"SPERR($\epsilon_{abs}$)",
                    f"{eb_abs_sperr}",
                    r"$\epsilon_{QoI,abs}$",
                    "one-shot",
                ],
                DU_eb_abs,
                U_sperr[eb_abs_sperr],
            ),
            table_DU(
                compute_DU,
                U_sg_it_qoi["sperr.rs"][eb_abs_sperr],
                U_sg_it_qoi_cr["sperr.rs"][eb_abs_sperr],
                [
                    r"SPERR($\epsilon_{abs}$)",
                    f"{eb_abs_sperr}",
                    r"$\epsilon_{QoI,abs}$",
                    "iterative",
                ],
                DU_eb_abs,
                U_sperr[eb_abs_sperr],
            ),
        ]
    ]
    + [
        table_DU(
            compute_DU,
            U_optzconfig["sperr.rs"],
            U_optzconfig_cr["sperr.rs"],
            [
                "OptZConfig(SPERR)",
                "",
                r"$\epsilon_{QoI,abs}$",
                "",
            ],
            DU_eb_abs,
            None,
        ),
    ]
    + [
        table_DU(
            compute_DU,
            U_zstd,
            U_zstd_cr,
            ["ZSTD(22)", "", "-", ""],
            DU_eb_abs,
            None,
        )
    ]
)

u_radial_sg_table_index = [
    "Compressor",
    r"$\epsilon_{abs}$",
    "Safeguarded",
    "Corrections",
]

u_radial_sg_table = pd.concat([u_radial_sg_table_a, u_radial_sg_table_b]).set_index(
    u_radial_sg_table_index
)
u_radial_sg_table_a = u_radial_sg_table_a.set_index(u_radial_sg_table_index)
u_radial_sg_table_b = u_radial_sg_table_b.set_index(u_radial_sg_table_index)

for name, table in {
    "derivative-radial-a.tex": u_radial_sg_table_a,
    "derivative-radial-b.tex": u_radial_sg_table_b,
    "derivative-radial.tex": u_radial_sg_table,
}.items():
    Path("tables").joinpath(name).write_text(
        table.to_latex(escape=False)
        .replace("%", r"\%")
        .replace(
            "\\cline{1-10} \\cline{2-10} \\cline{3-10}\n\\bottomrule", "\\bottomrule"
        )
    )

u_radial_sg_table
u_radial_sg_table_a = pd.concat( [ table_DU( compute_DU, U_sg_lossless_qoi["zero"][0], U_sg_lossless_qoi_cr["zero"][0], ["0", "", r"$\epsilon_{QoI,abs}$", "lossless"], DU_eb_abs, U_zero, ), table_DU( compute_DU, U_sg_qoi["zero"][0], U_sg_qoi_cr["zero"][0], ["0", "", r"$\epsilon_{QoI,abs}$", "one-shot"], DU_eb_abs, U_zero, ), table_DU( compute_DU, U_sg_it_qoi["zero"][0], U_sg_it_qoi_cr["zero"][0], ["0", "", r"$\epsilon_{QoI,abs}$", "iterative"], DU_eb_abs, U_zero, ), ] + [ x for eb_abs_zfp in eb_abs_zfps for x in [ table_DU( compute_DU, U_zfp[eb_abs_zfp], U_zfp_cr[eb_abs_zfp], [r"ZFP($\epsilon_{abs}$)", f"{eb_abs_zfp}", "-", ""], DU_eb_abs, None, ), table_DU( compute_DU, U_sg_lossless_qoi["zfp.rs"][eb_abs_zfp], U_sg_lossless_qoi_cr["zfp.rs"][eb_abs_zfp], [ r"ZFP($\epsilon_{abs}$)", f"{eb_abs_zfp}", r"$\epsilon_{QoI,abs}$", "lossless", ], DU_eb_abs, U_zfp[eb_abs_zfp], ), table_DU( compute_DU, U_sg_qoi["zfp.rs"][eb_abs_zfp], U_sg_qoi_cr["zfp.rs"][eb_abs_zfp], [ r"ZFP($\epsilon_{abs}$)", f"{eb_abs_zfp}", r"$\epsilon_{QoI,abs}$", "one-shot", ], DU_eb_abs, U_zfp[eb_abs_zfp], ), table_DU( compute_DU, U_sg_it_qoi["zfp.rs"][eb_abs_zfp], U_sg_it_qoi_cr["zfp.rs"][eb_abs_zfp], [ r"ZFP($\epsilon_{abs}$)", f"{eb_abs_zfp}", r"$\epsilon_{QoI,abs}$", "iterative", ], DU_eb_abs, U_zfp[eb_abs_zfp], ), ] ] + [ table_DU( compute_DU, U_optzconfig["zfp.rs"], U_optzconfig_cr["zfp.rs"], [ "OptZConfig(ZFP)", "", r"$\epsilon_{QoI,abs}$", "", ], DU_eb_abs, None, ), ] + [ x for eb_abs_sz3 in eb_abs_sz3s[:2] for x in [ table_DU( compute_DU, U_sz3[eb_abs_sz3], U_sz3_cr[eb_abs_sz3], [r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", "-", ""], DU_eb_abs, None, ), table_DU( compute_DU, U_sg_lossless_qoi["sz3.rs"][eb_abs_sz3], U_sg_lossless_qoi_cr["sz3.rs"][eb_abs_sz3], [ r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", r"$\epsilon_{QoI,abs}$", "lossless", ], DU_eb_abs, U_sz3[eb_abs_sz3], ), table_DU( compute_DU, U_sg_qoi["sz3.rs"][eb_abs_sz3], U_sg_qoi_cr["sz3.rs"][eb_abs_sz3], [ r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", r"$\epsilon_{QoI,abs}$", "one-shot", ], DU_eb_abs, U_sz3[eb_abs_sz3], ), table_DU( compute_DU, U_sg_it_qoi["sz3.rs"][eb_abs_sz3], U_sg_it_qoi_cr["sz3.rs"][eb_abs_sz3], [ r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", r"$\epsilon_{QoI,abs}$", "iterative", ], DU_eb_abs, U_sz3[eb_abs_sz3], ), ] ] ) u_radial_sg_table_b = pd.concat( [ x for eb_abs_sz3 in eb_abs_sz3s[2:] for x in [ table_DU( compute_DU, U_sz3[eb_abs_sz3], U_sz3_cr[eb_abs_sz3], [r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", "-", ""], DU_eb_abs, None, ), table_DU( compute_DU, U_sg_lossless_qoi["sz3.rs"][eb_abs_sz3], U_sg_lossless_qoi_cr["sz3.rs"][eb_abs_sz3], [ r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", r"$\epsilon_{QoI,abs}$", "lossless", ], DU_eb_abs, U_sz3[eb_abs_sz3], ), table_DU( compute_DU, U_sg_qoi["sz3.rs"][eb_abs_sz3], U_sg_qoi_cr["sz3.rs"][eb_abs_sz3], [ r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", r"$\epsilon_{QoI,abs}$", "one-shot", ], DU_eb_abs, U_sz3[eb_abs_sz3], ), table_DU( compute_DU, U_sg_it_qoi["sz3.rs"][eb_abs_sz3], U_sg_it_qoi_cr["sz3.rs"][eb_abs_sz3], [ r"SZ3($\epsilon_{abs}$)", f"{eb_abs_sz3}", r"$\epsilon_{QoI,abs}$", "iterative", ], DU_eb_abs, U_sz3[eb_abs_sz3], ), ] ] + [ table_DU( compute_DU, U_optzconfig["sz3.rs"], U_optzconfig_cr["sz3.rs"], [ "OptZConfig(SZ3)", "", r"$\epsilon_{QoI,abs}$", "", ], DU_eb_abs, None, ), ] + [ x for eb_abs_sperr in eb_abs_sperrs for x in [ table_DU( compute_DU, U_sperr[eb_abs_sperr], U_sperr_cr[eb_abs_sperr], [r"SPERR($\epsilon_{abs}$)", f"{eb_abs_sperr}", "-", ""], DU_eb_abs, None, ), table_DU( compute_DU, U_sg_lossless_qoi["sperr.rs"][eb_abs_sperr], U_sg_lossless_qoi_cr["sperr.rs"][eb_abs_sperr], [ r"SPERR($\epsilon_{abs}$)", f"{eb_abs_sperr}", r"$\epsilon_{QoI,abs}$", "lossless", ], DU_eb_abs, U_sperr[eb_abs_sperr], ), table_DU( compute_DU, U_sg_qoi["sperr.rs"][eb_abs_sperr], U_sg_qoi_cr["sperr.rs"][eb_abs_sperr], [ r"SPERR($\epsilon_{abs}$)", f"{eb_abs_sperr}", r"$\epsilon_{QoI,abs}$", "one-shot", ], DU_eb_abs, U_sperr[eb_abs_sperr], ), table_DU( compute_DU, U_sg_it_qoi["sperr.rs"][eb_abs_sperr], U_sg_it_qoi_cr["sperr.rs"][eb_abs_sperr], [ r"SPERR($\epsilon_{abs}$)", f"{eb_abs_sperr}", r"$\epsilon_{QoI,abs}$", "iterative", ], DU_eb_abs, U_sperr[eb_abs_sperr], ), ] ] + [ table_DU( compute_DU, U_optzconfig["sperr.rs"], U_optzconfig_cr["sperr.rs"], [ "OptZConfig(SPERR)", "", r"$\epsilon_{QoI,abs}$", "", ], DU_eb_abs, None, ), ] + [ table_DU( compute_DU, U_zstd, U_zstd_cr, ["ZSTD(22)", "", "-", ""], DU_eb_abs, None, ) ] ) u_radial_sg_table_index = [ "Compressor", r"$\epsilon_{abs}$", "Safeguarded", "Corrections", ] u_radial_sg_table = pd.concat([u_radial_sg_table_a, u_radial_sg_table_b]).set_index( u_radial_sg_table_index ) u_radial_sg_table_a = u_radial_sg_table_a.set_index(u_radial_sg_table_index) u_radial_sg_table_b = u_radial_sg_table_b.set_index(u_radial_sg_table_index) for name, table in { "derivative-radial-a.tex": u_radial_sg_table_a, "derivative-radial-b.tex": u_radial_sg_table_b, "derivative-radial.tex": u_radial_sg_table, }.items(): Path("tables").joinpath(name).write_text( table.to_latex(escape=False) .replace("%", r"\%") .replace( "\\cline{1-10} \\cline{2-10} \\cline{3-10}\n\\bottomrule", "\\bottomrule" ) ) u_radial_sg_table
$L_{\infty}(\hat{u})$ $L_{\infty}(\Delta \hat{u})$ $L_{2}(\Delta \hat{u})$ V C CR
Compressor $\epsilon_{abs}$ Safeguarded Corrections
0 $\epsilon_{QoI,abs}$ lossless 0.31 0.0099 3.7e-05 0 100.0% $\times$ 2.97
one-shot 0.31 0.0092 0.0028 0 100.0% $\times$ 6.9
iterative 0.31 0.0092 0.0028 0 100.0% $\times$ 6.75
ZFP($\epsilon_{abs}$) 1e-07 - 2.7e-08 0.028 0.0045 4.5% $\times$ 8.37
$\epsilon_{QoI,abs}$ lossless 2e-08 0.01 0.0036 0 5.5% $\times$ 7.18
one-shot 2e-08 0.0086 0.0024 0 40.0% $\times$ 7.1
iterative 2e-08 0.01 0.0036 0 5.4% $\times$ 8.03
5e-08 - 1.5e-08 0.015 0.0025 0.2% $\times$ 7.91
$\epsilon_{QoI,abs}$ lossless 1.3e-08 0.01 0.0025 0 0.2% $\times$ 7.83
one-shot 4.8e-09 0.0073 0.0019 0 12.1% $\times$ 7.45
iterative 1.3e-08 0.01 0.0025 0 0.2% $\times$ 7.88
2e-08 - 7.8e-09 0.0077 0.0015 0 $\times$ 7.43
$\epsilon_{QoI,abs}$ lossless 7.8e-09 0.0077 0.0015 0 0 $\times$ 7.43
one-shot 7.8e-09 0.0077 0.0015 0 0 $\times$ 7.43
iterative 7.8e-09 0.0077 0.0015 0 0 $\times$ 7.43
OptZConfig(ZFP) $\epsilon_{QoI,abs}$ 4.1e-09 0.0041 0.00079 0 $\times$ 6.77
SZ3($\epsilon_{abs}$) 1e-07 - 1e-07 0.086 0.0022 0.4% $\times$ 721.97
$\epsilon_{QoI,abs}$ lossless 9.4e-08 0.01 0.0017 0 25.1% $\times$ 5.64
one-shot 7.6e-08 0.0094 0.0024 0 86.8% $\times$ 24.69
iterative 9.4e-08 0.01 0.0021 0 25.0% $\times$ 57.36
1.5e-07 - 1.5e-07 0.13 0.0032 0.9% $\times$ 821.12
$\epsilon_{QoI,abs}$ lossless 1.2e-07 0.01 0.0018 0 49.9% $\times$ 3.0
one-shot 1.2e-07 0.0091 0.0026 0 91.0% $\times$ 22.22
iterative 1.2e-07 0.01 0.0026 0 51.8% $\times$ 32.51
5e-09 - 5e-09 0.0093 0.00076 0 $\times$ 176.04
$\epsilon_{QoI,abs}$ lossless 5e-09 0.0093 0.00076 0 0 $\times$ 176.02
one-shot 5e-09 0.0093 0.00076 0 0 $\times$ 176.02
iterative 5e-09 0.0093 0.00076 0 0 $\times$ 176.02
OptZConfig(SZ3) $\epsilon_{QoI,abs}$ 5.2e-09 0.0098 0.00075 0 $\times$ 187.59
SPERR($\epsilon_{abs}$) 1e-07 - 9.7e-08 0.12 0.0049 3.5% $\times$ 112.65
$\epsilon_{QoI,abs}$ lossless 8.7e-08 0.01 0.0013 0 6.7% $\times$ 17.35
one-shot 8.7e-08 0.0087 0.0014 0 41.2% $\times$ 29.35
iterative 8.7e-08 0.01 0.0014 0 6.5% $\times$ 61.85
3.5e-08 - 3.5e-08 0.041 0.0017 0.9% $\times$ 98.06
$\epsilon_{QoI,abs}$ lossless 3.5e-08 0.01 0.001 0 1.3% $\times$ 46.54
one-shot 1.1e-08 0.0088 0.00083 0 8.7% $\times$ 53.68
iterative 3.5e-08 0.01 0.0011 0 1.3% $\times$ 83.29
8e-09 - 8e-09 0.0083 0.00041 0 $\times$ 80.65
$\epsilon_{QoI,abs}$ lossless 8e-09 0.0083 0.00041 0 0 $\times$ 80.65
one-shot 8e-09 0.0083 0.00041 0 0 $\times$ 80.65
iterative 8e-09 0.0083 0.00041 0 0 $\times$ 80.65
OptZConfig(SPERR) $\epsilon_{QoI,abs}$ 8e-09 0.0085 0.00041 0 $\times$ 80.74
ZSTD(22) - 0.0 0.0 0.0 0 $\times$ 4.26
Copied!
import json

with Path("observations").joinpath("derivative-radial.json").open("w") as f:
    json.dump(observations, f)
import json with Path("observations").joinpath("derivative-radial.json").open("w") as f: json.dump(observations, f)

Example 2: $u(x, y) = e^{4 x + 3 y}$¶

The Laplacian of $u$ is $\Delta u = 25 u$.

We plot the natural logarithm of the Laplacian.

Copied!
U = np.exp(4 * X + 3 * Y)
U = np.exp(4 * X + 3 * Y)
Copied!
# analytical solution on uncompressed
DU = U * 25
# analytical solution on uncompressed DU = U * 25
Copied!
# absolute error bound on the natural logarithm of the Laplacian,
#  around 1% of the range
ln_DU_eb_abs = 0.1
# absolute error bound on the natural logarithm of the Laplacian, # around 1% of the range ln_DU_eb_abs = 0.1
Copied!
# we use the safeguard's support for arbitrary grid-based spacing and switch
#  from 2nd order central finite differences to 2nd order forward/backwards
#  finite differences at the data boundaries, where data points do not have a
#  left, right, upper, and lower neighbour
# this enables us to compute the Laplacian at all data points, including at
#  the boundaries
# we pad the data with NaNs to denote the missing values
qoi_eb_stencil = SafeguardKind.qoi_eb_stencil.value(
    qoi="""
    V["d2Udy2"] = where(
        c["Y"] > -1,
        where(
            c["Y"] < 1,
            # use 2nd order central finite difference where possible
            finite_difference(
                x, order=2, accuracy=2, type=0, axis=0, grid_centre=c["Y"]
            ),
            # use 2nd order backwards finite difference at the upper boundary
            finite_difference(
                x, order=2, accuracy=1, type=-1, axis=0, grid_centre=c["Y"]
            ),
        ),
        # use 2nd order forward finite difference at the lower boundary
        finite_difference(
            x, order=2, accuracy=1, type=1, axis=0, grid_centre=c["Y"]
        ),
    );

    V["d2Udx2"] = where(
        c["X"] > -1,
        where(
            c["X"] < 1,
            # use 2nd order central finite difference where possible
            finite_difference(
                x, order=2, accuracy=2, type=0, axis=1, grid_centre=c["X"]
            ),
            # use 2nd order backwards finite difference at the right boundary
            finite_difference(
                x, order=2, accuracy=1, type=-1, axis=1, grid_centre=c["X"]
            ),
        ),
        # use 2nd order forward finite difference at the left boundary
        finite_difference(
            x, order=2, accuracy=1, type=1, axis=1, grid_centre=c["X"]
        ),
    );

    # compute the natural logarithm of the Laplacian
    return ln(V["d2Udy2"] + V["d2Udx2"]);
    """,
    neighbourhood=[
        dict(axis=0, before=2, after=2, boundary="constant", constant_boundary=np.nan),
        dict(axis=1, before=2, after=2, boundary="constant", constant_boundary=np.nan),
    ],
    type="abs",
    eb=ln_DU_eb_abs,
)


# evaluate the Laplacian numerically by evaluating the quantity of interest
def compute_ln_DU(U):
    return qoi_eb_stencil.evaluate_qoi(U, late_bound=Bindings(X=X, Y=Y))
# we use the safeguard's support for arbitrary grid-based spacing and switch # from 2nd order central finite differences to 2nd order forward/backwards # finite differences at the data boundaries, where data points do not have a # left, right, upper, and lower neighbour # this enables us to compute the Laplacian at all data points, including at # the boundaries # we pad the data with NaNs to denote the missing values qoi_eb_stencil = SafeguardKind.qoi_eb_stencil.value( qoi=""" V["d2Udy2"] = where( c["Y"] > -1, where( c["Y"] < 1, # use 2nd order central finite difference where possible finite_difference( x, order=2, accuracy=2, type=0, axis=0, grid_centre=c["Y"] ), # use 2nd order backwards finite difference at the upper boundary finite_difference( x, order=2, accuracy=1, type=-1, axis=0, grid_centre=c["Y"] ), ), # use 2nd order forward finite difference at the lower boundary finite_difference( x, order=2, accuracy=1, type=1, axis=0, grid_centre=c["Y"] ), ); V["d2Udx2"] = where( c["X"] > -1, where( c["X"] < 1, # use 2nd order central finite difference where possible finite_difference( x, order=2, accuracy=2, type=0, axis=1, grid_centre=c["X"] ), # use 2nd order backwards finite difference at the right boundary finite_difference( x, order=2, accuracy=1, type=-1, axis=1, grid_centre=c["X"] ), ), # use 2nd order forward finite difference at the left boundary finite_difference( x, order=2, accuracy=1, type=1, axis=1, grid_centre=c["X"] ), ); # compute the natural logarithm of the Laplacian return ln(V["d2Udy2"] + V["d2Udx2"]); """, neighbourhood=[ dict(axis=0, before=2, after=2, boundary="constant", constant_boundary=np.nan), dict(axis=1, before=2, after=2, boundary="constant", constant_boundary=np.nan), ], type="abs", eb=ln_DU_eb_abs, ) # evaluate the Laplacian numerically by evaluating the quantity of interest def compute_ln_DU(U): return qoi_eb_stencil.evaluate_qoi(U, late_bound=Bindings(X=X, Y=Y))
Copied!
observations = []
observations = []

Lossless compression¶

We first compress the data losslessly with ZStandard at level 22, which gives maximum compression, to provide a baseline.

Copied!
# compressed with Zstdandard
from numcodecs_wasm_zstd import Zstd

zstd = Zstd(level=22)

with observe.observe(zstd, observations):
    U_zstd_enc = zstd.encode(U)
    U_zstd = zstd.decode(U_zstd_enc)
U_zstd_cr = U.nbytes / U_zstd_enc.nbytes
# compressed with Zstdandard from numcodecs_wasm_zstd import Zstd zstd = Zstd(level=22) with observe.observe(zstd, observations): U_zstd_enc = zstd.encode(U) U_zstd = zstd.decode(U_zstd_enc) U_zstd_cr = U.nbytes / U_zstd_enc.nbytes

Compressing u with lossy compressors¶

We configure each compressor with an absolute error bound of $5 \cdot 10^{-6}$ over the u array.

Copied!
# absolute error bound for error-bounded lossy compression
eb_abs = 5e-6
# absolute error bound for error-bounded lossy compression eb_abs = 5e-6
Copied!
# compressed with ZFP
from numcodecs_wasm_zfp import Zfp

zfp = Zfp(mode="fixed-accuracy", tolerance=eb_abs)

with observe.observe(zfp, observations):
    U_zfp_enc = zfp.encode(U)
    U_zfp = zfp.decode(U_zfp_enc)
U_zfp_cr = U.nbytes / U_zfp_enc.nbytes
# compressed with ZFP from numcodecs_wasm_zfp import Zfp zfp = Zfp(mode="fixed-accuracy", tolerance=eb_abs) with observe.observe(zfp, observations): U_zfp_enc = zfp.encode(U) U_zfp = zfp.decode(U_zfp_enc) U_zfp_cr = U.nbytes / U_zfp_enc.nbytes
Copied!
# compressed with SZ3
from numcodecs_wasm_sz3 import Sz3

sz3 = Sz3(eb_mode="abs", eb_abs=eb_abs)

with observe.observe(sz3, observations):
    U_sz3_enc = sz3.encode(U)
    U_sz3 = sz3.decode(U_sz3_enc)
U_sz3_cr = U.nbytes / U_sz3_enc.nbytes
# compressed with SZ3 from numcodecs_wasm_sz3 import Sz3 sz3 = Sz3(eb_mode="abs", eb_abs=eb_abs) with observe.observe(sz3, observations): U_sz3_enc = sz3.encode(U) U_sz3 = sz3.decode(U_sz3_enc) U_sz3_cr = U.nbytes / U_sz3_enc.nbytes
Copied!
# compressed with SPERR
from numcodecs_wasm_sperr import Sperr

sperr = Sperr(mode="pwe", pwe=eb_abs)

with observe.observe(sperr, observations):
    U_sperr_enc = sperr.encode(U)
    U_sperr = sperr.decode(U_sperr_enc)
U_sperr_cr = U.nbytes / U_sperr_enc.nbytes
# compressed with SPERR from numcodecs_wasm_sperr import Sperr sperr = Sperr(mode="pwe", pwe=eb_abs) with observe.observe(sperr, observations): U_sperr_enc = sperr.encode(U) U_sperr = sperr.decode(U_sperr_enc) U_sperr_cr = U.nbytes / U_sperr_enc.nbytes
Copied!
# compressed to constant zero
from numcodecs_zero import ZeroCodec

zero = ZeroCodec()

with observe.observe(zero, observations):
    U_zero_enc = zero.encode(U)
    U_zero = zero.decode(U_zero_enc)
# compressed to constant zero from numcodecs_zero import ZeroCodec zero = ZeroCodec() with observe.observe(zero, observations): U_zero_enc = zero.encode(U) U_zero = zero.decode(U_zero_enc)

Compressing u using the safeguarded lossy compressors¶

We configure the safeguards to bound the pointwise absolute error on the derived natural logarithm of the Laplacian.

For this second example, we use second-order central finite differences on non-boundary points and second-order forward/backwards finite differences on boundary points so that we can evaluate the Laplacian everywhere.

Copied!
U_sg_qoi = dict()
U_sg_qoi_cr = dict()

# compressed with the safeguards with an absolute error bound over the log of the Laplacian
for codec in [zfp, sz3, sperr, zero]:
    codec_sg_qoi = SafeguardedCodec(
        codec=codec,
        safeguards=[qoi_eb_stencil],
        fixed_constants=dict(X=X, Y=Y),
    )

    with observe.observe(codec_sg_qoi, observations):
        U_sg_qoi_enc = codec_sg_qoi.encode(U)
        U_sg_qoi[codec.codec_id] = codec_sg_qoi.decode(U_sg_qoi_enc)
    U_sg_qoi_cr[codec.codec_id] = U.nbytes / np.asarray(U_sg_qoi_enc).nbytes
U_sg_qoi = dict() U_sg_qoi_cr = dict() # compressed with the safeguards with an absolute error bound over the log of the Laplacian for codec in [zfp, sz3, sperr, zero]: codec_sg_qoi = SafeguardedCodec( codec=codec, safeguards=[qoi_eb_stencil], fixed_constants=dict(X=X, Y=Y), ) with observe.observe(codec_sg_qoi, observations): U_sg_qoi_enc = codec_sg_qoi.encode(U) U_sg_qoi[codec.codec_id] = codec_sg_qoi.decode(U_sg_qoi_enc) U_sg_qoi_cr[codec.codec_id] = U.nbytes / np.asarray(U_sg_qoi_enc).nbytes
Copied!
U_sg_it_qoi = dict()
U_sg_it_qoi_cr = dict()

# compressed with the safeguards with an absolute error bound over the log of the Laplacian
for codec in [zfp, sz3, sperr, zero]:
    codec_sg_it_qoi = SafeguardedCodec(
        codec=codec,
        safeguards=[qoi_eb_stencil],
        fixed_constants=dict(X=X, Y=Y),
        # use iteration to refine the corrections
        compute=dict(unstable_iterative=True),
    )

    with observe.observe(codec_sg_it_qoi, observations):
        U_sg_it_qoi_enc = codec_sg_it_qoi.encode(U)
        U_sg_it_qoi[codec.codec_id] = codec_sg_it_qoi.decode(U_sg_it_qoi_enc)
    U_sg_it_qoi_cr[codec.codec_id] = U.nbytes / np.asarray(U_sg_it_qoi_enc).nbytes
U_sg_it_qoi = dict() U_sg_it_qoi_cr = dict() # compressed with the safeguards with an absolute error bound over the log of the Laplacian for codec in [zfp, sz3, sperr, zero]: codec_sg_it_qoi = SafeguardedCodec( codec=codec, safeguards=[qoi_eb_stencil], fixed_constants=dict(X=X, Y=Y), # use iteration to refine the corrections compute=dict(unstable_iterative=True), ) with observe.observe(codec_sg_it_qoi, observations): U_sg_it_qoi_enc = codec_sg_it_qoi.encode(U) U_sg_it_qoi[codec.codec_id] = codec_sg_it_qoi.decode(U_sg_it_qoi_enc) U_sg_it_qoi_cr[codec.codec_id] = U.nbytes / np.asarray(U_sg_it_qoi_enc).nbytes
Copied!
U_sg_lossless_qoi = dict()
U_sg_lossless_qoi_cr = dict()

# compressed with the safeguards with an absolute error bound over the log of the Laplacian
for codec in [zfp, sz3, sperr, zero]:
    codec_sg_lossless_qoi = SafeguardedCodec(
        codec=codec,
        safeguards=[qoi_eb_stencil],
        fixed_constants=dict(X=X, Y=Y),
        # produce lossless corrections and refine them with iteration
        compute=dict(unstable_iterative=True, unstable_lossless_corrections=True),
    )

    with observe.observe(codec_sg_lossless_qoi, observations):
        U_sg_lossless_qoi_enc = codec_sg_lossless_qoi.encode(U)
        U_sg_lossless_qoi[codec.codec_id] = codec_sg_lossless_qoi.decode(
            U_sg_lossless_qoi_enc
        )
    U_sg_lossless_qoi_cr[codec.codec_id] = (
        U.nbytes / np.asarray(U_sg_lossless_qoi_enc).nbytes
    )
U_sg_lossless_qoi = dict() U_sg_lossless_qoi_cr = dict() # compressed with the safeguards with an absolute error bound over the log of the Laplacian for codec in [zfp, sz3, sperr, zero]: codec_sg_lossless_qoi = SafeguardedCodec( codec=codec, safeguards=[qoi_eb_stencil], fixed_constants=dict(X=X, Y=Y), # produce lossless corrections and refine them with iteration compute=dict(unstable_iterative=True, unstable_lossless_corrections=True), ) with observe.observe(codec_sg_lossless_qoi, observations): U_sg_lossless_qoi_enc = codec_sg_lossless_qoi.encode(U) U_sg_lossless_qoi[codec.codec_id] = codec_sg_lossless_qoi.decode( U_sg_lossless_qoi_enc ) U_sg_lossless_qoi_cr[codec.codec_id] = ( U.nbytes / np.asarray(U_sg_lossless_qoi_enc).nbytes )

Compressing u with OptZConfig¶

Copied!
import numcodecs


class SafetyViolationsMetric(numcodecs.abc.Codec):
    codec_id = "safety-violations-metric"

    def __init__(self):
        self._data = None

    def encode(self, buf):
        # store the original data for later
        self._data = np.array(buf, copy=True)
        # return no metric
        return np.empty(0, dtype=np.float64)

    def decode(self, buf, out=None):
        # compute the violations
        data_ln_DU = compute_ln_DU(self._data)
        buf_ln_DU = compute_ln_DU(buf)
        violations = np.mean(~(np.abs(buf_ln_DU - data_ln_DU) <= ln_DU_eb_abs))
        self._data = None
        # return the violations score metric
        return numcodecs.compat.ndarray_copy(np.float64(violations), out)


numcodecs.registry.register_codec(SafetyViolationsMetric)
import numcodecs class SafetyViolationsMetric(numcodecs.abc.Codec): codec_id = "safety-violations-metric" def __init__(self): self._data = None def encode(self, buf): # store the original data for later self._data = np.array(buf, copy=True) # return no metric return np.empty(0, dtype=np.float64) def decode(self, buf, out=None): # compute the violations data_ln_DU = compute_ln_DU(self._data) buf_ln_DU = compute_ln_DU(buf) violations = np.mean(~(np.abs(buf_ln_DU - data_ln_DU) <= ln_DU_eb_abs)) self._data = None # return the violations score metric return numcodecs.compat.ndarray_copy(np.float64(violations), out) numcodecs.registry.register_codec(SafetyViolationsMetric)
Copied!
from numcodecs_wasm_pressio import Pressio

U_optzconfig = dict()
U_optzconfig_cr = dict()

for codec, parameter, lower_bound in [
    (zfp, "tolerance", 1e-9),  # decent guess
    (sz3, "eb_abs", 1e-9),  # decent guess
    (sperr, "pwe", 1e-9),  # decent guess
]:
    optzconfig = Pressio(
        compressor_id="opt",
        compressor_config={
            "opt:output": ["composite:score"],
            "opt:inputs": [f"numcodecs.rs:{parameter}"],
            "opt:lower_bound": np.log(lower_bound),
            "opt:upper_bound": np.log(eb_abs),
            "opt:max_iterations": 25,
            "opt:objective_mode_name": "max",
        },
        early_config={
            "opt:compressor": "pressio",
            "pressio:compressor": "numcodecs.rs",
            **{
                f"numcodecs.rs:{k}": f"e-{v}" if k == "id" else v
                for k, v in codec.get_config().items()
            },
            "opt:search": "fraz",
            "pressio:metric": "composite",
            "composite:plugins": ["size", "numcodecs.rs-metric"],
            "composite:scripts": [
                """
                violations = metrics["numcodecs.rs-metric:decompression"]
                if violations > 0 then
                    return "score", -violations
                else
                    return "score", metrics["size:compression_ratio"]
                end
                """
            ],
            "numcodecs.rs-metric:id": "safety-violations-metric",
        },
    )

    with observe.observe(optzconfig, observations):
        U_optzconfig_enc = optzconfig.encode(U)
        U_optzconfig[codec.codec_id] = optzconfig.decode(U_optzconfig_enc)
    U_optzconfig_cr[codec.codec_id] = U.nbytes / np.asarray(U_optzconfig_enc).nbytes
from numcodecs_wasm_pressio import Pressio U_optzconfig = dict() U_optzconfig_cr = dict() for codec, parameter, lower_bound in [ (zfp, "tolerance", 1e-9), # decent guess (sz3, "eb_abs", 1e-9), # decent guess (sperr, "pwe", 1e-9), # decent guess ]: optzconfig = Pressio( compressor_id="opt", compressor_config={ "opt:output": ["composite:score"], "opt:inputs": [f"numcodecs.rs:{parameter}"], "opt:lower_bound": np.log(lower_bound), "opt:upper_bound": np.log(eb_abs), "opt:max_iterations": 25, "opt:objective_mode_name": "max", }, early_config={ "opt:compressor": "pressio", "pressio:compressor": "numcodecs.rs", **{ f"numcodecs.rs:{k}": f"e-{v}" if k == "id" else v for k, v in codec.get_config().items() }, "opt:search": "fraz", "pressio:metric": "composite", "composite:plugins": ["size", "numcodecs.rs-metric"], "composite:scripts": [ """ violations = metrics["numcodecs.rs-metric:decompression"] if violations > 0 then return "score", -violations else return "score", metrics["size:compression_ratio"] end """ ], "numcodecs.rs-metric:id": "safety-violations-metric", }, ) with observe.observe(optzconfig, observations): U_optzconfig_enc = optzconfig.encode(U) U_optzconfig[codec.codec_id] = optzconfig.decode(U_optzconfig_enc) U_optzconfig_cr[codec.codec_id] = U.nbytes / np.asarray(U_optzconfig_enc).nbytes
rank={0,1,} iter={0} input={-16.4647,} output={-0.00361252,} objective={-0.00361252}
rank={0,1,} iter={1} input={-18.7364,} output={4.31434,} objective={4.31434}
rank={0,1,} iter={2} input={-14.2276,} output={-0.0477619,} objective={-0.0477619}
rank={0,1,} iter={3} input={-20.7233,} output={3.87286,} objective={3.87286}
rank={0,1,} iter={4} input={-19.6138,} output={4.08427,} objective={4.08427}
rank={0,1,} iter={5} input={-16.5948,} output={-0.00361252,} objective={-0.00361252}
rank={0,1,} iter={6} input={-20.1151,} output={3.87286,} objective={3.87286}
rank={0,1,} iter={7} input={-18.0423,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={8} input={-12.2062,} output={-0.173178,} objective={-0.173178}
rank={0,1,} iter={9} input={-18.2793,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={10} input={-19.1394,} output={4.31434,} objective={4.31434}
rank={0,1,} iter={11} input={-18.1608,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={12} input={-18.468,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={13} input={-19.3399,} output={4.31434,} objective={4.31434}
rank={0,1,} iter={14} input={-18.9384,} output={4.31434,} objective={4.31434}
rank={0,1,} iter={15} input={-18.5626,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={16} input={-18.3739,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={17} input={-20.4176,} output={3.87286,} objective={3.87286}
rank={0,1,} iter={18} input={-19.8319,} output={4.08427,} objective={4.08427}
rank={0,1,} iter={19} input={-18.1011,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={20} input={-18.2199,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={21} input={-18.3265,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={22} input={-18.6101,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={23} input={-18.4202,} output={4.56507,} objective={4.56507}
rank={0,1,} iter={24} input={-18.5143,} output={4.56507,} objective={4.56507}
final_iter={25} inputs={-18.0423,} output={4.56507,}
rank={0,1,} iter={0} input={-16.4647,} output={-0.00195503,} objective={-0.00195503}
rank={0,1,} iter={1} input={-18.7364,} output={-0.000151634,} objective={-0.000151634}
rank={0,1,} iter={2} input={-14.2276,} output={-0.00961113,} objective={-0.00961113}
rank={0,1,} iter={3} input={-18.9211,} output={22.5971,} objective={22.5971}
rank={0,1,} iter={4} input={-20.7233,} output={15.7417,} objective={15.7417}
rank={0,1,} iter={5} input={-12.2076,} output={-0.0120564,} objective={-0.0120564}
rank={0,1,} iter={6} input={-19.7922,} output={-9.53674e-07,} objective={-9.53674e-07}
rank={0,1,} iter={7} input={-17.6017,} output={-0.000749588,} objective={-0.000749588}
rank={0,1,} iter={8} input={-19.2643,} output={-4.86374e-05,} objective={-4.86374e-05}
rank={0,1,} iter={9} input={-15.3432,} output={-0.00452042,} objective={-0.00452042}
rank={0,1,} iter={10} input={-19.0004,} output={22.4294,} objective={22.4294}
rank={0,1,} iter={11} input={-13.2178,} output={-0.00402737,} objective={-0.00402737}
rank={0,1,} iter={12} input={-18.9585,} output={22.6012,} objective={22.6012}
rank={0,1,} iter={13} input={-17.0343,} output={-0.00115108,} objective={-0.00115108}
rank={0,1,} iter={14} input={-18.9408,} output={22.6182,} objective={22.6182}
rank={0,1,} iter={15} input={-18.1704,} output={-0.000402451,} objective={-0.000402451}
rank={0,1,} iter={16} input={-15.9054,} output={-0.000188828,} objective={-0.000188828}
rank={0,1,} iter={17} input={-14.7849,} output={-0.00613689,} objective={-0.00613689}
rank={0,1,} iter={18} input={-20.3229,} output={17.9368,} objective={17.9368}
rank={0,1,} iter={19} input={-13.7225,} output={-0.010644,} objective={-0.010644}
rank={0,1,} iter={20} input={-12.7121,} output={-0.0191288,} objective={-0.0191288}
rank={0,1,} iter={21} input={-20.5138,} output={16.3001,} objective={16.3001}
rank={0,1,} iter={22} input={-20.133,} output={-1.90735e-06,} objective={-1.90735e-06}
rank={0,1,} iter={23} input={-17.8865,} output={28.1549,} objective={28.1549}
rank={0,1,} iter={24} input={-16.7511,} output={-0.00179005,} objective={-0.00179005}
final_iter={25} inputs={-17.8865,} output={28.1549,}
rank={0,1,} iter={0} input={-16.4647,} output={-0.00167561,} objective={-0.00167561}
rank={0,1,} iter={1} input={-18.7364,} output={-1.90735e-05,} objective={-1.90735e-05}
rank={0,1,} iter={2} input={-14.2276,} output={-0.0121365,} objective={-0.0121365}
rank={0,1,} iter={3} input={-18.9211,} output={-1.14441e-05,} objective={-1.14441e-05}
rank={0,1,} iter={4} input={-12.7876,} output={-0.0294952,} objective={-0.0294952}
rank={0,1,} iter={5} input={-20.1487,} output={19.3432,} objective={19.3432}
rank={0,1,} iter={6} input={-20.7233,} output={17.2925,} objective={17.2925}
rank={0,1,} iter={7} input={-20.3707,} output={18.5197,} objective={18.5197}
rank={0,1,} iter={8} input={-19.4779,} output={22.19,} objective={22.19}
rank={0,1,} iter={9} input={-17.6007,} output={-0.000369072,} objective={-0.000369072}
rank={0,1,} iter={10} input={-19.7542,} output={20.9662,} objective={20.9662}
rank={0,1,} iter={11} input={-15.3468,} output={-0.00506592,} objective={-0.00506592}
rank={0,1,} iter={12} input={-19.5744,} output={21.7446,} objective={21.7446}
rank={0,1,} iter={13} input={-13.5084,} output={-0.0193777,} objective={-0.0193777}
rank={0,1,} iter={14} input={-19.1425,} output={-1.90735e-06,} objective={-1.90735e-06}
rank={0,1,} iter={15} input={-12.2099,} output={-0.0399446,} objective={-0.0399446}
rank={0,1,} iter={16} input={-19.3102,} output={-9.53674e-07,} objective={-9.53674e-07}
rank={0,1,} iter={17} input={-17.0321,} output={-0.000904083,} objective={-0.000904083}
rank={0,1,} iter={18} input={-19.5217,} output={21.9796,} objective={21.9796}
rank={0,1,} iter={19} input={-18.1685,} output={-0.000138283,} objective={-0.000138283}
rank={0,1,} iter={20} input={-19.436,} output={-9.53674e-07,} objective={-9.53674e-07}
rank={0,1,} iter={21} input={-14.7871,} output={-0.00792217,} objective={-0.00792217}
rank={0,1,} iter={22} input={-19.4989,} output={22.0852,} objective={22.0852}
rank={0,1,} iter={23} input={-15.9059,} output={-0.00310135,} objective={-0.00310135}
rank={0,1,} iter={24} input={-19.4881,} output={22.1341,} objective={22.1341}
final_iter={25} inputs={-19.4779,} output={22.19,}

Visual comparison of the compressed natural logarithms of the Laplacians¶

Copied!
fig, axs = plt.subplots(nrows=3, ncols=4, figsize=(16, 12))

plot_DU(
    compute_ln_DU,
    U,
    1.0,
    axs[0, 0],
    "Analytical",
    DU_eb_abs=ln_DU_eb_abs,
    my_DU=np.log(DU),
    transform_symbol="ln",
    include_boundary=True,
)
plot_DU(
    compute_ln_DU,
    U_zfp,
    U_zfp_cr,
    axs[0, 1],
    r"ZFP($\epsilon_{abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    include_boundary=True,
    inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)),
)
plot_DU(
    compute_ln_DU,
    U_sz3,
    U_sz3_cr,
    axs[0, 2],
    r"SZ3($\epsilon_{abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    include_boundary=True,
    inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)),
)
plot_DU(
    compute_ln_DU,
    U_sperr,
    U_sperr_cr,
    axs[0, 3],
    r"SPERR($\epsilon_{abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    include_boundary=True,
    inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)),
)

plot_DU(
    compute_ln_DU,
    U_sg_qoi["zero"],
    U_sg_qoi_cr["zero"],
    axs[1, 0],
    r"Safeguarded(0, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    corr=U_zero,
    my_U_it=U_sg_it_qoi["zero"],
    cr_it=U_sg_it_qoi_cr["zero"],
    include_boundary=True,
    inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)),
)
plot_DU(
    compute_ln_DU,
    U_sg_qoi["zfp.rs"],
    U_sg_qoi_cr["zfp.rs"],
    axs[1, 1],
    r"Safeguarded(ZFP, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    corr=U_zfp,
    my_U_it=U_sg_it_qoi["zfp.rs"],
    cr_it=U_sg_it_qoi_cr["zfp.rs"],
    include_boundary=True,
    inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)),
)
plot_DU(
    compute_ln_DU,
    U_sg_qoi["sz3.rs"],
    U_sg_qoi_cr["sz3.rs"],
    axs[1, 2],
    r"Safeguarded(SZ3, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    corr=U_sz3,
    my_U_it=U_sg_it_qoi["sz3.rs"],
    cr_it=U_sg_it_qoi_cr["sz3.rs"],
    include_boundary=True,
    inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)),
)
plot_DU(
    compute_ln_DU,
    U_sg_qoi["sperr.rs"],
    U_sg_qoi_cr["sperr.rs"],
    axs[1, 3],
    r"Safeguarded(SPERR, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    corr=U_sperr,
    my_U_it=U_sg_it_qoi["sperr.rs"],
    cr_it=U_sg_it_qoi_cr["sperr.rs"],
    include_boundary=True,
    inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)),
)

axs[2, 0].set_axis_off()

plot_DU(
    compute_ln_DU,
    U_optzconfig["zfp.rs"],
    U_optzconfig_cr["zfp.rs"],
    axs[2, 1],
    r"OptZConfig(ZFP, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    include_boundary=True,
    inset=False,
)
plot_DU(
    compute_ln_DU,
    U_optzconfig["sz3.rs"],
    U_optzconfig_cr["sz3.rs"],
    axs[2, 2],
    r"OptZConfig(SZ3, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    include_boundary=True,
    inset=False,
)
plot_DU(
    compute_ln_DU,
    U_optzconfig["sperr.rs"],
    U_optzconfig_cr["sperr.rs"],
    axs[2, 3],
    r"OptZConfig(SPERR, $\epsilon_{QoI,abs}$)",
    DU_eb_abs=ln_DU_eb_abs,
    transform_symbol="ln",
    include_boundary=True,
    inset=False,
)

plt.tight_layout()

plt.savefig(Path("plots") / "derivative-log-exp.pdf", dpi=300)

plt.show()
fig, axs = plt.subplots(nrows=3, ncols=4, figsize=(16, 12)) plot_DU( compute_ln_DU, U, 1.0, axs[0, 0], "Analytical", DU_eb_abs=ln_DU_eb_abs, my_DU=np.log(DU), transform_symbol="ln", include_boundary=True, ) plot_DU( compute_ln_DU, U_zfp, U_zfp_cr, axs[0, 1], r"ZFP($\epsilon_{abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", include_boundary=True, inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)), ) plot_DU( compute_ln_DU, U_sz3, U_sz3_cr, axs[0, 2], r"SZ3($\epsilon_{abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", include_boundary=True, inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)), ) plot_DU( compute_ln_DU, U_sperr, U_sperr_cr, axs[0, 3], r"SPERR($\epsilon_{abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", include_boundary=True, inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)), ) plot_DU( compute_ln_DU, U_sg_qoi["zero"], U_sg_qoi_cr["zero"], axs[1, 0], r"Safeguarded(0, $\epsilon_{QoI,abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", corr=U_zero, my_U_it=U_sg_it_qoi["zero"], cr_it=U_sg_it_qoi_cr["zero"], include_boundary=True, inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)), ) plot_DU( compute_ln_DU, U_sg_qoi["zfp.rs"], U_sg_qoi_cr["zfp.rs"], axs[1, 1], r"Safeguarded(ZFP, $\epsilon_{QoI,abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", corr=U_zfp, my_U_it=U_sg_it_qoi["zfp.rs"], cr_it=U_sg_it_qoi_cr["zfp.rs"], include_boundary=True, inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)), ) plot_DU( compute_ln_DU, U_sg_qoi["sz3.rs"], U_sg_qoi_cr["sz3.rs"], axs[1, 2], r"Safeguarded(SZ3, $\epsilon_{QoI,abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", corr=U_sz3, my_U_it=U_sg_it_qoi["sz3.rs"], cr_it=U_sg_it_qoi_cr["sz3.rs"], include_boundary=True, inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)), ) plot_DU( compute_ln_DU, U_sg_qoi["sperr.rs"], U_sg_qoi_cr["sperr.rs"], axs[1, 3], r"Safeguarded(SPERR, $\epsilon_{QoI,abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", corr=U_sperr, my_U_it=U_sg_it_qoi["sperr.rs"], cr_it=U_sg_it_qoi_cr["sperr.rs"], include_boundary=True, inset_offset=(1 - 0.05 - (1 / 3), 0.5 - (1 / 6)), ) axs[2, 0].set_axis_off() plot_DU( compute_ln_DU, U_optzconfig["zfp.rs"], U_optzconfig_cr["zfp.rs"], axs[2, 1], r"OptZConfig(ZFP, $\epsilon_{QoI,abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", include_boundary=True, inset=False, ) plot_DU( compute_ln_DU, U_optzconfig["sz3.rs"], U_optzconfig_cr["sz3.rs"], axs[2, 2], r"OptZConfig(SZ3, $\epsilon_{QoI,abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", include_boundary=True, inset=False, ) plot_DU( compute_ln_DU, U_optzconfig["sperr.rs"], U_optzconfig_cr["sperr.rs"], axs[2, 3], r"OptZConfig(SPERR, $\epsilon_{QoI,abs}$)", DU_eb_abs=ln_DU_eb_abs, transform_symbol="ln", include_boundary=True, inset=False, ) plt.tight_layout() plt.savefig(Path("plots") / "derivative-log-exp.pdf", dpi=300) plt.show()
No description has been provided for this image
Copied!
u_log_exp_sg_table = (
    pd.concat(
        [
            table_DU(
                compute_ln_DU,
                U_sg_lossless_qoi["zero"],
                U_sg_lossless_qoi_cr["zero"],
                ["0", "", r"$\epsilon_{QoI,abs}$", "lossless"],
                ln_DU_eb_abs,
                U_zero,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_qoi["zero"],
                U_sg_qoi_cr["zero"],
                ["0", "", r"$\epsilon_{QoI,abs}$", "one-shot"],
                ln_DU_eb_abs,
                U_zero,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_it_qoi["zero"],
                U_sg_it_qoi_cr["zero"],
                ["0", "", r"$\epsilon_{QoI,abs}$", "iterative"],
                ln_DU_eb_abs,
                U_zero,
            ),
            table_DU(
                compute_ln_DU,
                U_zfp,
                U_zfp_cr,
                [r"ZFP($\epsilon_{abs}$)", f"{eb_abs}", "-", ""],
                ln_DU_eb_abs,
                None,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_lossless_qoi["zfp.rs"],
                U_sg_lossless_qoi_cr["zfp.rs"],
                [
                    r"ZFP($\epsilon_{abs}$)",
                    f"{eb_abs}",
                    r"$\epsilon_{QoI,abs}$",
                    "lossless",
                ],
                ln_DU_eb_abs,
                U_zfp,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_qoi["zfp.rs"],
                U_sg_qoi_cr["zfp.rs"],
                [
                    r"ZFP($\epsilon_{abs}$)",
                    f"{eb_abs}",
                    r"$\epsilon_{QoI,abs}$",
                    "one-shot",
                ],
                ln_DU_eb_abs,
                U_zfp,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_it_qoi["zfp.rs"],
                U_sg_it_qoi_cr["zfp.rs"],
                [
                    r"ZFP($\epsilon_{abs}$)",
                    f"{eb_abs}",
                    r"$\epsilon_{QoI,abs}$",
                    "iterative",
                ],
                ln_DU_eb_abs,
                U_zfp,
            ),
            table_DU(
                compute_ln_DU,
                U_optzconfig["zfp.rs"],
                U_optzconfig_cr["zfp.rs"],
                [
                    "OptZConfig(ZFP)",
                    "",
                    r"$\epsilon_{QoI,abs}$",
                    "",
                ],
                ln_DU_eb_abs,
                None,
            ),
            table_DU(
                compute_ln_DU,
                U_sz3,
                U_sz3_cr,
                [r"SZ3($\epsilon_{abs}$)", f"{eb_abs}", "-", ""],
                ln_DU_eb_abs,
                None,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_lossless_qoi["sz3.rs"],
                U_sg_lossless_qoi_cr["sz3.rs"],
                [
                    r"SZ3($\epsilon_{abs}$)",
                    f"{eb_abs}",
                    r"$\epsilon_{QoI,abs}$",
                    "lossless",
                ],
                ln_DU_eb_abs,
                U_sz3,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_qoi["sz3.rs"],
                U_sg_qoi_cr["sz3.rs"],
                [
                    r"SZ3($\epsilon_{abs}$)",
                    f"{eb_abs}",
                    r"$\epsilon_{QoI,abs}$",
                    "one-shot",
                ],
                ln_DU_eb_abs,
                U_sz3,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_it_qoi["sz3.rs"],
                U_sg_it_qoi_cr["sz3.rs"],
                [
                    r"SZ3($\epsilon_{abs}$)",
                    f"{eb_abs}",
                    r"$\epsilon_{QoI,abs}$",
                    "iterative",
                ],
                ln_DU_eb_abs,
                U_sz3,
            ),
            table_DU(
                compute_ln_DU,
                U_optzconfig["sz3.rs"],
                U_optzconfig_cr["sz3.rs"],
                [
                    "OptZConfig(SZ3)",
                    "",
                    r"$\epsilon_{QoI,abs}$",
                    "",
                ],
                ln_DU_eb_abs,
                None,
            ),
            table_DU(
                compute_ln_DU,
                U_sperr,
                U_sperr_cr,
                [r"SPERR($\epsilon_{abs}$)", f"{eb_abs}", "-", ""],
                ln_DU_eb_abs,
                None,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_lossless_qoi["sperr.rs"],
                U_sg_lossless_qoi_cr["sperr.rs"],
                [
                    r"SPERR($\epsilon_{abs}$)",
                    f"{eb_abs}",
                    r"$\epsilon_{QoI,abs}$",
                    "lossless",
                ],
                ln_DU_eb_abs,
                U_sperr,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_qoi["sperr.rs"],
                U_sg_qoi_cr["sperr.rs"],
                [
                    r"SPERR($\epsilon_{abs}$)",
                    f"{eb_abs}",
                    r"$\epsilon_{QoI,abs}$",
                    "one-shot",
                ],
                ln_DU_eb_abs,
                U_sperr,
            ),
            table_DU(
                compute_ln_DU,
                U_sg_it_qoi["sperr.rs"],
                U_sg_it_qoi_cr["sperr.rs"],
                [
                    r"SPERR($\epsilon_{abs}$)",
                    f"{eb_abs}",
                    r"$\epsilon_{QoI,abs}$",
                    "iterative",
                ],
                ln_DU_eb_abs,
                U_sperr,
            ),
            table_DU(
                compute_ln_DU,
                U_optzconfig["sperr.rs"],
                U_optzconfig_cr["sperr.rs"],
                [
                    "OptZConfig(SPERR)",
                    "",
                    r"$\epsilon_{QoI,abs}$",
                    "",
                ],
                ln_DU_eb_abs,
                None,
            ),
            table_DU(
                compute_ln_DU,
                U_zstd,
                U_zstd_cr,
                ["ZSTD(22)", "", "-", ""],
                ln_DU_eb_abs,
                None,
            ),
        ]
    )
    .drop(r"$\epsilon_{abs}$", axis="columns")
    .rename(
        columns={
            r"$L_{\infty}(\Delta \hat{u})$": r"$L_{\infty}(\ln(\Delta \hat{u}))$",
            r"$L_{2}(\Delta \hat{u})$": r"$L_{2}(\ln(\Delta \hat{u}))$",
        }
    )
    .set_index(["Compressor", "Safeguarded", "Corrections"])
)

Path("tables").joinpath("derivative-log-exp.tex").write_text(
    u_log_exp_sg_table.to_latex(escape=False)
    .replace("%", r"\%")
    .replace("\\cline{1-9} \\cline{2-9}\n\\bottomrule", "\\bottomrule")
)

u_log_exp_sg_table
u_log_exp_sg_table = ( pd.concat( [ table_DU( compute_ln_DU, U_sg_lossless_qoi["zero"], U_sg_lossless_qoi_cr["zero"], ["0", "", r"$\epsilon_{QoI,abs}$", "lossless"], ln_DU_eb_abs, U_zero, ), table_DU( compute_ln_DU, U_sg_qoi["zero"], U_sg_qoi_cr["zero"], ["0", "", r"$\epsilon_{QoI,abs}$", "one-shot"], ln_DU_eb_abs, U_zero, ), table_DU( compute_ln_DU, U_sg_it_qoi["zero"], U_sg_it_qoi_cr["zero"], ["0", "", r"$\epsilon_{QoI,abs}$", "iterative"], ln_DU_eb_abs, U_zero, ), table_DU( compute_ln_DU, U_zfp, U_zfp_cr, [r"ZFP($\epsilon_{abs}$)", f"{eb_abs}", "-", ""], ln_DU_eb_abs, None, ), table_DU( compute_ln_DU, U_sg_lossless_qoi["zfp.rs"], U_sg_lossless_qoi_cr["zfp.rs"], [ r"ZFP($\epsilon_{abs}$)", f"{eb_abs}", r"$\epsilon_{QoI,abs}$", "lossless", ], ln_DU_eb_abs, U_zfp, ), table_DU( compute_ln_DU, U_sg_qoi["zfp.rs"], U_sg_qoi_cr["zfp.rs"], [ r"ZFP($\epsilon_{abs}$)", f"{eb_abs}", r"$\epsilon_{QoI,abs}$", "one-shot", ], ln_DU_eb_abs, U_zfp, ), table_DU( compute_ln_DU, U_sg_it_qoi["zfp.rs"], U_sg_it_qoi_cr["zfp.rs"], [ r"ZFP($\epsilon_{abs}$)", f"{eb_abs}", r"$\epsilon_{QoI,abs}$", "iterative", ], ln_DU_eb_abs, U_zfp, ), table_DU( compute_ln_DU, U_optzconfig["zfp.rs"], U_optzconfig_cr["zfp.rs"], [ "OptZConfig(ZFP)", "", r"$\epsilon_{QoI,abs}$", "", ], ln_DU_eb_abs, None, ), table_DU( compute_ln_DU, U_sz3, U_sz3_cr, [r"SZ3($\epsilon_{abs}$)", f"{eb_abs}", "-", ""], ln_DU_eb_abs, None, ), table_DU( compute_ln_DU, U_sg_lossless_qoi["sz3.rs"], U_sg_lossless_qoi_cr["sz3.rs"], [ r"SZ3($\epsilon_{abs}$)", f"{eb_abs}", r"$\epsilon_{QoI,abs}$", "lossless", ], ln_DU_eb_abs, U_sz3, ), table_DU( compute_ln_DU, U_sg_qoi["sz3.rs"], U_sg_qoi_cr["sz3.rs"], [ r"SZ3($\epsilon_{abs}$)", f"{eb_abs}", r"$\epsilon_{QoI,abs}$", "one-shot", ], ln_DU_eb_abs, U_sz3, ), table_DU( compute_ln_DU, U_sg_it_qoi["sz3.rs"], U_sg_it_qoi_cr["sz3.rs"], [ r"SZ3($\epsilon_{abs}$)", f"{eb_abs}", r"$\epsilon_{QoI,abs}$", "iterative", ], ln_DU_eb_abs, U_sz3, ), table_DU( compute_ln_DU, U_optzconfig["sz3.rs"], U_optzconfig_cr["sz3.rs"], [ "OptZConfig(SZ3)", "", r"$\epsilon_{QoI,abs}$", "", ], ln_DU_eb_abs, None, ), table_DU( compute_ln_DU, U_sperr, U_sperr_cr, [r"SPERR($\epsilon_{abs}$)", f"{eb_abs}", "-", ""], ln_DU_eb_abs, None, ), table_DU( compute_ln_DU, U_sg_lossless_qoi["sperr.rs"], U_sg_lossless_qoi_cr["sperr.rs"], [ r"SPERR($\epsilon_{abs}$)", f"{eb_abs}", r"$\epsilon_{QoI,abs}$", "lossless", ], ln_DU_eb_abs, U_sperr, ), table_DU( compute_ln_DU, U_sg_qoi["sperr.rs"], U_sg_qoi_cr["sperr.rs"], [ r"SPERR($\epsilon_{abs}$)", f"{eb_abs}", r"$\epsilon_{QoI,abs}$", "one-shot", ], ln_DU_eb_abs, U_sperr, ), table_DU( compute_ln_DU, U_sg_it_qoi["sperr.rs"], U_sg_it_qoi_cr["sperr.rs"], [ r"SPERR($\epsilon_{abs}$)", f"{eb_abs}", r"$\epsilon_{QoI,abs}$", "iterative", ], ln_DU_eb_abs, U_sperr, ), table_DU( compute_ln_DU, U_optzconfig["sperr.rs"], U_optzconfig_cr["sperr.rs"], [ "OptZConfig(SPERR)", "", r"$\epsilon_{QoI,abs}$", "", ], ln_DU_eb_abs, None, ), table_DU( compute_ln_DU, U_zstd, U_zstd_cr, ["ZSTD(22)", "", "-", ""], ln_DU_eb_abs, None, ), ] ) .drop(r"$\epsilon_{abs}$", axis="columns") .rename( columns={ r"$L_{\infty}(\Delta \hat{u})$": r"$L_{\infty}(\ln(\Delta \hat{u}))$", r"$L_{2}(\Delta \hat{u})$": r"$L_{2}(\ln(\Delta \hat{u}))$", } ) .set_index(["Compressor", "Safeguarded", "Corrections"]) ) Path("tables").joinpath("derivative-log-exp.tex").write_text( u_log_exp_sg_table.to_latex(escape=False) .replace("%", r"\%") .replace("\\cline{1-9} \\cline{2-9}\n\\bottomrule", "\\bottomrule") ) u_log_exp_sg_table
$L_{\infty}(\hat{u})$ $L_{\infty}(\ln(\Delta \hat{u}))$ $L_{2}(\ln(\Delta \hat{u}))$ V C CR
Compressor Safeguarded Corrections
0 $\epsilon_{QoI,abs}$ lossless 0.0 0.0 0.0 0 100.0% $\times$ 27.22
one-shot 0.0012 0.087 0.028 0 100.0% $\times$ 329.22
iterative 0.0012 0.087 0.028 0 100.0% $\times$ 329.22
ZFP($\epsilon_{abs}$) - 2e-06 NaN (2.7e+01) NaN (1.3) 17.3% $\times$ 8.2
$\epsilon_{QoI,abs}$ lossless 2e-06 0.1 0.019 0 23.4% $\times$ 7.04
one-shot 2e-06 0.087 0.018 0 30.1% $\times$ 8.0
iterative 2e-06 0.1 0.023 0 22.6% $\times$ 8.02
OptZConfig(ZFP) $\epsilon_{QoI,abs}$ 4.2e-09 0.084 0.0024 0 $\times$ 4.57
SZ3($\epsilon_{abs}$) - 5e-06 NaN (6.6) NaN (0.052) 1.4% $\times$ 159.4
$\epsilon_{QoI,abs}$ lossless 5e-06 0.1 0.0085 0 29.7% $\times$ 4.11
one-shot 5e-06 0.089 0.018 0 45.6% $\times$ 28.95
iterative 5e-06 0.1 0.017 0 29.5% $\times$ 37.5
OptZConfig(SZ3) $\epsilon_{QoI,abs}$ 1.7e-08 0.099 0.002 0 $\times$ 28.15
SPERR($\epsilon_{abs}$) - 5e-06 NaN (1.3e+01) NaN (0.16) 4.0% $\times$ 91.59
$\epsilon_{QoI,abs}$ lossless 5e-06 0.1 0.009 0 14.8% $\times$ 7.18
one-shot 5e-06 0.092 0.014 0 28.7% $\times$ 31.48
iterative 5e-06 0.1 0.014 0 14.6% $\times$ 41.2
OptZConfig(SPERR) $\epsilon_{QoI,abs}$ 3.5e-09 0.079 0.0007 0 $\times$ 22.19
ZSTD(22) - 0.0 0.0 0.0 0 $\times$ 73.21
Copied!
import json

with Path("observations").joinpath("derivative-log-exp.json").open("w") as f:
    json.dump(observations, f)
import json with Path("observations").joinpath("derivative-log-exp.json").open("w") as f: json.dump(observations, f)
Copied!

Next

Built with ProperDocs using a theme provided by Read the Docs.