Ejemplo n.º 1
0
 def _test_op_construction(self, array, op):
     a = op(array)
     v = isle.Vector(op(array))
     self.assertTrue(
         core.isEqual(a, v),
         msg="Failed check for scalar type: {typ} and operation: {op}".
         format(typ=array.dtype, op=op))
def hmc(lat, params, file, log):

    LATTICE = lat.name
    nt = lat.nt()
    discretization = DISC(params.hopping)

    rng = isle.random.NumpyRNG(1075)

    hmcState = isle.drivers.hmc.newRun(lat, params, rng, makeAction, file,
                                       False)

    # Generate a random initial condition.
    phi = isle.Vector(
        rng.normal(0,
                   params.tilde("U", lat)**(1 / 2), lat.lattSize()) + 0j)

    log.info(f"Thermalizing {LATTICE} nt={nt} {discretization}")
    evolver = isle.evolver.LinearStepLeapfrog(hmcState.action, (1, 1), (20, 5),
                                              99, rng)
    evStage = hmcState(phi, evolver, 1000, saveFreq=0, checkpointFreq=0)
    hmcState.resetIndex()

    log.info(f"Producing {LATTICE} nt={nt} {discretization}")
    evolver = isle.evolver.ConstStepLeapfrog(hmcState.action, 1, 5, rng)
    hmcState(evStage, evolver, 100000, saveFreq=10, checkpointFreq=100)
Ejemplo n.º 3
0
def main():
    args = _init()

    # Load the spatial lattice.
    lat = isle.fileio.yaml.loadLattice(LATTICE)
    # Store nt.
    lat.nt(NT)

    # Set up a random number generator.
    rng = isle.random.NumpyRNG(1337)

    # Set up a fresh HMC driver.
    hmcState = isle.drivers.hmc.newRun(lat, PARAMS, rng, makeAction,
                                       args.outfile, args.overwrite)

    # Generate a random initial condition.
    # Note that configurations must be vectors of complex numbers.
    phi = isle.Vector(
        rng.normal(0,
                   PARAMS.tilde("U", lat)**(1 / 2), lat.lattSize()) + 0j)

    # Run thermalization.
    getLogger(__name__).info("Thermalizing")
    # Pick an evolver which linearly decreases the number of MD steps from 20 to 5.
    evolver = isle.evolver.LinearStepLeapfrog(hmcState.action, (1, 1), (20, 5),
                                              args.ntrajectories - 1, rng)
    # Thermalize configuration using the command line arguments.
    hmcState(phi,
             evolver,
             args.ntrajectories,
             saveFreq=args.save_freq,
             checkpointFreq=args.checkpoint_freq)
Ejemplo n.º 4
0
    def __call__(self, phi, action, itr):
        """!Record the single-particle correlators."""

        nt = int(len(phi) / self.hfm.nx())

        # Create a large set of sources:
        rhss = [isle.Vector(spaceToSpacetime(irrep, time, nt))
                for irrep in self.irreps for time in range(nt)]
        # For the j^th spacetime vector of the i^th state, go to self.rhss[i * nt + j]
        # In other words, time is the faster running index.

        # Solve M*x = b for all right-hand sides:
        if self._alpha == 1:
            res = np.array(isle.solveM(self.hfm, phi, self.species, rhss), copy=False)
        else:
            res = np.linalg.solve(isle.Matrix(self.hfm.M(-1j*phi, self.species)), np.array(rhss).T).T

        propagators = res.reshape([len(self.irreps), nt, nt, len(self.irreps)])
        # The logic for the one-liner goes as:
        # For each source irrep we need to apply a sink for every irrep.
        #     This produces a big cross-correlator.
        # For each source time we need to roll the vector such that the
        #     source lives on timeslice 0.
        # Finally, we need to average over all the source correlators with
        #     the same source irrep but different timeslices.
        self.corr.append(np.mean(
            np.array([
                [
                    [rollTemporally(np.dot(propagators[i, src], np.conj(irrepj)), -src)
                     for src in range(nt)]
                    for i in range(len(self.irreps))]
                for irrepj in self.irreps]),
            axis=2))
