Skip to content

API

main

Tools for rendering the PFHub data.

efficiency_plot

efficiency_plot(
    benchmark_id, benchmark_path=BENCHMARK_PATH
)

Plot memory usage vs. runtime for a given benchmark

Parameters:

  • benchmark_id

    the benchmark ID to plot

  • benchmark_path

    path to data file used by glob

Source code in pfhub/main.py
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
def efficiency_plot(benchmark_id, benchmark_path=BENCHMARK_PATH):  # pragma: no cover
    """Plot memory usage vs. runtime for a given benchmark

    Args:
      benchmark_id: the benchmark ID to plot
      benchmark_path: path to data file used by glob
    """

    def df_time(id_):
        norm = lambda x: x.wall_time.astype(float) / x.sim_time.astype(float)
        return pipe(
            get_result_data(
                ["run_time"],
                [id_],
                ["sim_time", "wall_time"],
                benchmark_path=benchmark_path,
            ),
            lambda x: get(
                x.groupby(["sim_name"])["sim_time"].transform(max) == x["sim_time"], x
            ),
            lambda x: x.assign(time_norm=norm(x)),
        )

    def df_memory(id_):
        mem = {"KB": 1, "MB": 1024, "GB": 1024**2}
        func = lambda x: x.value * mem.get(x.unit, 1.0)
        return pipe(
            get_result_data(
                ["memory_usage"],
                [id_],
                ["value", "unit"],
                benchmark_path=benchmark_path,
            ),
            lambda x: x.assign(memory_norm=x.apply(func, axis=1)),
        )

    return pipe(
        pandas.merge(
            df_time(benchmark_id),
            df_memory(benchmark_id),
            on="sim_name",
        ),
        lambda x: px.scatter(
            x,
            x="time_norm",
            y="memory_norm",
            log_x=True,
            log_y=True,
            title="Numerical Efficiency",
            color="sim_name",
            labels={
                "sim_name": "Simulation Result",
                "time_norm": r"<i>t</i><sub>Wall</sub> / <i>t</i><sub>Sim</sub> *",
                "memory_norm": "Memory Usage [KB]",
            },
        ),
        lambda x: x.update_layout(title_x=0.5),
    )

levelset_plot

levelset_plot(
    data,
    layout=None,
    columns=("x", "y", "z"),
    mask_func=lambda x: slice(len(x)),
)

Generate a Plotly level set plot

Parameters:

  • data

    extracted data as a data frame

  • layout

    dictionary with "x", "y" and "title" keys to customize the plot

  • mask_func

    function to apply to remove values (helps to reduce memory usage)

Example:

