def calibrate_and_model_tensor(uvdata, fg_model_comps_dict, gains=None, freeze_model=False, optimizer='Adamax', tol=1e-14, maxsteps=10000, include_autos=False, verbose=False, sky_model=None, dtype=np.float32, use_min=False, use_redundancy=False, notebook_progressbar=False, correct_resid=False, correct_model=True, weights=None, nsamples_in_weights=True, graph_mode=False, grp_size_threshold=5, n_profile_steps=0, profile_log_dir='./logdir', model_regularization='sum', init_guesses_from_previous_time_step=False, skip_threshold=0.5, use_model_snr_weights=False, **opt_kwargs):
    "Perform simultaneous calibration and foreground fitting using tensors.\n\n\n    Parameters\n    ----------\n    uvdata: UVData object\n        uvdata objet of data to be calibrated.\n    fg_model_comps_dict: dictionary\n        dictionary with keys that are tuples of tuples of 2-tuples (thats right, 3 levels)\n        in the first level, each tuple represents a 'modeling group' visibilities in each\n        modeling group are represented by a set of basis vectors that span all baselines in that\n        group with elements raveled by baseline and then frequency. Each tuple in the modeling group is a\n        'redundant group' representing visibilities that we will represent with identical component coefficients\n        each element of each 'redundant group' is a 2-tuple antenna pair. Our formalism easily accomodates modeling\n        visibilities as redundant or non redundant (one simply needs to make each redundant group length 1).\n        values are real numpy arrays with size (Ngrp * Nfreqs) * Ncomponents\n    gains: UVCal object\n        UVCal with initial gain estimates.\n        There many smart ways to obtain initial gain estimates\n        but this is beyond the scope of calamity (for example, firstcal, logcal, sky-based cal).\n        Users can determine initial gains with their favorite established cal algorithm.\n        default is None -> start with unity gains.\n        WARNING: At the present, the flags in gains are not propagated/used! Make sure flags in uvdata object!\n    freeze_model: bool, optional\n        Only optimize loss function wrt gain variables. This is effectively traditional model-based calibration\n        with sky_model as the model (but projected onto the foreground basis vectors).\n        default is False.\n    optimizer: string\n        Name of optimizer. See OPTIMIZERS dictionary which contains optimizers described in\n        https://www.tensorflow.org/api_docs/python/tf/keras/optimizers\n        default is 'Adamax'\n    tol: float, optional\n        halting condition for optimizer loop. Stop loop when the change in the cost function falls\n        below tol.\n        default is 1e-14\n    maxsteps: int, optional\n        maximum number of opt.minimize calls before halting.\n        default is 10000\n    include_autos: bool, optional\n        include autocorrelations in fitting.\n        default is False.\n    verbose: bool, optional\n        generate lots of text.\n        default is False.\n    sky_model: UVData object, optional\n        a sky-model to use for initial estimates of foreground coeffs and\n        to set overall flux scale and phases.\n        Note that this model is not used to obtain initial gain estimates.\n        These must be provided through the gains argument.\n    dtype: numpy dtype, optional\n        the float precision to be used in tensorflow gradient descent.\n        runtime scales roughly inversely linear with precision.\n        default is np.float32\n    use_min: bool, optional\n        If True, use the set of parameters that determine minimum as the ML params\n        If False, use the last set of parameters visited by the optimization loop.\n    use_redundancy: bool, optional\n        if true, solve for one set of foreground coeffs per redundant baseline group\n        instead of per baseline.\n    notebook_progressbar: bool, optional\n        use progress bar optimized for notebook output.\n        default is False.\n    red_tol: float, optional\n        tolerance for determining baselines redundant (meters)\n        default is 1.0\n    correct_resid: bool, optional\n        if True, gain correct residual.\n        default is False\n    correct_model: bool, optional\n        if True, gain correct model.\n        default is False\n    weights: UVFlag object, optional.\n        UVFlag weights object containing weights to use for data fitting.\n        default is None -> use nsamples * ~flags if nsamples_in_weights\n        or ~flags if not nsamples_in_weights\n    nsamples_in_weights: bool, optional\n        If True and weights is None, generate weights proportional to nsamples.\n        default is True.\n    graph_mode: bool, optional\n        if True, compile gradient update step in graph mode to speed up\n        runtime by ~2-3x. I've found that this helps on CPUs but on GPUs\n        it actually increases runtime by a similar factor.\n    n_profile_steps: bool, optional\n        number of steps to run profiling on\n        default is 0.\n    profile_log_dir: str, optional\n        directory to save profile logs to\n        default is './logdir'\n    model_regularization: str, optional\n        option to regularize model\n        supported 'post_hoc', 'sum'\n        default is 'post_hoc'\n        which sets sum of amps equal and sum of phases equal.\n    init_guesses_from_previous_time_step: bool, optional\n        if True, then use foreground coeffs and gains from previous time-step to\n        initialize gains for next time step.\n    skip_threshold: float, optional\n        if less then this fraction of data is unflagged on a particular poltime,\n        flag the entire poltime.\n    opt_kwargs: kwarg_dict\n        kwargs for tf.optimizers\n\n    Returns\n    -------\n    model: UVData object\n        uvdata object containing model of the foregrounds\n    resid: UVData object\n        uvdata object containing resids which are the data minus\n        the model with gains multiplied and then with the gains divided out.\n    gains: UVCal object\n        uvcal object containing estimates of the gain solutions. These solutions\n        are not referenced to any sky model and are likely orders of\n    fit_history:\n        dictionary containing fit history with fields:\n        'loss_history': list of values of the loss function in each minimization iteration.\n    "
    antpairs_data = uvdata.get_antpairs()
    if (not include_autos):
        antpairs_data = set([ap for ap in antpairs_data if (ap[0] != ap[1])])
    uvdata = uvdata.select(inplace=False, bls=[ap for ap in antpairs_data])
    resid = copy.deepcopy(uvdata)
    model = copy.deepcopy(uvdata)
    model.data_array[:] = 0.0
    model.flag_array[:] = False
    red_grps = []
    for fit_grp in fg_model_comps_dict.keys():
        for red_grp in fit_grp:
            red_grps.append(red_grp)
    if (gains is None):
        echo(f'''{datetime.datetime.now()} Gains are None. Initializing gains starting with unity...
''', verbose=verbose)
        gains = cal_utils.blank_uvcal_from_uvdata(uvdata)
    if ((sky_model is None) and (model_regularization is not None)):
        echo(f'''{datetime.datetime.now()} Sky model is None. Initializing from data...
''', verbose=verbose)
        sky_model = cal_utils.apply_gains(uvdata, gains)
    else:
        sky_model = sky_model.select(inplace=False, bls=[ap for ap in antpairs_data])
    fit_history = {}
    ants_map = {ant: i for (i, ant) in enumerate(gains.ant_array)}
    (fg_model_comps, corr_inds) = tensorize_fg_model_comps_dict(fg_model_comps_dict=fg_model_comps_dict, ants_map=ants_map, dtype=dtype, nfreqs=sky_model.Nfreqs, verbose=verbose, notebook_progressbar=notebook_progressbar, use_redundancy=use_redundancy, grp_size_threshold=grp_size_threshold)
    echo(f'''{datetime.datetime.now()}Finished Converting Foreground Modeling Components to Tensors...
''', verbose=verbose)
    del fg_model_comps_dict
    for (polnum, pol) in enumerate(uvdata.get_pols()):
        echo(f'''{datetime.datetime.now()} Working on pol {pol}, {(polnum + 1)} of {uvdata.Npols}...
''', verbose=verbose)
        fit_history_p = {}
        first_time = True
        for (time_index, time) in enumerate(np.unique(uvdata.time_array)):
            echo(f'''{datetime.datetime.now()} Working on time {(time_index + 1)} of {uvdata.Ntimes}...
''', verbose=verbose)
            bltsel = np.isclose(uvdata.time_array, time, atol=1e-07, rtol=0.0)
            frac_unflagged = (np.count_nonzero((~ uvdata.flag_array[bltsel, 0, :, polnum])) / (uvdata.Nbls * uvdata.Nfreqs))
            if (frac_unflagged >= skip_threshold):
                rmsdata = np.sqrt(np.mean((np.abs(uvdata.data_array[bltsel, 0, :, polnum][(~ uvdata.flag_array[bltsel, 0, :, polnum])]) ** 2.0)))
                echo(f'''{datetime.datetime.now()} Tensorizing data...
''', verbose=verbose)
                (data_r, data_i, wgts) = tensorize_data(uvdata, corr_inds=corr_inds, ants_map=ants_map, polarization=pol, time=time, data_scale_factor=rmsdata, weights=weights, nsamples_in_weights=nsamples_in_weights, dtype=dtype)
                if (sky_model is not None):
                    echo(f'''{datetime.datetime.now()} Tensorizing sky model...
''', verbose=verbose)
                    (sky_model_r, sky_model_i, _) = tensorize_data(sky_model, corr_inds=corr_inds, ants_map=ants_map, polarization=pol, time=time, data_scale_factor=rmsdata, weights=weights, dtype=dtype)
                else:
                    (sky_model_r, sky_model_i) = (None, None)
                if (first_time or (not init_guesses_from_previous_time_step)):
                    first_time = False
                    echo(f'''{datetime.datetime.now()} Tensorizing Gains...
''', verbose=verbose)
                    (g_r, g_i) = tensorize_gains(gains, dtype=dtype, time=time, polarization=pol)
                    echo(f'''{datetime.datetime.now()} Tensorizing Foreground coeffs...
''', verbose=verbose)
                    fg_r = tensorize_fg_coeffs(data=data_r, wgts=wgts, fg_model_comps=fg_model_comps, verbose=verbose, notebook_progressbar=notebook_progressbar)
                    fg_i = tensorize_fg_coeffs(data=data_i, wgts=wgts, fg_model_comps=fg_model_comps, verbose=verbose, notebook_progressbar=notebook_progressbar)
                    if use_model_snr_weights:
                        wgts_model = [fg_model(fgr, fgi, fgc) for (fgr, fgi, fgc) in zip(fg_r, fg_i, fg_model_comps)]
                        wgts = [((tf.square(wm[0]) + tf.square(wm[1])) * w) for (wm, w) in zip(wgts_model, wgts)]
                        del wgts_model
                        wgts_sum = np.sum([np.sum(w) for w in wgts])
                        wgts = [(w / wgts_sum) for w in wgts]
                (g_r, g_i, fg_r, fg_i, fit_history_p[time_index]) = fit_gains_and_foregrounds(g_r=g_r, g_i=g_i, fg_r=fg_r, fg_i=fg_i, data_r=data_r, data_i=data_i, wgts=wgts, fg_comps=fg_model_comps, corr_inds=corr_inds, optimizer=optimizer, use_min=use_min, freeze_model=freeze_model, notebook_progressbar=notebook_progressbar, verbose=verbose, tol=tol, dtype=dtype, maxsteps=maxsteps, graph_mode=graph_mode, n_profile_steps=n_profile_steps, profile_log_dir=profile_log_dir, sky_model_r=sky_model_r, sky_model_i=sky_model_i, model_regularization=model_regularization, **opt_kwargs)
                insert_model_into_uvdata_tensor(uvdata=model, time=time, polarization=pol, ants_map=ants_map, red_grps=red_grps, model_r=yield_fg_model_array(fg_model_comps=fg_model_comps, fg_coeffs=fg_r, corr_inds=corr_inds, nants=uvdata.Nants_data, nfreqs=uvdata.Nfreqs), model_i=yield_fg_model_array(fg_model_comps=fg_model_comps, fg_coeffs=fg_i, corr_inds=corr_inds, nants=uvdata.Nants_data, nfreqs=uvdata.Nfreqs), scale_factor=rmsdata)
                insert_gains_into_uvcal(uvcal=gains, time=time, polarization=pol, gains_re=g_r, gains_im=g_i)
            else:
                echo(f'''{datetime.datetime.now()}: Only {(frac_unflagged * 100)}-percent of data unflagged. Skipping...
''', verbose=verbose)
                flag_poltime(resid, time=time, polarization=pol)
                flag_poltime(gains, time=time, polarization=pol)
                flag_poltime(model, time=time, polarization=pol)
                fit_history[polnum] = 'skipped!'
            if ((not freeze_model) and (model_regularization == 'post_hoc') and np.any((~ model.flag_array[bltsel]))):
                renormalize(uvdata_reference_model=sky_model, uvdata_deconv=model, gains=gains, polarization=pol, time=time, additional_flags=uvdata.flag_array)
        fit_history[polnum] = fit_history_p
    model_with_gains = cal_utils.apply_gains(model, gains, inverse=True)
    if (not correct_model):
        model = model_with_gains
    resid.data_array -= model_with_gains.data_array
    resid.data_array[model_with_gains.flag_array] = 0.0
    resid.data_array[uvdata.flag_array] = 0.0
    if correct_resid:
        resid = cal_utils.apply_gains(resid, gains)
    return (model, resid, gains, fit_history)