Ejemplo n.º 5
0
def tune(rng):
    """
    Thermalize and then tune a leapfrog integrator.
    """

    # Get a logger. Use this instead of print() to output any and all information.
    log = getLogger("HMC")

    # Load the spatial lattice.
    lat = isle.LATTICES[LATTICE]
    # Lattice files usually only contain information on the spatial lattice
    # to be more flexible. Set the number of time slices here.
    lat.nt(NT)

    # Set up a fresh HMC driver.
    # It handles all HMC evolution as well as I/O.
    # Last argument forbids the driver to overwrite any existing data.
    hmcState = isle.drivers.hmc.newRun(lat, PARAMS, rng, makeAction, TUNEFILE,
                                       True)

    # Generate a random initial condition.
    # Note that configurations must be vectors of complex numbers.
    phi = isle.Vector(
        rng.normal(0,
                   PARAMS.tilde("U", lat)**(1 / 2), lat.lattSize()) + 0j)

    # Run thermalization; tuning works best on thermalized configurations.
    log.info("Thermalizing")
    # Pick an evolver which linearly decreases the number of MD steps from 20 to 5.
    # The number of steps (99) must be one less than the number of trajectories below.
    evolver = isle.evolver.LinearStepLeapfrog(hmcState.action, (1, 1), (20, 5),
                                              299, rng)
    # Thermalize configuration for 100 trajectories without saving anything.
    evStage = hmcState(phi, evolver, 300, saveFreq=0, checkpointFreq=0)
    # Reset the internal counter so we start saving configs at index 0.
    hmcState.resetIndex()

    log.info("Tuning")
    # Construct the auto-tuner with default settings, see the documentation of the
    # constructor for a list of all supported parameters.
    # Start with an nstep of 1 which should be sufficiently small to produce an acceptance
    # rate close to zero in this case.
    # This is good as it anchors the fit, starting close to the expected optimum can make
    # the fit fail and slow down tuning.
    evolver = isle.evolver.LeapfrogTuner(hmcState.action,
                                         1,
                                         1,
                                         rng,
                                         TUNEFILE,
                                         targetAccRate=0.7,
                                         targetConfIntProb=0.0001,
                                         runsPerParam=(50, 500),
                                         maxRuns=50)
    # Run evolution with the tuner for an indefinite number of trajectories,
    # LeapfrogTuner is in charge of terminating the run.
    # Checkpointing is not supported by the tuner, so checkpointFreq must be 0.
    hmcState(evStage, evolver, None, saveFreq=1, checkpointFreq=0)
    print(evolver.currentParams())
    print(evolver.tunedParameters())
Ejemplo n.º 6
0
def _randomPhi(n, realOnly):
    "Return a normally distributed random complex vector of n elements."
    real = np.random.normal(RAND_MEAN, RAND_STD, n)
    if not realOnly:
        imag = np.random.normal(RAND_MEAN, RAND_STD, n)
    else:
        imag = 0
    return isle.Vector(real + 1j * imag)
Ejemplo n.º 7
0
def makeStartPhi(lat, params, starty, rng):
    """
    Generate a single configuration on the real plane.
    """

    sigma = rng.uniform(np.sqrt(params.tilde("U", lat) / (1 + 16 / lat.nt())),
                        np.sqrt(params.tilde("U", lat) / 1.0), 1)[0]

    return isle.Vector(
        np.random.normal(0, sigma, lat.lattSize()) + 1j * starty), sigma
Ejemplo n.º 8
0
def main():
    # Initialize Isle.
    # This sets up the command line interface, defines a barebones argument parser,
    # and parses and returns parsed arguments.
    # More complex parsers can be automatically defined or passed in manually.
    # See, e.g., `hmcThermalization.py` or `measure.py` examples.
    isle.initialize("default")

    # Get a logger. Use this instead of print() to output any and all information.
    log = getLogger("HMC")

    # Load the spatial lattice.
    # Note: This command loads a lattice that is distributed together with Isle.
    #       In order to load custom lattices from a file, use
    #       either  isle.LATTICES.loadExternal(filename)
    #       or  isle.fileio.yaml.loadLattice(filename)
    lat = isle.LATTICES[LATTICE]
    # Lattice files usually only contain information on the spatial lattice
    # to be more flexible. Set the number of time slices here.
    lat.nt(NT)

    # Set up a random number generator.
    rng = isle.random.NumpyRNG(1075)

    # Set up a fresh HMC driver.
    # It handles all HMC evolution as well as I/O.
    # Last argument forbids the driver to overwrite any existing data.
    hmcState = isle.drivers.hmc.newRun(lat, PARAMS, rng, makeAction,
                                       OUTFILE, False)

    # Generate a random initial condition.
    # Note that configurations must be vectors of complex numbers.
    phi = isle.Vector(rng.normal(0,
                                 PARAMS.tilde("U", lat)**(1/2),
                                 lat.lattSize())
                      +0j)

    # Run thermalization.
    log.info("Thermalizing")
    # Pick an evolver which linearly decreases the number of MD steps from 20 to 5.
    # The number of steps (99) must be one less than the number of trajectories below.
    evolver = isle.evolver.LinearStepLeapfrog(hmcState.action, (1, 1), (20, 5), 99, rng)
    # Thermalize configuration for 100 trajectories without saving anything.
    evStage = hmcState(phi, evolver, 100, saveFreq=0, checkpointFreq=0)
    # Reset the internal counter so we start saving configs at index 0.
    hmcState.resetIndex()

    # Run production.
    log.info("Producing")
    # Pick a new evolver with a constant number of steps to get a reproducible ensemble.
    evolver = isle.evolver.ConstStepLeapfrog(hmcState.action, 1, 5, rng)
    # Produce configurations and save in intervals of 2 trajectories.
    # Place a checkpoint every 10 trajectories.
    hmcState(evStage, evolver, 100, saveFreq=2, checkpointFreq=10)
