summaryrefslogtreecommitdiff
path: root/examples/poiseulle_particles_2d_compare/.nix/derivation.nix
blob: de2d415ded0a0ad595a1996f081bf2f244c73d7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
{ lib
, stdenv
, python3
}:

{ pkgs ? import <nixpkgs> {} }:

let

  pythonEnv = python3.withPackages (ps: with ps; [
    pandas
    matplotlib
    numpy
    imageio        # for video output
    imageio-ffmpeg # ffmpeg backend for imageio
  ]);

  # The comparison & video generation script (embedded)
  compareAndRenderPy = pkgs.writeText "compare_and_render.py" ''
    import pandas as pd
    import matplotlib.pyplot as plt
    import numpy as np
    import argparse
    import os
    import imageio.v2 as iio
    from matplotlib.animation import FuncAnimation, FFMpegWriter

    def main():
        parser = argparse.ArgumentParser()
        parser.add_argument('--csv1', required=True)
        parser.add_argument('--csv2', required=True)
        parser.add_argument('--csv3', required=True)
        parser.add_argument('--video-dir', required=True)
        args = parser.parse_args()

        df1 = pd.read_csv(args.csv1)
        df2 = pd.read_csv(args.csv2)
        df3 = pd.read_csv(args.csv3)

        times = df1['time'].values
        fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))

        def update(frame):
            ax1.clear()
            ax2.clear()
            ax1.set_title(f'Velocity at t = {times[frame]:.2f}')
            ax2.set_title(f'Pressure at t = {times[frame]:.2f}')
            ax1.plot(times[:frame+1], df1['velocity'][:frame+1], label='Binary1')
            ax1.plot(times[:frame+1], df2['velocity'][:frame+1], label='Binary2')
            ax1.plot(times[:frame+1], df3['velocity'][:frame+1], label='Binary3')
            ax2.plot(times[:frame+1], df1['pressure'][:frame+1], label='Binary1')
            ax2.plot(times[:frame+1], df2['pressure'][:frame+1], label='Binary2')
            ax2.plot(times[:frame+1], df3['pressure'][:frame+1], label='Binary3')
            ax1.legend(), ax2.legend()
            ax1.set_xlim(times[0], times[-1])
            ax2.set_xlim(times[0], times[-1])

        ani = FuncAnimation(fig, update, frames=len(times), repeat=False)
        writer = FFMpegWriter(fps=5, bitrate=1800)
        os.makedirs(args.video_dir, exist_ok=True)
        video_path = os.path.join(args.video_dir, 'comparison.mp4')
        ani.save(video_path, writer=writer)
        print(f"Video saved to {video_path}")

    if __name__ == '__main__':
        main()
  '';

  # Wrapper script that runs the three binaries and then the Python comparison
  runScript = pkgs.writeShellScript "run-simulation-pipeline" ''
    set -e
    mkdir -p results videos

    echo "Running binary1..."
    ${binary1}/bin/sim1
    echo "Running binary2..."
    ${binary2}/bin/sim2
    echo "Running binary3..."
    ${binary3}/bin/sim3

    echo "Generating comparison video..."
    ${pythonEnv}/bin/python ${compareAndRenderPy} \
      --csv1 results/binary1.csv \
      --csv2 results/binary2.csv \
      --csv3 results/binary3.csv \
      --video-dir videos

    echo "Done. Video available at videos/comparison.mp4"
  '';

in
pkgs.stdenv.mkDerivation {
  name = "simulation-pipeline";
  buildInputs = [ hlbm_2d psm_2d bgk_2d pythonEnv pkgs.ffmpeg ]; # ffmpeg for video encoding
  buildCommand = ''
    mkdir -p $out/bin
    cp ${runScript} $out/bin/run-pipeline
    chmod +x $out/bin/run-pipeline
    # Optionally copy the Python script for reference
    cp ${compareAndRenderPy} $out/compare_and_render.py
    echo "Pipeline installed. Run $out/bin/run-pipeline"
  '';
}