jiahuimbzuai/CoQuIR huggingface dataset:
//  [python]
def best_ld_derivative(data, xs, alphas, n_iters=4, njobs=8, variance=None, **kw):
    from pathos.multiprocessing import Pool
    from readdy_learn.analyze.progress import Progress

    assert len(alphas) > 0
    assert n_iters > 0

    kwkopy = dict(kw)
    bestalpha = alphas[0]
    derivs = []
    best = 0

    wuerger = lambda x: (x, ld_derivative(data, xs, **kwkopy, alpha=x))

    for i in range(n_iters):
        prog = Progress(n=len(alphas), label='Find alpha')

        print("current level = {}, looking in [{}, {}]".format(i, np.min(alphas), np.max(alphas)))

        derivs = []
        alphas_unordered = []
        if njobs > 1:
            with Pool(processes=njobs) as p:
                for d in p.imap_unordered(wuerger, alphas, chunksize=1):
                    derivs.append(d[1])
                    alphas_unordered.append(d[0])
                    prog.increase(1)
        else:
            for alpha in alphas:
                d = wuerger(alpha)
                derivs.append(d[1])
                alphas_unordered.append(d[0])
                prog.increase(1)

        errs = []
        for ld in derivs:
            integrated_ld = integrate.cumtrapz(ld, x=xs, initial=0) + data[0]
            if variance is not None:
                var = variance
            else:
                var, ff = estimate_noise_variance(xs, data)
            _mse = mse(integrated_ld, data)
            errs.append(np.abs(var - _mse))
        errs = np.array([errs]).squeeze()
        best = int(np.argmin(errs))
        print("found alpha={} to be best with a difference of {} between mse and "
              "variance".format(alphas_unordered[best], errs[best]))
        prog.finish()

        bestalpha = alphas_unordered[best]
        ix = np.where(alphas == bestalpha)[0]
        assert alphas[ix] == bestalpha
        prevalph = alphas[ix - 1] if ix - 1 >= 0 else alphas[0]
        nextalph = alphas[ix + 1] if ix + 1 < len(alphas) else alphas[-1]
        alphas = np.linspace(prevalph, nextalph, num=len(alphas))

    return bestalpha, derivs[best]
//  [python]
def best_ld_derivative(data, xs, alphas, n_iters=4, njobs=8, variance=None, **kw):
    from pathos.multiprocessing import Pool
    from readdy_learn.analyze.progress import Progress

    assert len(alphas) > 0
    assert n_iters > 0

    kwkopy = dict(kw)
    bestalpha = alphas[0]
    derivs = []
    best = 0

    wuerger = lambda x: (x, ld_derivative(data, xs, **kwkopy, alpha=x))

    for i in range(n_iters):
        prog = Progress(n=len(alphas), label='Find alpha')

        print("current level = {}, looking in [{}, {}]".format(i, np.min(alphas), np.max(alphas)))

        derivs = []
        alphas_unordered = []
        if njobs > 1:
            with Pool(processes=njobs) as p:
                for d in p.imap_unordered(wuerger, alphas, chunksize=1):
                    derivs.append(d[1])
                    alphas_unordered.append(d[0])
                    prog.increase(1)
        else:
            for alpha in alphas:
                d = wuerger(alpha)
                derivs.append(d[1])
                alphas_unordered.append(d[0])
                prog.increase(1)

        errs = []
        for ld in derivs:
            integrated_ld = integrate.cumulative_trapezoid(ld, x=xs, initial=0) + data[0]
            if variance is not None:
                var = variance
            else:
                var, ff = estimate_noise_variance(xs, data)
            _mse = mse(integrated_ld, data)
            errs.append(np.abs(var - _mse))
        errs = np.array([errs]).squeeze()
        best = int(np.argmin(errs))
        print("found alpha={} to be best with a difference of {} between mse and "
              "variance".format(alphas_unordered[best], errs[best]))
        prog.finish()

        bestalpha = alphas_unordered[best]
        ix = np.where(alphas == bestalpha)[0]
        assert alphas[ix] == bestalpha
        prevalph = alphas[ix - 1] if ix - 1 >= 0 else alphas[0]
        nextalph = alphas[ix + 1] if ix + 1 < len(alphas) else alphas[-1]
        alphas = np.linspace(prevalph, nextalph, num=len(alphas))

    return bestalpha, derivs[best]
//  [python]
def best_tv_derivative(data, xs, alphas, n_iters=4, variance=None, x0=None, reuse_deriv=True, **kw):
    from readdy_learn.analyze.progress import Progress

    args = dict(kw)
    if variance is not None:
        var = variance
    else:
        var, ff = estimate_noise_variance(xs, data)

    bestalpha = alphas[0]
    derivs = []
    best = 0
    current_best_tv = None

    prog = Progress(n=len(alphas), label='Find alpha', nstages=n_iters)

    scores = []

    for i in range(n_iters):
        derivs = []
        for alpha in alphas:
            if current_best_tv is not None:
                d = tv_derivative(data, xs, u0=current_best_tv, **args, alpha=alpha)
            else:
                d = tv_derivative(data, xs, **args, alpha=alpha)
            derivs.append(d)
            prog.increase(1, stage=i)
        errs = []
        for ix, tv in enumerate(derivs):
            d = .5 * (tv[1:] + tv[:-1])
            integrated = integrate.cumtrapz(d, x=xs, initial=0) + (x0 if x0 is not None else data[0])
            _mse = mse(integrated, data)
            errs.append(np.abs(var - _mse))
            scores.append([alphas[ix], errs[-1]])
        errs = np.array([errs]).squeeze()
        best = int(np.argmin(errs))
        print("found alpha={} to be best with a difference of {} between mse and "
              "variance".format(alphas[best], errs[best]))
        if reuse_deriv:
            current_best_tv = derivs[best]
        else:
            current_best_tv = None
        bestalpha = alphas[best]
        ix = np.where(alphas == bestalpha)[0][0]
        print("got ix {}".format(ix))
        if ix - 1 >= 0:
            prevalph = alphas[ix - 1]
        else:
            prevalph = alphas[0]
        if ix + 1 < len(alphas):
            nextalph = alphas[ix + 1]
        else:
            nextalph = alphas[-1]
        alphas = np.linspace(prevalph, nextalph, num=len(alphas))
        prog.finish(stage=i)

    d = tv_derivative(data, xs, u0=None, **args, alpha=bestalpha)
    return bestalpha, .5 * (d[1:] + d[:-1]), np.array(scores).squeeze()