Perform simultaneous calibration and foreground fitting using tensors.


Parameters
----------
uvdata: UVData object
    uvdata objet of data to be calibrated.
fg_model_comps_dict: dictionary
    dictionary with keys that are tuples of tuples of 2-tuples (thats right, 3 levels)
    in the first level, each tuple represents a 'modeling group' visibilities in each
    modeling group are represented by a set of basis vectors that span all baselines in that
    group with elements raveled by baseline and then frequency. Each tuple in the modeling group is a
    'redundant group' representing visibilities that we will represent with identical component coefficients
    each element of each 'redundant group' is a 2-tuple antenna pair. Our formalism easily accomodates modeling
    visibilities as redundant or non redundant (one simply needs to make each redundant group length 1).
    values are real numpy arrays with size (Ngrp * Nfreqs) * Ncomponents
gains: UVCal object
    UVCal with initial gain estimates.
    There many smart ways to obtain initial gain estimates
    but this is beyond the scope of calamity (for example, firstcal, logcal, sky-based cal).
    Users can determine initial gains with their favorite established cal algorithm.
    default is None -> start with unity gains.
    WARNING: At the present, the flags in gains are not propagated/used! Make sure flags in uvdata object!
freeze_model: bool, optional
    Only optimize loss function wrt gain variables. This is effectively traditional model-based calibration
    with sky_model as the model (but projected onto the foreground basis vectors).
    default is False.