>>> x, y = np.mgrid[-1:1:10j, -1:1:10j]
>>> x = x.flatten()
>>> y = y.flatten()
>>> r = np.sqrt((x)**2 + (y)**2)
>>> z = 1 - r
>>> sim_name = ['a'] * len(x)
>>> d = dict(x=x, y=y, z=z, sim_name=sim_name)
>>> df = pandas.DataFrame(d)
>>> levelset_plot(df, layout={'levelset' : 0.5})
Figure({
    'data': [{'colorscale': [[0, 'rgb(229, 134, 6)'], [1, 'rgb(229, 134, 6)']],
...
               'yaxis': {'range': [-1, 1], 'scaleanchor': 'x', 'scaleratio': 1}}
})
>>> df.z = df.z - 0.5
>>> levelset_plot(df)
Figure({
    'data': [{'colorscale': [[0, 'rgb(229, 134, 6)'], [1, 'rgb(229, 134, 6)']],
...
               'yaxis': {'range': [-1, 1], 'scaleanchor': 'x', 'scaleratio': 1}}
})

Source code in pfhub/main.py
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
def levelset_plot(
    data, layout=None, columns=("x", "y", "z"), mask_func=lambda x: slice(len(x))
):
    r"""Generate a Plotly level set plot

    Args:
      data: extracted data as a data frame
      layout: dictionary with "x", "y" and "title" keys to customize the plot
      mask_func: function to apply to remove values (helps to reduce memory usage)

    Example:

    ```
    >>> x, y = np.mgrid[-1:1:10j, -1:1:10j]
    >>> x = x.flatten()
    >>> y = y.flatten()
    >>> r = np.sqrt((x)**2 + (y)**2)
    >>> z = 1 - r
    >>> sim_name = ['a'] * len(x)
    >>> d = dict(x=x, y=y, z=z, sim_name=sim_name)
    >>> df = pandas.DataFrame(d)
    >>> levelset_plot(df, layout={'levelset' : 0.5})
    Figure({
        'data': [{'colorscale': [[0, 'rgb(229, 134, 6)'], [1, 'rgb(229, 134, 6)']],
    ...
                   'yaxis': {'range': [-1, 1], 'scaleanchor': 'x', 'scaleratio': 1}}
    })
    >>> df.z = df.z - 0.5
    >>> levelset_plot(df)
    Figure({
        'data': [{'colorscale': [[0, 'rgb(229, 134, 6)'], [1, 'rgb(229, 134, 6)']],
    ...
                   'yaxis': {'range': [-1, 1], 'scaleanchor': 'x', 'scaleratio': 1}}
    })

    ```
    """
    if layout is None:
        layout = {}

    colorscale = lambda index: pipe(
        px.colors.qualitative.Vivid,
        lambda x: x[index % len(x)],
        lambda x: [[0, x], [1, x]],
    )

    get_contour = lambda df, name, counter: go.Contour(
        z=df[columns[2]],
        x=df[columns[0]],
        y=df[columns[1]],
        contours={
            "start": get("levelset", layout, 0.0),
            "end": get("levelset", layout, 0.0),
            "size": 0.0,
            "coloring": "lines",
        },
        colorbar=None,
        showscale=False,
        line_width=2,
        name=name,
        showlegend=True,
        colorscale=colorscale(counter),
    )

    update_layout = lambda fig: fig.update_layout(
        title=get("title", layout, ""),
        title_x=0.5,
        xaxis={"range": get("range", layout, [-1, 1]), "constrain": "domain"},
        yaxis={
            "scaleanchor": "x",
            "scaleratio": 1,
            "range": get("range", layout, [-1, 1]),
        },
    )

    return pipe(
        data,
        lambda df: df[mask_func(df)],
        lambda x: x.groupby("sim_name"),
        enumerate,
        map_(lambda x: get_contour(df=x[1][1], name=x[1][0], counter=x[0])),
        list,
        go.Figure,
        do(update_layout),
    )

cli

The CLI command line tool

download_zenodo

download_zenodo(url, dest)

Download a Zenodo record

Works with any Zenodo link

Parameters:

  • url

    the URL of either a meta.yaml or Zenodo record

  • dest

    the destination directory

Source code in pfhub/scripts/cli.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
@cli.command(epilog=EPILOG)
@click.argument("url", type=click_params.URL)
@click.option(
    "--dest",
    "-d",
    help="destination directory",
    default="./",
    type=click.Path(exists=True, writable=True, file_okay=False),
)
def download_zenodo(url, dest):
    """Download a Zenodo record

    Works with any Zenodo link

    Args:
      url: the URL of either a meta.yaml or Zenodo record
      dest: the destination directory
    """
    record_id = get_zenodo_record_id(url, zenodo_regexs())
    sandbox = False
    if record_id is None:
        record_id = get_zenodo_record_id(url, zenodo_sandbox_regexs())
        sandbox = True

    if record_id is not None:
        local_filepaths = download_zenodo_(record_id, sandbox=sandbox, dest=dest)
        output(local_filepaths)
    else:
        click.secho(f"{url} does not match any expected regex for Zenodo", fg="red")
        sys.exit(1)