//  [python]
def best_tv_derivative(data, xs, alphas, n_iters=4, variance=None, x0=None, reuse_deriv=True, **kw):
    from readdy_learn.analyze.progress import Progress

    args = dict(kw)
    if variance is not None:
        var = variance
    else:
        var, ff = estimate_noise_variance(xs, data)

    bestalpha = alphas[0]
    derivs = []
    best = 0
    current_best_tv = None

    prog = Progress(n=len(alphas), label='Find alpha', nstages=n_iters)

    scores = []

    for i in range(n_iters):
        derivs = []
        for alpha in alphas:
            if current_best_tv is not None:
                d = tv_derivative(data, xs, u0=current_best_tv, **args, alpha=alpha)
            else:
                d = tv_derivative(data, xs, **args, alpha=alpha)
            derivs.append(d)
            prog.increase(1, stage=i)
        errs = []
        for ix, tv in enumerate(derivs):
            d = .5 * (tv[1:] + tv[:-1])
            integrated = integrate.cumulative_trapezoid(d, x=xs, initial=0) + (x0 if x0 is not None else data[0])
            _mse = mse(integrated, data)
            errs.append(np.abs(var - _mse))
            scores.append([alphas[ix], errs[-1]])
        errs = np.array([errs]).squeeze()
        best = int(np.argmin(errs))
        print("found alpha={} to be best with a difference of {} between mse and "
              "variance".format(alphas[best], errs[best]))
        if reuse_deriv:
            current_best_tv = derivs[best]
        else:
            current_best_tv = None
        bestalpha = alphas[best]
        ix = np.where(alphas == bestalpha)[0][0]
        print("got ix {}".format(ix))
        if ix - 1 >= 0:
            prevalph = alphas[ix - 1]
        else:
            prevalph = alphas[0]
        if ix + 1 < len(alphas):
            nextalph = alphas[ix + 1]
        else:
            nextalph = alphas[-1]
        alphas = np.linspace(prevalph, nextalph, num=len(alphas))
        prog.finish(stage=i)

    d = tv_derivative(data, xs, u0=None, **args, alpha=bestalpha)
    return bestalpha, .5 * (d[1:] + d[:-1]), np.array(scores).squeeze()
//  [python]
def set_filling(h,filling=0.5,nk=10,extrae=0.,delta=1e-1):
    """Set the filling of a Hamiltonian"""
    if h.has_eh: # quick workaround
        ef = h.get_fermi4filling(filling,nk=nk) # fermi energy
        h.add_onsite(-ef)
        return
    fill = filling + extrae/h.intra.shape[0] # filling
    n = h.intra.shape[0]
    use_kpm = False
    if n>algebra.maxsize: # use the KPM method
        use_kpm = True
        print("Using KPM in set_filling")
    if use_kpm: # use KPM
        es,ds = h.get_dos(energies=np.linspace(-5.0,5.0,1000),
                use_kpm=True,delta=delta,nk=nk,random=False)
        from scipy.integrate import cumtrapz
        di = cumtrapz(ds,es)
        ei = (es[0:len(es)-1] + es[1:len(es)])/2.
        di /= di[len(di)-1] # normalize
        from scipy.interpolate import interp1d
        f = interp1d(di,ei) # interpolating function
        efermi = f(fill) # get the fermi energy
    else: # dense Hamiltonian, use ED
        es = eigenvalues(h,nk=nk,notime=True)
        efermi = get_fermi_energy(es,fill)
    h.shift_fermi(-efermi)
//  [python]
def set_filling(h,filling=0.5,nk=10,extrae=0.,delta=1e-1):
    """Set the filling of a Hamiltonian"""
    if h.has_eh: # quick workaround
        ef = h.get_fermi4filling(filling,nk=nk) # fermi energy
        h.add_onsite(-ef)
        return
    fill = filling + extrae/h.intra.shape[0] # filling
    n = h.intra.shape[0]
    use_kpm = False
    if n>algebra.maxsize: # use the KPM method
        use_kpm = True
        print("Using KPM in set_filling")
    if use_kpm: # use KPM
        es,ds = h.get_dos(energies=np.linspace(-5.0,5.0,1000),
                use_kpm=True,delta=delta,nk=nk,random=False)
        from scipy.integrate import cumulative_trapezoid
        di = cumulative_trapezoid(ds,es)
        ei = (es[0:len(es)-1] + es[1:len(es)])/2.
        di /= di[len(di)-1] # normalize
        from scipy.interpolate import interp1d
        f = interp1d(di,ei) # interpolating function
        efermi = f(fill) # get the fermi energy
    else: # dense Hamiltonian, use ED
        es = eigenvalues(h,nk=nk,notime=True)
        efermi = get_fermi_energy(es,fill)
    h.shift_fermi(-efermi)
//  [python]
def GridDensity(self, x, px, N):
        """#
        #  PROGRAM: GridDensity(input)
        #
        #	Takes in a PDF or density function, and spits out a bunch of points in
        #       accordance with the PDF
        #
        #  Input:
        #       x  = vector of points. It need *not* be equispaced,
        #       px = vector of same size as x: probability distribution or
        #            density function. It need not be normalized but has to be positive.
        #  	    N  = Number of points >= 3. The end points of "x" are included
        #  	     necessarily,
        #
        #  Output:
        #       z  = Points distributed according to the density
        #       hz = width of the "intervals" - useful to apportion domain to points
        #            if you are doing quadrature with the results, for example.
        #
        #  (c) Sachin Shanbhag, November 11, 2015
        #"""

        npts = 100
        # can potentially change
        xi = np.linspace(min(x), max(x), npts)  # reinterpolate on equi-spaced axis
        fint = interp1d(x, px, "cubic")  # smoothen using cubic splines
        pint = fint(xi)  # interpolation
        ci = cumtrapz(pint, xi, initial=0)
        pint = pint / ci[npts - 1]
        ci = ci / ci[npts - 1]  # normalize ci

        alfa = 1.0 / (N - 1)  # alfa/2 + (N-1)*alfa + alfa/2
        zij = np.zeros(N + 1)  # quadrature interval end marker
        z = np.zeros(N)  # quadrature point

        z[0] = min(x)
        z[N - 1] = max(x)

        #
        # ci(Z_j,j+1) = (j - 0.5) * alfa
        #
        beta = np.arange(0.5, N - 0.5) * alfa
        zij[0] = z[0]
        zij[N] = z[N - 1]
        fint = interp1d(ci, xi, "cubic")
        zij[1:N] = fint(beta)
        h = np.diff(zij)

        #
        # Quadrature points are not the centroids, but rather the center of masses
        # of the quadrature intervals
        #

        beta = np.arange(1, N - 1) * alfa
        z[1 : N - 1] = fint(beta)

        return z, h