optimizer: string
    Name of optimizer. See OPTIMIZERS dictionary which contains optimizers described in
    https://www.tensorflow.org/api_docs/python/tf/keras/optimizers
    default is 'Adamax'
tol: float, optional
    halting condition for optimizer loop. Stop loop when the change in the cost function falls
    below tol.
    default is 1e-14
maxsteps: int, optional
    maximum number of opt.minimize calls before halting.
    default is 10000
include_autos: bool, optional
    include autocorrelations in fitting.
    default is False.
verbose: bool, optional
    generate lots of text.
    default is False.
sky_model: UVData object, optional
    a sky-model to use for initial estimates of foreground coeffs and
    to set overall flux scale and phases.
    Note that this model is not used to obtain initial gain estimates.
    These must be provided through the gains argument.
dtype: numpy dtype, optional
    the float precision to be used in tensorflow gradient descent.
    runtime scales roughly inversely linear with precision.
    default is np.float32
use_min: bool, optional
    If True, use the set of parameters that determine minimum as the ML params
    If False, use the last set of parameters visited by the optimization loop.
use_redundancy: bool, optional
    if true, solve for one set of foreground coeffs per redundant baseline group
    instead of per baseline.
notebook_progressbar: bool, optional
    use progress bar optimized for notebook output.
    default is False.