Ejemplo n.º 9
0
def makePhi(lattice, params):
    # phi = isle.Vector(np.zeros(LATTICE.lattSize()) + .257541462j)
    phi = isle.Vector(
        np.random.normal(0,
                         params.tilde("U", lattice)**(1 /
                                                      2), lattice.lattSize()) +
        0j)

    # phix = np.random.normal(0, params.tilde("U", lattice)**(1/2), lattice.nx())
    # phi = isle.Vector(np.tile(phix, lattice.nt()) + 0j)

    return phi
Ejemplo n.º 10
0
def nt_scaling():
    "Benchmark scaling with Nt."

    with open(str(BENCH_PATH / "../resources/lattices/c60_ipr.yml"),
              "r") as yamlf:
        lat = yaml.safe_load(yamlf)
    nx = lat.nx()

    functions = {
        "dense": (isle.logdet, "fn(Q)", "Q = isle.Matrix(hfm.Q(phi))"),
        "logdetQ": (isle.logdetQ, "fn(hfm, phi)", ""),
        "logdetM":
        (isle.logdetM,
         "fn(hfm, phi, isle.Species.PARTICLE)+fn(hfm, phi, isle.Species.HOLE)",
         ""),
    }
    times = {key: [] for key in functions}

    for nt in NTS:
        print("nt = {}".format(nt))

        # make random auxilliary field and HFM
        phi = isle.Vector(
            np.random.randn(nx * nt) + 1j * np.random.randn(nx * nt))
        hfm = isle.HubbardFermiMatrixDia(lat.hopping() / nt, 0, -1)

        # do the benchmarks
        for name, (function, execStr, setupStr) in functions.items():
            if nt > 12 and name == "dense":  # this is just too slow
                continue

            times[name].append(
                timeit.timeit(execStr,
                              setup=setupStr,
                              globals={
                                  "fn": function,
                                  "hfm": hfm,
                                  "phi": phi,
                                  "isle": isle
                              },
                              number=NREP) / NREP)

    # save benchmark to file
    pickle.dump(
        {
            "xlabel": "Nt",
            "ylabel": "time / s",
            "xvalues": NTS,
            "results": times
        }, open("logdet.ben", "wb"))
Ejemplo n.º 11
0
def RK4(phi, epsilon, action, n, direction):
    if n == 0:
        omega1 = 1. / 6
        omega2 = 1. / 3
        omega3 = 1. / 3
        omega4 = 1. / 6
        beta21 = 0.5
        beta31 = 0.0
        beta32 = 0.5
        beta41 = 0.0
        beta42 = 0.0
        beta43 = 1.0
    elif n == 1:
        omega1 = .125
        omega2 = .375
        omega3 = .375
        omega4 = .125
        beta21 = 1 / 3.
        beta31 = -1. / 3
        beta32 = 1.0
        beta41 = 1.0
        beta42 = -1.0
        beta43 = 1.0

    k1 = -direction * isle.Vector(np.conj(action.force(phi)))
    k2 = -direction * isle.Vector(
        np.conj(action.force(phi + epsilon * beta21 * k1)))
    k3 = -direction * isle.Vector(
        np.conj(action.force(phi + epsilon * (beta31 * k1 + beta32 * k2))))
    k4 = -direction * isle.Vector(
        np.conj(
            action.force(phi + epsilon *
                         (beta41 * k1 + beta42 * k2 + beta43 * k3))))

    return phi + epsilon * (omega1 * k1 + omega2 * k2 + omega3 * k3 +
                            omega4 * k4)