//  [python]
def GridDensity(self, x, px, N):
        """#
        #  PROGRAM: GridDensity(input)
        #
        #	Takes in a PDF or density function, and spits out a bunch of points in
        #       accordance with the PDF
        #
        #  Input:
        #       x  = vector of points. It need *not* be equispaced,
        #       px = vector of same size as x: probability distribution or
        #            density function. It need not be normalized but has to be positive.
        #  	    N  = Number of points >= 3. The end points of "x" are included
        #  	     necessarily,
        #
        #  Output:
        #       z  = Points distributed according to the density
        #       hz = width of the "intervals" - useful to apportion domain to points
        #            if you are doing quadrature with the results, for example.
        #
        #  (c) Sachin Shanbhag, November 11, 2015
        #"""

        npts = 100
        # can potentially change
        xi = np.linspace(min(x), max(x), npts)  # reinterpolate on equi-spaced axis
        fint = interp1d(x, px, "cubic")  # smoothen using cubic splines
        pint = fint(xi)  # interpolation
        ci = cumulative_trapezoid(pint, xi, initial=0)
        pint = pint / ci[npts - 1]
        ci = ci / ci[npts - 1]  # normalize ci

        alfa = 1.0 / (N - 1)  # alfa/2 + (N-1)*alfa + alfa/2
        zij = np.zeros(N + 1)  # quadrature interval end marker
        z = np.zeros(N)  # quadrature point

        z[0] = min(x)
        z[N - 1] = max(x)

        #
        # ci(Z_j,j+1) = (j - 0.5) * alfa
        #
        beta = np.arange(0.5, N - 0.5) * alfa
        zij[0] = z[0]
        zij[N] = z[N - 1]
        fint = interp1d(ci, xi, "cubic")
        zij[1:N] = fint(beta)
        h = np.diff(zij)

        #
        # Quadrature points are not the centroids, but rather the center of masses
        # of the quadrature intervals
        #

        beta = np.arange(1, N - 1) * alfa
        z[1 : N - 1] = fint(beta)

        return z, h
//  [python]
def add_imu_to_pose(imu, pre_pose, freq):
    '''
    Calculate pose candidates based on IMU data and Last pose
    input:
        imu     : (t, B, 3)
                    ax,ay,w_yaw -- linear accelaration for x,y; angular velocity for yaw
        pre_pose: (B,3) predicted pose from last step
        freq    : (1) sampling rate of imu data

    Output:
        absolute pose (t,B,3)
    '''
    axy     = imu[:,:,:2] #(t,B,2)
    w_yaw   = imu[:,:,2] #(t,B)
    device = pre_pose.device
    vxy             = it.cumtrapz(axy, dx=1/freq, axis=0, initial=0)
    displacement    = torch.tensor(it.cumtrapz(vxy, dx=1/freq, axis=0, initial=0))[-1,...].to(device) #B,2
    yaw             = torch.tensor(it.cumtrapz(w_yaw, dx=1/freq, axis=0, initial=0))[-1,:,None].to(device) #B,1
    rela_pose       = torch.cat(displacement,yaw, 1)
    abs_pose = pre_pose + rela_pose

    return abs_pose
//  [python]
def add_imu_to_pose(imu, pre_pose, freq):
    '''
    Calculate pose candidates based on IMU data and Last pose
    input:
        imu     : (t, B, 3)
                    ax,ay,w_yaw -- linear accelaration for x,y; angular velocity for yaw
        pre_pose: (B,3) predicted pose from last step
        freq    : (1) sampling rate of imu data

    Output:
        absolute pose (t,B,3)
    '''
    axy     = imu[:,:,:2] #(t,B,2)
    w_yaw   = imu[:,:,2] #(t,B)
    device = pre_pose.device
    vxy             = it.cumulative_trapezoid(axy, dx=1/freq, axis=0, initial=0)
    displacement    = torch.tensor(it.cumulative_trapezoid(vxy, dx=1/freq, axis=0, initial=0))[-1,...].to(device) #B,2
    yaw             = torch.tensor(it.cumulative_trapezoid(w_yaw, dx=1/freq, axis=0, initial=0))[-1,:,None].to(device) #B,1
    rela_pose       = torch.cat((displacement,yaw), 1)
    abs_pose = pre_pose + rela_pose

    return abs_pose
//  [python]
def COT_intp2(f_ins,SampPerRev,x,fs):
    t= np.r_[:len(x)];t=t/fs;
    # Calculate the inst. angle as function of time
    # (in part of revolutions, not radians!)
    Ainst = integrate.cumtrapz(f_ins,t, initial=0)
    # Find every 1/SampPerRev of a cycle in Ainst
    minA = min(Ainst)
    maxA = max(Ainst)
    Fractions = np.r_[np.ceil(minA*SampPerRev)/SampPerRev:maxA:1/SampPerRev]
    # New sampling times
    tt=interpolate.InterpolatedUnivariateSpline(Ainst,t,\
                                                w=None, bbox=[None, None], k=1)
    tt = tt(Fractions)
    # Now upsample the original signal 10 times (to a total
    # of approx 25 times oversampling)
    x = sg.resample(x,10*len(x))
    fs= 10*fs
    # create a time axis for this upsampled signal
    #tx=(0:1/fs:(length(x)-1)/fs);
    tx= np.r_[:len(x)]/fs
    # Interpolate x onto the x-axis in ts instead of tx
    xs=interpolate.InterpolatedUnivariateSpline(tx,x,\
                                                w=None, bbox=[None, None], k=1)
    xs = xs(tt)
    tc=np.r_[:len(xs)]/SampPerRev
    return xs,tc,SampPerRev,tt
//  [python]
def COT_intp2(f_ins,SampPerRev,x,fs):
    t= np.r_[:len(x)];t=t/fs;
    # Calculate the inst. angle as function of time
    # (in part of revolutions, not radians!)
    Ainst = integrate.cumulative_trapezoid(f_ins,t, initial=0)
    # Find every 1/SampPerRev of a cycle in Ainst
    minA = min(Ainst)
    maxA = max(Ainst)
    Fractions = np.r_[np.ceil(minA*SampPerRev)/SampPerRev:maxA:1/SampPerRev]
    # New sampling times
    tt=interpolate.InterpolatedUnivariateSpline(Ainst,t,\
                                                w=None, bbox=[None, None], k=1)
    tt = tt(Fractions)
    # Now upsample the original signal 10 times (to a total
    # of approx 25 times oversampling)
    x = sg.resample(x,10*len(x))
    fs= 10*fs
    # create a time axis for this upsampled signal
    #tx=(0:1/fs:(length(x)-1)/fs);
    tx= np.r_[:len(x)]/fs
    # Interpolate x onto the x-axis in ts instead of tx
    xs=interpolate.InterpolatedUnivariateSpline(tx,x,\
                                                w=None, bbox=[None, None], k=1)
    xs = xs(tt)
    tc=np.r_[:len(xs)]/SampPerRev
    return xs,tc,SampPerRev,tt