red_tol: float, optional
    tolerance for determining baselines redundant (meters)
    default is 1.0
correct_resid: bool, optional
    if True, gain correct residual.
    default is False
correct_model: bool, optional
    if True, gain correct model.
    default is False
weights: UVFlag object, optional.
    UVFlag weights object containing weights to use for data fitting.
    default is None -> use nsamples * ~flags if nsamples_in_weights
    or ~flags if not nsamples_in_weights
nsamples_in_weights: bool, optional
    If True and weights is None, generate weights proportional to nsamples.
    default is True.
graph_mode: bool, optional
    if True, compile gradient update step in graph mode to speed up
    runtime by ~2-3x. I've found that this helps on CPUs but on GPUs
    it actually increases runtime by a similar factor.
n_profile_steps: bool, optional
    number of steps to run profiling on
    default is 0.
profile_log_dir: str, optional
    directory to save profile logs to
    default is './logdir'
model_regularization: str, optional
    option to regularize model
    supported 'post_hoc', 'sum'
    default is 'post_hoc'
    which sets sum of amps equal and sum of phases equal.
init_guesses_from_previous_time_step: bool, optional
    if True, then use foreground coeffs and gains from previous time-step to
    initialize gains for next time step.
skip_threshold: float, optional
    if less then this fraction of data is unflagged on a particular poltime,
    flag the entire poltime.