Ejemplo n.º 12
0
    def test_2_eval(self):
        "Test eval function of isle.action.SumAction."

        logger = getLogger(__name__)
        logger.info("Testing SumAction.eval()")
        for rep in range(N_REP):
            sact = isle.action.SumAction(_DummyAction(), isle.action.HubbardGaugeAction(1))
            phi = np.random.normal(RAND_MEAN, RAND_STD, 1000) \
                  + 1j*np.random.normal(RAND_MEAN, RAND_STD, 1000)

            sacteval = sact.eval(isle.Vector(phi))
            manualeval = np.sum(phi) + np.dot(phi, phi)/2

            self.assertAlmostEqual(sacteval, manualeval, places=10,
                                   msg="Failed check of SumAction.eval in repetition {}\n".format(rep)\
                                   + f"with sacteval = {sacteval}, manualeval = {manualeval}")
Ejemplo n.º 13
0
    def _getRHSs(self, nt):
        """!
        Get all right hand side vectors as a matrix.
        For the j^th spacetime vector of the i^th state, go to self.rhss[i * nt + j]
        In other words, time is the faster running index.
        """

        if self._rhss is None or self._rhss.rows() != nt * self.hfm.nx():
            # Create a large set of sources:
            self._rhss = isle.Matrix(
                np.array([
                    isle.Vector(
                        self.rng.normal(0, 1, nt * self.hfm.nx()) + 0j)
                    for _ in range(self.nsamples)
                ]))
        return self._rhss
Ejemplo n.º 14
0
def tuneForEnsemble(latticeYAML, paramsYAML, clArgs):
    """
    Tune the leapfrog integrator for ont ensemble with given lattice and parameters.
    """

    rank = MPI.COMM_WORLD.rank
    log = getLogger(f"{__name__}[{rank}]")

    # Re-construct the actual Objects from strings here in the worker task.
    lattice = yaml.safe_load(latticeYAML)
    params = yaml.safe_load(paramsYAML)

    # A unique output file name for this set or parameters.
    outputFile = "mpiexample" + fnameSuffix(lattice, params)

    # Set up a random number generator.
    rng = isle.random.NumpyRNG(rank + 831)

    # Set up a fresh HMC driver just for this ensemble.
    hmcState = isle.drivers.hmc.newRun(lattice, params, rng, makeAction,
                                       outputFile, clArgs.overwrite)

    # Generate a random initial condition.
    phi = isle.Vector(
        rng.normal(0,
                   params.tilde("U", lattice)**(1 / 2), lattice.lattSize()) +
        0j)

    # Run thermalization.
    log.info("Thermalizing")
    # Pick an evolver which linearly decreases the number of MD steps from 20 to 5.
    # The number of steps (99) must be one less than the number of trajectories below.
    evolver = isle.evolver.LinearStepLeapfrog(hmcState.action, (1, 1), (20, 5),
                                              99, rng)
    # Thermalize configuration for 100 trajectories without saving anything.
    stage = hmcState(phi, evolver, 100, saveFreq=0, checkpointFreq=0)
    # Reset the internal counter so we start saving configs at index 0.
    hmcState.resetIndex()

    log.info("Tuning")
    # Construct the auto-tuner with default settings, see the documentation of the
    # constructor for a list of all supported parameters.
    evolver = isle.evolver.LeapfrogTuner(hmcState.action, 1, 1, rng,
                                         outputFile)
    # Run evolution with the tuner for an indefinite number of trajectories,
    hmcState(stage, evolver, None, saveFreq=1, checkpointFreq=0)
Ejemplo n.º 15
0
    def test_3_force(self):
        "Test force function of isle.action.SumAction."

        logger = getLogger(__name__)
        logger.info("Testing SumAction.force()")
        for rep in range(N_REP):
            sact = isle.action.SumAction(_DummyAction(),
                                         isle.action.HubbardGaugeAction(1))
            phi = np.random.normal(RAND_MEAN, RAND_STD, 1000) \
                  + 1j*np.random.normal(RAND_MEAN, RAND_STD, 1000)

            sactforce = sact.force(isle.Vector(phi))
            manualforce = phi - phi / 1

            self.assertAlmostEqual(np.linalg.norm(sactforce-manualforce), 0., places=10,
                                   msg="Failed check of SumAction.force in repetition {}\n".format(rep)\
                                   + f"with sactforce = {sactforce}, manualforce = {manualforce}")