//  [python]
def tTacho_fsig(rpm,fs,PPR,isencod):
    # rpm tacho signal
    # fs sampling frequency
    # PPR pulses per revolition, resolution tacho 44 surveillance case
    # isencod ==1 encoder signal or IF profile
    # sm smoothing intervals with 20
    if isencod==1:
        x=rpm
    else: 
        x=np.sin(2*np.pi*PPR*integrate.cumtrapz(rpm)/fs)
    t=np.arange(0,len(x))
    t=t/fs
    # Produce +1 where signal is above trigger level
    # and -1 where signal is below trigger level
    TLevel=0
    xs=np.sign(x-TLevel)
    # Differentiate this to find where xs changes
    # between -1 and +1 and vice versa
    xDiff=np.diff(xs);
    # We need to synchronize xDiff with variable t from the
    # code above, since DIFF shifts one step
    tDiff=t[1:]
    # Now find the time instances of positive slope positions
    # (-2 if negative slope is used)
    tTacho=tDiff[xDiff.T == 2] # xDiff.T return the indexes boolean
    # Count the time between the tacho signals and compute
    # the RPM at these instances
    rpmt=60/PPR/np.diff(tTacho); # Temporary rpm values
    # Use three tacho pulses at the time and assign mean
    # value to the center tacho pulse
    rpmt=0.5*(rpmt[0:-1]+rpmt[1:]);
    tTacho=tTacho[1:-1]; # diff again shifts one sample
    
    wfiltsv = int(2**np.fix(np.log2(.05*fs)))-1
    rpmt= sg.savgol_filter(rpmt,wfiltsv,2)# smoothing filter
    #rpmt= sg.medfilt(rpmt,2**3-1)
    
    rpmt=interpolate.InterpolatedUnivariateSpline\
    (tTacho,rpmt,w=None, bbox=[None, None], k=1)
    
    rpmt = rpmt(t)
    return rpmt,tTacho,xs
//  [python]
def tTacho_fsig(rpm,fs,PPR,isencod):
    # rpm tacho signal
    # fs sampling frequency
    # PPR pulses per revolition, resolution tacho 44 surveillance case
    # isencod ==1 encoder signal or IF profile
    # sm smoothing intervals with 20
    if isencod==1:
        x=rpm
    else: 
        x=np.sin(2*np.pi*PPR*integrate.cumulative_trapezoid(rpm)/fs)
    t=np.arange(0,len(x))
    t=t/fs
    # Produce +1 where signal is above trigger level
    # and -1 where signal is below trigger level
    TLevel=0
    xs=np.sign(x-TLevel)
    # Differentiate this to find where xs changes
    # between -1 and +1 and vice versa
    xDiff=np.diff(xs);
    # We need to synchronize xDiff with variable t from the
    # code above, since DIFF shifts one step
    tDiff=t[1:]
    # Now find the time instances of positive slope positions
    # (-2 if negative slope is used)
    tTacho=tDiff[xDiff.T == 2] # xDiff.T return the indexes boolean
    # Count the time between the tacho signals and compute
    # the RPM at these instances
    rpmt=60/PPR/np.diff(tTacho); # Temporary rpm values
    # Use three tacho pulses at the time and assign mean
    # value to the center tacho pulse
    rpmt=0.5*(rpmt[0:-1]+rpmt[1:]);
    tTacho=tTacho[1:-1]; # diff again shifts one sample
    
    wfiltsv = int(2**np.fix(np.log2(.05*fs)))-1
    rpmt= sg.savgol_filter(rpmt,wfiltsv,2)# smoothing filter
    #rpmt= sg.medfilt(rpmt,2**3-1)
    
    rpmt=interpolate.InterpolatedUnivariateSpline\
    (tTacho,rpmt,w=None, bbox=[None, None], k=1)
    
    rpmt = rpmt(t)
    return rpmt,tTacho,xs
//  [python]
def cd_update():
	"""Add a new data point to the charge/discharge measurement (should be called regularly)."""
	global cd_currentsetpoint, cd_currentcycle, state
	elapsed_time = timeit.default_timer()-cd_starttime
	if cd_currentcycle > cd_parameters['numcycles']: # End of charge/discharge measurements
		cd_stop(interrupted=False)
	else: # Continue charge/discharge measurement process
		read_potential_current() # Read new potential and current
		cd_time_data.add_sample(elapsed_time)
		cd_potential_data.add_sample(potential)
		cd_current_data.add_sample(1e-3*current) # Convert mA to A
		if len(cd_time_data.samples) == 0 and len(cd_time_data.averagebuffer) > 0: # A new average was just calculated
			cd_outputfile_raw.write("%e\t%e\t%e\n"%(cd_time_data.averagebuffer[-1],cd_potential_data.averagebuffer[-1],cd_current_data.averagebuffer[-1])) # Write it out
			charge = numpy.abs(scipy.integrate.cumtrapz(cd_current_data.averagebuffer,cd_time_data.averagebuffer,initial=0.)/3600.) # Cumulative charge in Ah
			cd_plot_curves[cd_currentcycle-1].setData(charge,cd_potential_data.averagebuffer) # Update the graph
		if (cd_currentsetpoint > 0 and potential > cd_parameters['ubound']) or (cd_currentsetpoint < 0 and potential < cd_parameters['lbound']): # A potential cut-off has been reached
			if cd_currentsetpoint == cd_parameters['chargecurrent']: # Switch from the discharge phase to the charge phase or vice versa
				cd_currentsetpoint = cd_parameters['dischargecurrent']
			else:
				cd_currentsetpoint = cd_parameters['chargecurrent']
			hardware_manual_control_range_dropdown.setCurrentIndex(current_range_from_current(cd_currentsetpoint)) # Determine the proper current range for the new setpoint
			set_current_range() # Set new current range
			set_output(1, cd_currentsetpoint)  # Set current to setpoint
			cd_plot_curves.append(plot_frame.plot(pen='y')) # Start a new plot curve and append it to the plot area (keeping the old ones as well)
			cd_charges.append(numpy.abs(numpy.trapz(cd_current_data.averagebuffer,cd_time_data.averagebuffer)/3600.)) # Cumulative charge in Ah
			if cd_currentcycle % 2 == 0: # Write out the charge and discharge capacities after both a charge and discharge phase (i.e. after cycle 2, 4, 6...)
				cd_outputfile_capacities.write("%d\t%e\t%e\n"%(cd_currentcycle/2,cd_charges[cd_currentcycle-2],cd_charges[cd_currentcycle-1]))
			for data in [cd_time_data, cd_potential_data, cd_current_data]: # Clear average buffers to prepare them for the next cycle
				data.clear()
			cd_currentcycle += 1 # Next cycle
			cd_current_cycle_entry.setText("%d"%cd_currentcycle)