opt_kwargs: kwarg_dict
    kwargs for tf.optimizers

Returns
-------
model: UVData object
    uvdata object containing model of the foregrounds
resid: UVData object
    uvdata object containing resids which are the data minus
    the model with gains multiplied and then with the gains divided out.
gains: UVCal object
    uvcal object containing estimates of the gain solutions. These solutions
    are not referenced to any sky model and are likely orders of
fit_history:
    dictionary containing fit history with fields:
    'loss_history': list of values of the loss function in each minimization iteration.
def calibrate_and_model_tensor(uvdata, fg_model_comps_dict, gains=None, freeze_model=False, optimizer='Adamax', tol=1e-14, maxsteps=10000, include_autos=False, verbose=False, sky_model=None, dtype=np.float32, use_min=False, use_redundancy=False, notebook_progressbar=False, correct_resid=False, correct_model=True, weights=None, nsamples_in_weights=True, graph_mode=False, grp_size_threshold=5, n_profile_steps=0, profile_log_dir='./logdir', model_regularization='sum', init_guesses_from_previous_time_step=False, skip_threshold=0.5, use_model_snr_weights=False, **opt_kwargs):
    "Perform simultaneous calibration and foreground fitting using tensors.\n\n\n    Parameters\n    ----------\n    uvdata: UVData object\n        uvdata objet of data to be calibrated.\n    fg_model_comps_dict: dictionary\n        dictionary with keys that are tuples of tuples of 2-tuples (thats right, 3 levels)\n        in the first level, each tuple represents a 'modeling group' visibilities in each\n        modeling group are represented by a set of basis vectors that span all baselines in that\n        group with elements raveled by baseline and then frequency. Each tuple in the modeling group is a\n        'redundant group' representing visibilities that we will represent with identical component coefficients\n        each element of each 'redundant group' is a 2-tuple antenna pair. Our formalism easily accomodates modeling\n        visibilities as redundant or non redundant (one simply needs to make each redundant group length 1).\n        values are real numpy arrays with size (Ngrp * Nfreqs) * Ncomponents\n    gains: UVCal object\n        UVCal with initial gain estimates.\n        There many smart ways to obtain initial gain estimates\n        but this is beyond the scope of calamity (for example, firstcal, logcal, sky-based cal).\n        Users can determine initial gains with their favorite established cal algorithm.\n        default is None -> start with unity gains.\n        WARNING: At the present, the flags in gains are not propagated/used! Make sure flags in uvdata object!\n    freeze_model: bool, optional\n        Only optimize loss function wrt gain variables. This is effectively traditional model-based calibration\n        with sky_model as the model (but projected onto the foreground basis vectors).\n        default is False.\n    optimizer: string\n        Name of optimizer. See OPTIMIZERS dictionary which contains optimizers described in\n        https://www.tensorflow.org/api_docs/python/tf/keras/optimizers\n        default is 'Adamax'\n    tol: float, optional\n        halting condition for optimizer loop. Stop loop when the change in the cost function falls\n        below tol.\n        default is 1e-14\n    maxsteps: int, optional\n        maximum number of opt.minimize calls before halting.\n        default is 10000\n    include_autos: bool, optional\n        include autocorrelations in fitting.\n        default is False.\n    verbose: bool, optional\n        generate lots of text.\n        default is False.\n    sky_model: UVData object, optional\n        a sky-model to use for initial estimates of foreground coeffs and\n        to set overall flux scale and phases.\n        Note that this model is not used to obtain initial gain estimates.\n        These must be provided through the gains argument.\n    dtype: numpy dtype, optional\n        the float precision to be used in tensorflow gradient descent.\n        runtime scales roughly inversely linear with precision.\n        default is np.float32\n    use_min: bool, optional\n        If True, use the set of parameters that determine minimum as the ML params\n        If False, use the last set of parameters visited by the optimization loop.\n    use_redundancy: bool, optional\n        if true, solve for one set of foreground coeffs per redundant baseline group\n        instead of per baseline.\n    notebook_progressbar: bool, optional\n        use progress bar optimized for notebook output.\n        default is False.\n    red_tol: float, optional\n        tolerance for determining baselines redundant (meters)\n        default is 1.0\n    correct_resid: bool, optional\n        if True, gain correct residual.\n        default is False\n    correct_model: bool, optional\n        if True, gain correct model.\n        default is False\n    weights: UVFlag object, optional.\n        UVFlag weights object containing weights to use for data fitting.\n        default is None -> use nsamples * ~flags if nsamples_in_weights\n        or ~flags if not nsamples_in_weights\n    nsamples_in_weights: bool, optional\n        If True and weights is None, generate weights proportional to nsamples.\n        default is True.\n    graph_mode: bool, optional\n        if True, compile gradient update step in graph mode to speed up\n        runtime by ~2-3x. I've found that this helps on CPUs but on GPUs\n        it actually increases runtime by a similar factor.\n    n_profile_steps: bool, optional\n        number of steps to run profiling on\n        default is 0.\n    profile_log_dir: str, optional\n        directory to save profile logs to\n        default is './logdir'\n    model_regularization: str, optional\n        option to regularize model\n        supported 'post_hoc', 'sum'\n        default is 'post_hoc'\n        which sets sum of amps equal and sum of phases equal.\n    init_guesses_from_previous_time_step: bool, optional\n        if True, then use foreground coeffs and gains from previous time-step to\n        initialize gains for next time step.\n    skip_threshold: float, optional\n        if less then this fraction of data is unflagged on a particular poltime,\n        flag the entire poltime.\n    opt_kwargs: kwarg_dict\n        kwargs for tf.optimizers\n\n    Returns\n    -------\n    model: UVData object\n        uvdata object containing model of the foregrounds\n    resid: UVData object\n        uvdata object containing resids which are the data minus\n        the model with gains multiplied and then with the gains divided out.\n    gains: UVCal object\n        uvcal object containing estimates of the gain solutions. These solutions\n        are not referenced to any sky model and are likely orders of\n    fit_history:\n        dictionary containing fit history with fields:\n        'loss_history': list of values of the loss function in each minimization iteration.\n    "
    antpairs_data = uvdata.get_antpairs()
    if (not include_autos):
        antpairs_data = set([ap for ap in antpairs_data if (ap[0] != ap[1])])
    uvdata = uvdata.select(inplace=False, bls=[ap for ap in antpairs_data])
    resid = copy.deepcopy(uvdata)
    model = copy.deepcopy(uvdata)
    model.data_array[:] = 0.0
    model.flag_array[:] = False
    red_grps = []
    for fit_grp in fg_model_comps_dict.keys():
        for red_grp in fit_grp:
            red_grps.append(red_grp)
    if (gains is None):
        echo(f'{datetime.datetime.now()} Gains are None. Initializing gains starting with unity...
', verbose=verbose)
        gains = cal_utils.blank_uvcal_from_uvdata(uvdata)
    if ((sky_model is None) and (model_regularization is not None)):
        echo(f'{datetime.datetime.now()} Sky model is None. Initializing from data...
', verbose=verbose)
        sky_model = cal_utils.apply_gains(uvdata, gains)
    else:
        sky_model = sky_model.select(inplace=False, bls=[ap for ap in antpairs_data])
    fit_history = {}
    ants_map = {ant: i for (i, ant) in enumerate(gains.ant_array)}
    (fg_model_comps, corr_inds) = tensorize_fg_model_comps_dict(fg_model_comps_dict=fg_model_comps_dict, ants_map=ants_map, dtype=dtype, nfreqs=sky_model.Nfreqs, verbose=verbose, notebook_progressbar=notebook_progressbar, use_redundancy=use_redundancy, grp_size_threshold=grp_size_threshold)
    echo(f'{datetime.datetime.now()}Finished Converting Foreground Modeling Components to Tensors...
', verbose=verbose)
    del fg_model_comps_dict
    for (polnum, pol) in enumerate(uvdata.get_pols()):
        echo(f'{datetime.datetime.now()} Working on pol {pol}, {(polnum + 1)} of {uvdata.Npols}...
', verbose=verbose)
        fit_history_p = {}
        first_time = True
        for (time_index, time) in enumerate(np.unique(uvdata.time_array)):
            echo(f'{datetime.datetime.now()} Working on time {(time_index + 1)} of {uvdata.Ntimes}...
', verbose=verbose)
            bltsel = np.isclose(uvdata.time_array, time, atol=1e-07, rtol=0.0)
            frac_unflagged = (np.count_nonzero((~ uvdata.flag_array[bltsel, 0, :, polnum])) / (uvdata.Nbls * uvdata.Nfreqs))
            if (frac_unflagged >= skip_threshold):
                rmsdata = np.sqrt(np.mean((np.abs(uvdata.data_array[bltsel, 0, :, polnum][(~ uvdata.flag_array[bltsel, 0, :, polnum])]) ** 2.0)))
                echo(f'{datetime.datetime.now()} Tensorizing data...
', verbose=verbose)
                (data_r, data_i, wgts) = tensorize_data(uvdata, corr_inds=corr_inds, ants_map=ants_map, polarization=pol, time=time, data_scale_factor=rmsdata, weights=weights, nsamples_in_weights=nsamples_in_weights, dtype=dtype)
                if (sky_model is not None):
                    echo(f'{datetime.datetime.now()} Tensorizing sky model...
', verbose=verbose)
                    (sky_model_r, sky_model_i, _) = tensorize_data(sky_model, corr_inds=corr_inds, ants_map=ants_map, polarization=pol, time=time, data_scale_factor=rmsdata, weights=weights, dtype=dtype)
                else:
                    (sky_model_r, sky_model_i) = (None, None)
                if (first_time or (not init_guesses_from_previous_time_step)):
                    first_time = False
                    echo(f'{datetime.datetime.now()} Tensorizing Gains...
', verbose=verbose)
                    (g_r, g_i) = tensorize_gains(gains, dtype=dtype, time=time, polarization=pol)
                    echo(f'{datetime.datetime.now()} Tensorizing Foreground coeffs...
', verbose=verbose)
                    fg_r = tensorize_fg_coeffs(data=data_r, wgts=wgts, fg_model_comps=fg_model_comps, verbose=verbose, notebook_progressbar=notebook_progressbar)
                    fg_i = tensorize_fg_coeffs(data=data_i, wgts=wgts, fg_model_comps=fg_model_comps, verbose=verbose, notebook_progressbar=notebook_progressbar)
                    if use_model_snr_weights:
                        wgts_model = [fg_model(fgr, fgi, fgc) for (fgr, fgi, fgc) in zip(fg_r, fg_i, fg_model_comps)]
                        wgts = [((tf.square(wm[0]) + tf.square(wm[1])) * w) for (wm, w) in zip(wgts_model, wgts)]
                        del wgts_model
                        wgts_sum = np.sum([np.sum(w) for w in wgts])
                        wgts = [(w / wgts_sum) for w in wgts]
                (g_r, g_i, fg_r, fg_i, fit_history_p[time_index]) = fit_gains_and_foregrounds(g_r=g_r, g_i=g_i, fg_r=fg_r, fg_i=fg_i, data_r=data_r, data_i=data_i, wgts=wgts, fg_comps=fg_model_comps, corr_inds=corr_inds, optimizer=optimizer, use_min=use_min, freeze_model=freeze_model, notebook_progressbar=notebook_progressbar, verbose=verbose, tol=tol, dtype=dtype, maxsteps=maxsteps, graph_mode=graph_mode, n_profile_steps=n_profile_steps, profile_log_dir=profile_log_dir, sky_model_r=sky_model_r, sky_model_i=sky_model_i, model_regularization=model_regularization, **opt_kwargs)
                insert_model_into_uvdata_tensor(uvdata=model, time=time, polarization=pol, ants_map=ants_map, red_grps=red_grps, model_r=yield_fg_model_array(fg_model_comps=fg_model_comps, fg_coeffs=fg_r, corr_inds=corr_inds, nants=uvdata.Nants_data, nfreqs=uvdata.Nfreqs), model_i=yield_fg_model_array(fg_model_comps=fg_model_comps, fg_coeffs=fg_i, corr_inds=corr_inds, nants=uvdata.Nants_data, nfreqs=uvdata.Nfreqs), scale_factor=rmsdata)
                insert_gains_into_uvcal(uvcal=gains, time=time, polarization=pol, gains_re=g_r, gains_im=g_i)
            else:
                echo(f'{datetime.datetime.now()}: Only {(frac_unflagged * 100)}-percent of data unflagged. Skipping...
', verbose=verbose)
                flag_poltime(resid, time=time, polarization=pol)
                flag_poltime(gains, time=time, polarization=pol)
                flag_poltime(model, time=time, polarization=pol)
                fit_history[polnum] = 'skipped!'
            if ((not freeze_model) and (model_regularization == 'post_hoc') and np.any((~ model.flag_array[bltsel]))):
                renormalize(uvdata_reference_model=sky_model, uvdata_deconv=model, gains=gains, polarization=pol, time=time, additional_flags=uvdata.flag_array)
        fit_history[polnum] = fit_history_p
    model_with_gains = cal_utils.apply_gains(model, gains, inverse=True)
    if (not correct_model):
        model = model_with_gains
    resid.data_array -= model_with_gains.data_array
    resid.data_array[model_with_gains.flag_array] = 0.0
    resid.data_array[uvdata.flag_array] = 0.0
    if correct_resid:
        resid = cal_utils.apply_gains(resid, gains)
    return (model, resid, gains, fit_history)