Ejemplo n.º 16
0
def nx_scaling():
    "Benchmark scaling with Nx."

    lattices = [
        isle.yamlio.loadLattice(fname)
        for fname in (BENCH_PATH / "../resources/lattices").iterdir()
    ]
    lattices = sorted(lattices, key=lambda lat: lat.nx())
    NT = 16

    times = {"logdetM": []}

    nxs = []
    for lat in lattices:
        print(f"lat = {lat.name}")
        nx = lat.nx()
        if nx in nxs:
            continue

        nxs.append(nx)
        lat.nt(NT)

        # make random auxilliary field and HFM
        phi = isle.Vector(
            np.random.randn(nx * NT) + 1j * np.random.randn(nx * NT))
        hfm = isle.HubbardFermiMatrixDia(lat.hopping() / NT, 0, -1)

        times["logdetM"].append(
            timeit.timeit("isle.logdetM(hfm, phi, isle.Species.PARTICLE)",
                          globals={
                              "hfm": hfm,
                              "phi": phi,
                              "isle": isle
                          },
                          number=NREP) / NREP)

    # save benchmark to file
    pickle.dump(
        {
            "xlabel": "Nx",
            "ylabel": "time / s",
            "xvalues": nxs,
            "results": times
        }, open("logdet.ben", "wb"))
Ejemplo n.º 17
0
def _randomPhi(n):
    "Return a normally distributed random complex vector of n elements."
    real = np.random.normal(RAND_MEAN, RAND_STD, n)
    imag = np.random.normal(RAND_MEAN, RAND_STD, n)
    return isle.Vector(real + 1j*imag)
Ejemplo n.º 18
0
def generate(overwrite):
    """
    Generate and store a single dataset.
    """

    log = getLogger(f"{__name__}")

    lattice = isle.LATTICES[LATTICE]
    lattice.nt(NT)
    params = PARAMS
    flowParams = preprocessFlowParams(lattice, params)

    outfname =  initFile(lattice,params,flowParams,overwrite) #DATADIR/formatFname("train", lattice, params, flowParams)

    # The default RNG should not have been seeded...
    rng = isle.random.NumpyRNG(random.randint(0, 10000))

    action = makeAction(lattice, params)

    # Set up a fresh HMC driver.
    # It handles all HMC evolution as well as I/O.
    # Last argument forbids the driver to overwrite any existing data.
    #hmcState = isle.drivers.hmc.newRun(lat, params, rng, makeAction, outfile_fn, overwrite)
    hmcStage = isle.drivers.hmc.HMC(lattice,params,rng,action,outfname,0)

    # Generate a random initial condition.
    # Note that configurations must be vectors of complex numbers.
    phi_unflowed = isle.Vector(rng.normal(0, params.tilde("U", lattice)**(1/2), lattice.lattSize())+0j)

    log.info("Thermalizing")
    # Pick an evolver which linearly decreases the number of MD steps from 20 to 5.
    # The number of steps (99) must be one less than the number of trajectories below.
    evolver = isle.evolver.LinearStepLeapfrog(action, (1, 1), (20, 5), 99, rng)
    phi_unflowed = hmcStage(phi_unflowed,evolver,1000,0,0).phi

    # Run production.
    log.info("Producing")
    # Pick a new evolver with a constant number of steps to get a reproducible ensemble.
    evolver = isle.evolver.ConstStepLeapfrog(action, 1, 5, rng)
    # Produce configurations and save in intervals of 2 trajectories.
    # Place a checkpoint every 10 trajectories.

    flowTime = []

    fields_flowed = np.empty((NSAMPLES, lattice.lattSize()), dtype=complex)
    fields_unflowed = np.empty((NSAMPLES, lattice.lattSize()), dtype=complex)
    actions = np.empty(NSAMPLES, dtype=complex)

    isample = 0
    tries = 0
    while isample < NSAMPLES:
        tries += 1
        # create the next 100 trajectories and return the last as new configuration
        phi_unflowed = hmcStage(phi_unflowed,evolver,100,0,0).phi

        # Solve the flow equation
        phi_flowed, actVal, actualFlowTime = isle.rungeKutta4Flow(phi_unflowed, action,
                                                               flowParams.flowTime,
                                                               flowParams.stepSize,
                                                               imActTolerance=1e-6)
        if actualFlowTime < flowParams.minFlowTime:
            log.info("Failed to generate phi at sample %d, reached flow time: %f",isample, actualFlowTime)
        else:
            # store the fields
            fields_flowed[isample, :] = phi_flowed
            fields_unflowed[isample, :] = phi_unflowed
            actions[isample] = actVal
            flowTime.append(actualFlowTime)
            isample += 1

    # write the data to file
    with h5.File(str(outfname), "a") as h5f:
        h5f["phi_flowed"] = fields_flowed
        h5f["phi_unflowed"] = fields_unflowed
        h5f["action_flowed"] = actions
        grp = h5f.create_group("flow_diagnostics")
        grp["flow_time"] = np.array(flowTime)