//  [python]
def cd_update():
	"""Add a new data point to the charge/discharge measurement (should be called regularly)."""
	global cd_currentsetpoint, cd_currentcycle, state
	elapsed_time = timeit.default_timer()-cd_starttime
	if cd_currentcycle > cd_parameters['numcycles']: # End of charge/discharge measurements
		cd_stop(interrupted=False)
	else: # Continue charge/discharge measurement process
		read_potential_current() # Read new potential and current
		cd_time_data.add_sample(elapsed_time)
		cd_potential_data.add_sample(potential)
		cd_current_data.add_sample(1e-3*current) # Convert mA to A
		if len(cd_time_data.samples) == 0 and len(cd_time_data.averagebuffer) > 0: # A new average was just calculated
			cd_outputfile_raw.write("%e\t%e\t%e\n"%(cd_time_data.averagebuffer[-1],cd_potential_data.averagebuffer[-1],cd_current_data.averagebuffer[-1])) # Write it out
			charge = numpy.abs(scipy.integrate.cumulative_trapezoid(cd_current_data.averagebuffer,cd_time_data.averagebuffer,initial=0.)/3600.) # Cumulative charge in Ah
			cd_plot_curves[cd_currentcycle-1].setData(charge,cd_potential_data.averagebuffer) # Update the graph
		if (cd_currentsetpoint > 0 and potential > cd_parameters['ubound']) or (cd_currentsetpoint < 0 and potential < cd_parameters['lbound']): # A potential cut-off has been reached
			if cd_currentsetpoint == cd_parameters['chargecurrent']: # Switch from the discharge phase to the charge phase or vice versa
				cd_currentsetpoint = cd_parameters['dischargecurrent']
			else:
				cd_currentsetpoint = cd_parameters['chargecurrent']
			hardware_manual_control_range_dropdown.setCurrentIndex(current_range_from_current(cd_currentsetpoint)) # Determine the proper current range for the new setpoint
			set_current_range() # Set new current range
			set_output(1, cd_currentsetpoint)  # Set current to setpoint
			cd_plot_curves.append(plot_frame.plot(pen='y')) # Start a new plot curve and append it to the plot area (keeping the old ones as well)
			cd_charges.append(numpy.abs(numpy.trapz(cd_current_data.averagebuffer,cd_time_data.averagebuffer)/3600.)) # Cumulative charge in Ah
			if cd_currentcycle % 2 == 0: # Write out the charge and discharge capacities after both a charge and discharge phase (i.e. after cycle 2, 4, 6...)
				cd_outputfile_capacities.write("%d\t%e\t%e\n"%(cd_currentcycle/2,cd_charges[cd_currentcycle-2],cd_charges[cd_currentcycle-1]))
			for data in [cd_time_data, cd_potential_data, cd_current_data]: # Clear average buffers to prepare them for the next cycle
				data.clear()
			cd_currentcycle += 1 # Next cycle
			cd_current_cycle_entry.setText("%d"%cd_currentcycle)
//  [python]
def ana_likelihood(self, rv, leff, fakedata, errors, model, prior,mylikelihood=LogLikelihood, covariance_model_funct=None, otherp=None, nbins=None):
        ll = mylikelihood(xvals=leff, yvals=fakedata, errors=errors, model = model, flatprior=prior,
                                    covariance_model_funct=covariance_model_funct, nbins=nbins)

        like = np.zeros_like(rv)
        for i in range(len(rv)):
            like[i] = np.exp(ll([rv[i]]))
            maxL = rv[like == np.max(like)]
            cumint = scipy.integrate.cumtrapz(like, x=rv)
            cumint = cumint / np.max(cumint)
            onesigma = np.interp(0.68, cumint, rv[1:])
        if otherp:
            other = np.interp(otherp, cumint, rv[1:])
            return like, cumint, onesigma, other, maxL
        else:
            return like, cumint, onesigma, maxL
//  [python]
def ana_likelihood(self, rv, leff, fakedata, errors, model, prior,mylikelihood=LogLikelihood, covariance_model_funct=None, otherp=None, nbins=None):
        ll = mylikelihood(xvals=leff, yvals=fakedata, errors=errors, model = model, flatprior=prior,
                                    covariance_model_funct=covariance_model_funct, nbins=nbins)

        like = np.zeros_like(rv)
        for i in range(len(rv)):
            like[i] = np.exp(ll([rv[i]]))
            maxL = rv[like == np.max(like)]
            cumint = scipy.integrate.cumulative_trapezoid(like, x=rv)
            cumint = cumint / np.max(cumint)
            onesigma = np.interp(0.68, cumint, rv[1:])
        if otherp:
            other = np.interp(otherp, cumint, rv[1:])
            return like, cumint, onesigma, other, maxL
        else:
            return like, cumint, onesigma, maxL
//  [python]
def initialize_from_data_empspect(self, train_x, train_y):
        """
        Initialize mixture components based on the empirical spectrum of the data.

        This will often be better than the standard initialize_from_data method.
        """
        import numpy as np
        from scipy.fftpack import fft
        from scipy.integrate import cumtrapz

        if not torch.is_tensor(train_x) or not torch.is_tensor(train_y):
            raise RuntimeError("train_x and train_y should be tensors")
        if train_x.ndimension() == 1:
            train_x = train_x.unsqueeze(-1)

        N = train_x.size(-2)
        emp_spect = np.abs(fft(train_y.cpu().detach().numpy())) ** 2 / N
        M = math.floor(N / 2)

        freq1 = np.arange(M + 1)
        freq2 = np.arange(-M + 1, 0)
        freq = np.hstack((freq1, freq2)) / N
        freq = freq[: M + 1]
        emp_spect = emp_spect[: M + 1]

        total_area = np.trapz(emp_spect, freq)
        spec_cdf = np.hstack((np.zeros(1), cumtrapz(emp_spect, freq)))
        spec_cdf = spec_cdf / total_area

        a = np.random.rand(1000, self.ard_num_dims)
        p, q = np.histogram(a, spec_cdf)
        bins = np.digitize(a, q)
        slopes = (spec_cdf[bins] - spec_cdf[bins - 1]) / (freq[bins] - freq[bins - 1])
        intercepts = spec_cdf[bins - 1] - slopes * freq[bins - 1]
        inv_spec = (a - intercepts) / slopes

        from sklearn.mixture import GaussianMixture

        GMM = GaussianMixture(n_components=self.num_mixtures, covariance_type="diag").fit(inv_spec)
        means = GMM.means_
        varz = GMM.covariances_
        weights = GMM.weights_

        self.mixture_means = means
        self.mixture_scales = varz
        self.mixture_weights = weights