Ejemplo n.º 19
0
def _randomPhi(n, real=True, imag=True):
    "Return a normally distributed random complex vector of n elements."
    r = np.random.normal(RAND_MEAN, RAND_STD, n) if real else 0
    i = np.random.normal(RAND_MEAN, RAND_STD, n) if imag else 0
    return isle.Vector(r + 1j*i)
Ejemplo n.º 20
0
 def calcPhiNorm(x):
     phi = isle.Vector(x[0] * np.ones(lattice.lattSize()) + 1j * x[1])
     phi = isle.Vector(np.array(action.force(phi)))
     return phi[0].real * phi[0].real + phi[0].imag * phi[0].imag
Ejemplo n.º 21
0
def generate(overwrite, tangent):
    """
    Generate and store a single dataset.
    """

    log = getLogger(f"{__name__}")

    lattice = isle.LATTICES[LATTICE]
    lattice.nt(Nt)
    params = PARAMS
    flowParams = preprocessFlowParams(lattice, params)

    outfname = initFile(lattice, params, flowParams, overwrite)
    # The default RNG should not have been seeded...
    rng = isle.random.NumpyRNG(random.randint(0, 10000))
    action = makeAction(lattice, params)

    def calcPhiNorm(x):
        phi = isle.Vector(x[0] * np.ones(lattice.lattSize()) + 1j * x[1])
        phi = isle.Vector(np.array(action.force(phi)))
        return phi[0].real * phi[0].real + phi[0].imag * phi[0].imag

    starty = 0.0

    if tangent:
        # First find critical point assuming constant phi
        x0 = np.array([startRePhi, startImPhi])
        res = minimize(calcPhiNorm,
                       x0,
                       method='nelder-mead',
                       options={
                           'xtol': 1e-14,
                           'disp': True
                       })
        print('# Critical phi @ ', res.x)
        phi = isle.Vector(res.x[0] * np.ones(lattice.lattSize()) +
                          1j * res.x[1])
        print('# S = ', action.eval(phi))
        starty = res.x[1]

    flowTime = []
    width = []

    conf_gauss = np.empty((NSAMPLES, lattice.lattSize()), dtype=complex)
    conf_flowed = np.empty((NSAMPLES, lattice.lattSize()), dtype=complex)
    actions = np.empty(NSAMPLES, dtype=complex)
    with isle.cli.trackProgress(NSAMPLES) as pbar:
        isample = 0
        tries = 0
        while isample < NSAMPLES:
            tries += 1
            phi_gauss, sigma = makeStartPhi(lattice, params, starty, rng)
            phi_flowed, actVal, actualFlowTime = isle.rungeKutta4Flow(
                phi_gauss,
                action,
                flowParams.flowTime,
                flowParams.stepSize,
                imActTolerance=1e-6)
            if actualFlowTime < flowParams.minFlowTime:
                log.info(
                    "Failed to generate phi at sample %d, reached flow time: %f",
                    isample, actualFlowTime)
            else:
                conf_gauss[isample, :] = phi_gauss
                conf_flowed[isample, :] = phi_flowed
                actions[isample] = actVal
                flowTime.append(actualFlowTime)
                width.append(sigma)
                isample += 1
                pbar.advance()

            pbar._message = f"Success rate: {isample/tries:.3f}"

    with h5.File(str(outfname), "a") as h5f:
        h5f["phi_flowed"] = conf_flowed
        h5f["phi_gauss"] = conf_gauss
        h5f["action_flowed"] = actions
        grp = h5f.create_group("flow_diagnostics")
        grp["flow_time"] = np.array(flowTime)
        grp["width"] = np.array(width)