//  [python]
def initialize_from_data_empspect(self, train_x, train_y):
        """
        Initialize mixture components based on the empirical spectrum of the data.

        This will often be better than the standard initialize_from_data method.
        """
        import numpy as np
        from scipy.fftpack import fft
        from scipy.integrate import cumulative_trapezoid

        if not torch.is_tensor(train_x) or not torch.is_tensor(train_y):
            raise RuntimeError("train_x and train_y should be tensors")
        if train_x.ndimension() == 1:
            train_x = train_x.unsqueeze(-1)

        N = train_x.size(-2)
        emp_spect = np.abs(fft(train_y.cpu().detach().numpy())) ** 2 / N
        M = math.floor(N / 2)

        freq1 = np.arange(M + 1)
        freq2 = np.arange(-M + 1, 0)
        freq = np.hstack((freq1, freq2)) / N
        freq = freq[: M + 1]
        emp_spect = emp_spect[: M + 1]

        total_area = np.trapz(emp_spect, freq)
        spec_cdf = np.hstack((np.zeros(1), cumulative_trapezoid(emp_spect, freq)))
        spec_cdf = spec_cdf / total_area

        a = np.random.rand(1000, self.ard_num_dims)
        p, q = np.histogram(a, spec_cdf)
        bins = np.digitize(a, q)
        slopes = (spec_cdf[bins] - spec_cdf[bins - 1]) / (freq[bins] - freq[bins - 1])
        intercepts = spec_cdf[bins - 1] - slopes * freq[bins - 1]
        inv_spec = (a - intercepts) / slopes

        from sklearn.mixture import GaussianMixture

        GMM = GaussianMixture(n_components=self.num_mixtures, covariance_type="diag").fit(inv_spec)
        means = GMM.means_
        varz = GMM.covariances_
        weights = GMM.weights_

        self.mixture_means = means
        self.mixture_scales = varz
        self.mixture_weights = weights
//  [python]
def run(x,jarr,aarr,rhoarr,sphstokes=-1,atol=1e-8,rtol=1e-6):
    if sphstokes==-1:
        method=0
    else:
        method=3
    radtrans_integrate.init_radtrans_integrate_data(method,4,len(x),len(x),10.,0.1,atol,rtol,1e-2,100000)
    Karr = (np.append(aarr,rhoarr,axis=1))
    tau = np.append(0.,scipy.integrate.cumtrapz(Karr[:,0],x))
    radtrans_integrate.integrate(x[::-1],jarr[:,:],Karr[:,:],tau,4)
    i = radtrans_integrate.intensity.copy()
    radtrans_integrate.del_radtrans_integrate_data()
    return i
//  [python]
def run(x,jarr,aarr,rhoarr,sphstokes=-1,atol=1e-8,rtol=1e-6):
    if sphstokes==-1:
        method=0
    else:
        method=3
    radtrans_integrate.init_radtrans_integrate_data(method,4,len(x),len(x),10.,0.1,atol,rtol,1e-2,100000)
    Karr = (np.append(aarr,rhoarr,axis=1))
    tau = np.append(0.,scipy.integrate.cumulative_trapezoid(Karr[:,0],x))
    radtrans_integrate.integrate(x[::-1],jarr[:,:],Karr[:,:],tau,4)
    i = radtrans_integrate.intensity.copy()
    radtrans_integrate.del_radtrans_integrate_data()
    return i
//  [python]
def test_cumulative_integrate(dask):
    rs = np.random.RandomState(43)
    coord = [0.2, 0.35, 0.4, 0.6, 0.7, 0.75, 0.76, 0.8]

    da = xr.DataArray(
        rs.randn(8, 6),
        dims=["x", "y"],
        coords={
            "x": coord,
            "x2": (("x",), rs.randn(8)),
            "z": 3,
            "x2d": (("x", "y"), rs.randn(8, 6)),
        },
    )
    if dask and has_dask:
        da = da.chunk({"x": 4})

    ds = xr.Dataset({"var": da})

    # along x
    actual = da.cumulative_integrate("x")

    # From scipy-1.6.0 cumtrapz is renamed to cumulative_trapezoid, but cumtrapz is
    # still provided for backward compatibility
    from scipy.integrate import cumtrapz

    expected_x = xr.DataArray(
        cumtrapz(da.compute(), da["x"], axis=0, initial=0.0),
        dims=["x", "y"],
        coords=da.coords,
    )
    assert_allclose(expected_x, actual.compute())
    assert_equal(
        ds["var"].cumulative_integrate("x"),
        ds.cumulative_integrate("x")["var"],
    )

    # make sure result is also a dask array (if the source is dask array)
    assert isinstance(actual.data, type(da.data))

    # along y
    actual = da.cumulative_integrate("y")
    expected_y = xr.DataArray(
        cumtrapz(da, da["y"], axis=1, initial=0.0),
        dims=["x", "y"],
        coords=da.coords,
    )
    assert_allclose(expected_y, actual.compute())
    assert_equal(actual, ds.cumulative_integrate("y")["var"])
    assert_equal(
        ds["var"].cumulative_integrate("y"),
        ds.cumulative_integrate("y")["var"],
    )

    # along x and y
    actual = da.cumulative_integrate(("y", "x"))
    assert actual.ndim == 2

    with pytest.raises(ValueError):
        da.cumulative_integrate("x2d")
//  [python]
def test_cumulative_integrate(dask):
    rs = np.random.RandomState(43)
    coord = [0.2, 0.35, 0.4, 0.6, 0.7, 0.75, 0.76, 0.8]

    da = xr.DataArray(
        rs.randn(8, 6),
        dims=["x", "y"],
        coords={
            "x": coord,
            "x2": (("x",), rs.randn(8)),
            "z": 3,
            "x2d": (("x", "y"), rs.randn(8, 6)),
        },
    )
    if dask and has_dask:
        da = da.chunk({"x": 4})

    ds = xr.Dataset({"var": da})

    # along x
    actual = da.cumulative_integrate("x")

    # From scipy-1.6.0 cumtrapz is renamed to cumulative_trapezoid, but cumtrapz is
    # still provided for backward compatibility
    from scipy.integrate import cumulative_trapezoid

    expected_x = xr.DataArray(
        cumulative_trapezoid(da.compute(), da["x"], axis=0, initial=0.0),
        dims=["x", "y"],
        coords=da.coords,
    )
    assert_allclose(expected_x, actual.compute())
    assert_equal(
        ds["var"].cumulative_integrate("x"),
        ds.cumulative_integrate("x")["var"],
    )

    # make sure result is also a dask array (if the source is dask array)
    assert isinstance(actual.data, type(da.data))

    # along y
    actual = da.cumulative_integrate("y")
    expected_y = xr.DataArray(
        cumulative_trapezoid(da, da["y"], axis=1, initial=0.0),
        dims=["x", "y"],
        coords=da.coords,
    )
    assert_allclose(expected_y, actual.compute())
    assert_equal(actual, ds.cumulative_integrate("y")["var"])
    assert_equal(
        ds["var"].cumulative_integrate("y"),
        ds.cumulative_integrate("y")["var"],
    )

    # along x and y
    actual = da.cumulative_integrate(("y", "x"))
    assert actual.ndim == 2

    with pytest.raises(ValueError):
        da.cumulative_integrate("x2d")
//  [python]
def sample_spiral(self, p):
        # These equations map from the optimization parameter space
        # to the spiral parameter space.   
        p = [0.0, p[0], p[1], 0.0, p[2]]
        a = p[0]
        b = -(11*p[0]/2.0-9*p[1]+9*p[2]/2.0-p[3])/p[4]
        c = (9*p[0]-45*p[1]/2.0+18*p[2]-9*p[3]/2.0)/p[4]**2
        d = -(9*p[0]/2.0-27*p[1]/2.0+27*p[2]/2.0-9*p[3]/2.0)/p[4]**3

        # Compute the theta, x, and y points from the uniformly sampled
        # arc length points s_points (p[4] is the spiral arc length).
        # Use self.thetaf() to compute the theta values from the s values.
        # Recall that x = integral cos(theta(s)) ds and
        #             y = integral sin(theta(s)) ds.
        # You will find the scipy.integrate.cumtrapz() function useful.
        # Try to vectorize the code using numpy functions for speed if you can.
        # TODO YOUR CODE HERE
        s_points = np.linspace(0.0, p[4])
        t_points = self.thetaf(a, b, c, d, s_points)

        fx = np.cos(t_points)
        x_points = scipy.integrate.cumtrapz(fx, s_points)        

        fy = np.sin(t_points)
        y_points = scipy.integrate.cumtrapz(fy, s_points)                

        return [x_points, y_points, t_points]
//  [python]
def sample_spiral(self, p):
        # These equations map from the optimization parameter space
        # to the spiral parameter space.   
        p = [0.0, p[0], p[1], 0.0, p[2]]
        a = p[0]
        b = -(11*p[0]/2.0-9*p[1]+9*p[2]/2.0-p[3])/p[4]
        c = (9*p[0]-45*p[1]/2.0+18*p[2]-9*p[3]/2.0)/p[4]**2
        d = -(9*p[0]/2.0-27*p[1]/2.0+27*p[2]/2.0-9*p[3]/2.0)/p[4]**3

        # Compute the theta, x, and y points from the uniformly sampled
        # arc length points s_points (p[4] is the spiral arc length).
        # Use self.thetaf() to compute the theta values from the s values.
        # Recall that x = integral cos(theta(s)) ds and
        #             y = integral sin(theta(s)) ds.
        # You will find the scipy.integrate.cumtrapz() function useful.
        # Try to vectorize the code using numpy functions for speed if you can.
        # TODO YOUR CODE HERE
        s_points = np.linspace(0.0, p[4])
        t_points = self.thetaf(a, b, c, d, s_points)

        fx = np.cos(t_points)
        x_points = scipy.integrate.cumulative_trapezoid(fx, s_points)        

        fy = np.sin(t_points)
        y_points = scipy.integrate.cumulative_trapezoid(fy, s_points)                

        return [x_points, y_points, t_points]
//  [python]
def _find_m_min(self, ng):
        """
        Calculate the minimum mass of a halo to contain a (central) galaxy
        based on a known mean galaxy density.
        """

        self.power  # This just makes sure the power is gotten and copied
        c = self.clone(hod_params={"M_min": self.Mmin}, dlog10m=0.01)

        integrand = c.m[c._tm] * c.dndm[c._tm] * c.total_occupation[c._tm]

        density_message = (
            f"Maximum mean galaxy density exceeded. User input required density of {ng}, "
            "but maximum density (with HOD M_min == DM Mmin) is {}. "
            "Consider decreasing Mmin,or checking tracer_density."
        )
        if self.hod.sharp_cut:
            integral = intg.cumtrapz(integrand[::-1], dx=np.log(c.m[1] / c.m[0]))

            if integral[-1] < ng:
                raise NGException(density_message.format(integral[-1]))

            ind = np.where(integral > ng)[0][0]

            m = c.m[c._tm][::-1][1:][max(ind - 4, 0) : min(ind + 4, len(c.m))]
            integral = integral[max(ind - 4, 0) : min(ind + 4, len(c.m))]

            spline_int = spline(np.log(integral), np.log(m), k=3)
            mmin = spline_int(np.log(ng)) / np.log(10)
        else:
            # Anything else requires us to do some optimization unfortunately.
            integral = intg.simps(integrand, dx=np.log(c.m[1] / c.m[0]))
            if integral < ng:
                raise NGException(density_message.format(integral))

            def model(mmin):
                c.update(hod_params={"M_min": mmin})
                integrand = c.m[c._tm] * c.dndm[c._tm] * c.total_occupation[c._tm]
                integral = intg.simps(integrand, dx=np.log(c.m[1] / c.m[0]))
                return abs(integral - ng)

            res = minimize(
                model, 12.0, tol=1e-3, method="Nelder-Mead", options={"maxiter": 200}
            )
            mmin = res.x[0]

        return mmin
//  [python]
def _find_m_min(self, ng):
        """
        Calculate the minimum mass of a halo to contain a (central) galaxy
        based on a known mean galaxy density.
        """

        self.power  # This just makes sure the power is gotten and copied
        c = self.clone(hod_params={"M_min": self.Mmin}, dlog10m=0.01)

        integrand = c.m[c._tm] * c.dndm[c._tm] * c.total_occupation[c._tm]

        density_message = (
            f"Maximum mean galaxy density exceeded. User input required density of {ng}, "
            "but maximum density (with HOD M_min == DM Mmin) is {}. "
            "Consider decreasing Mmin,or checking tracer_density."
        )
        if self.hod.sharp_cut:
            integral = intg.cumulative_trapezoid(integrand[::-1], dx=np.log(c.m[1] / c.m[0]))

            if integral[-1] < ng:
                raise NGException(density_message.format(integral[-1]))

            ind = np.where(integral > ng)[0][0]

            m = c.m[c._tm][::-1][1:][max(ind - 4, 0) : min(ind + 4, len(c.m))]
            integral = integral[max(ind - 4, 0) : min(ind + 4, len(c.m))]

            spline_int = spline(np.log(integral), np.log(m), k=3)
            mmin = spline_int(np.log(ng)) / np.log(10)
        else:
            # Anything else requires us to do some optimization unfortunately.
            integral = intg.simps(integrand, dx=np.log(c.m[1] / c.m[0]))
            if integral < ng:
                raise NGException(density_message.format(integral))

            def model(mmin):
                c.update(hod_params={"M_min": mmin})
                integrand = c.m[c._tm] * c.dndm[c._tm] * c.total_occupation[c._tm]
                integral = intg.simps(integrand, dx=np.log(c.m[1] / c.m[0]))
                return abs(integral - ng)

            res = minimize(
                model, 12.0, tol=1e-3, method="Nelder-Mead", options={"maxiter": 200}
            )
            mmin = res.x[0]

        return mmin
//  [python]
def convolute(t, K, D, inirho, endrho, L2):
    """
    Convolution of two first-passage time distributions.

    The first distribution is evaluated from the given parameters and the second
    one is given as an input. This is because this function is intended for
    inding parameters K and D.

    Args:
        t : array_like <br>
            Time coordinate [s].
        K : array_like <br>
            Drift coefficient of first first-passage time distribution [rho/s].
        D : array_like <br>
            Diffusion coefficient of second first-passage time distribution
            [rho^2/s].
        inirho : array_like <br>
            Initial radial coordinate [rho].
        endrho : array_like <br>
            Coordinate for which the first-passage time is evaluated [rho].
        L2 : array_like <br>
            The second first-passage time distribution on t grid.
    """
    L1 = np.zeros(t.shape)
    for ti in np.arange(t.size):
        P1 = firstpassagetime(t[ti]-t, K, D, inirho, endrho)
        L1[ti] = np.trapz(P1*L2, t)

    temp = cumtrapz(L1, t, initial=0)
    return temp / temp[-1]
//  [python]
def convolute(t, K, D, inirho, endrho, L2):
    """
    Convolution of two first-passage time distributions.

    The first distribution is evaluated from the given parameters and the second
    one is given as an input. This is because this function is intended for
    inding parameters K and D.

    Args:
        t : array_like <br>
            Time coordinate [s].
        K : array_like <br>
            Drift coefficient of first first-passage time distribution [rho/s].
        D : array_like <br>
            Diffusion coefficient of second first-passage time distribution
            [rho^2/s].
        inirho : array_like <br>
            Initial radial coordinate [rho].
        endrho : array_like <br>
            Coordinate for which the first-passage time is evaluated [rho].
        L2 : array_like <br>
            The second first-passage time distribution on t grid.
    """
    L1 = np.zeros(t.shape)
    for ti in np.arange(t.size):
        P1 = firstpassagetime(t[ti]-t, K, D, inirho, endrho)
        L1[ti] = np.trapz(P1*L2, t)

    temp = scipy.integrate.cumulative_trapezoid(L1, t, initial=0)
    return temp / temp[-1]
//  [python]
def T(phi_cur, ti, y0, dx):
  """Fixed point iteration in the Picard method.
  See: https://en.wikipedia.org/wiki/Picard%E2%80%93Lindel%C3%B6f_theorem"""
  f_phi = f(ti, phi_cur)
  phi_next = scipy.integrate.cumtrapz(f_phi, initial=y0, dx=dx)
  return phi_next
//  [python]
def T(phi_cur, ti, y0, dx):
  """Fixed point iteration in the Picard method.
  See: https://en.wikipedia.org/wiki/Picard%E2%80%93Lindel%C3%B6f_theorem"""
  f_phi = f(ti, phi_cur)
  phi_next = scipy.integrate.cumulative_trapezoid(f_phi, initial=y0, dx=dx)
  return phi_next
//  [python]
def plot_component(ax: plt.Axes, trajs: TimeTrace,
                   dname: str, fieldname: str, index: int,
                   label=None,
                   do_integrate=False,
                   do_schedule=False,
                   mult=1.0,
                   fix=False):
    """convenience method to plot one axis object
    :param ax: plt.Axes to plot
    :param trajs: csaf simulation output
    :param dname: component name to access
    :param fieldname: name of field to plot
    :param index: index in vector where field is located
    :param label: string containing "plot label (units)"
    :param do_integrate: integrate results (useful for transforming state variable)
    :param do_schedule: use a schedule plot (plot_schedule)
    :param mult: apply a multiplier (simple unit conversion)
    :param fix: center steady state at zero (easier to see features line overshoot, settle time, etc)
    """
    import numpy as np

    # times component
    t = trajs[dname].times
    # variable to plot
    x = np.array(getattr(trajs[dname], fieldname))[:, index]

    if do_schedule:
        plot_schedule(ax, t, x)
    else:
        if do_integrate:
            import scipy.integrate
            x = scipy.integrate.cumtrapz(x, t)
            t = t[:-1]
        if fix:
            x = x - x[-1]
        # pretty plot for zero order hold (ZOH)
        # times of plant
        t_plant = np.array(trajs["plant"].times)
        x_match = t_plant.copy()
        x_match[:] = x[1]
        idx_max = 0
        for idx, ti in enumerate(t):
            if idx < len(t) - 1:
                idxs = np.logical_and(t_plant >= ti, t_plant < t[idx+1])
                x_match[idxs] = x[idx+1]
                barr = np.where(idxs)[0]
                if len(barr) > 0:
                    idx_max = max(barr)
            else:
                x_match[idx_max:] = x[-1]

        # times now match up with t_plant
        t = t_plant
        ax.plot(t_plant, mult*np.array(x_match), label=label.split('(')[0])
        ax.grid(True)

    ax.set_xlim([min(t), max(t)])
    if label and not do_schedule:
        ax.set_ylabel(re.search(r'\((.*?)\)',label).group(1))
    ax.legend()