def calculate(self, calc, formula_reg, data_reg, out_reg,
                  timestep=None, idx=None):
        """
        Calculate looping over specified repeat arguments.

        :param calc: Calculation to loop over.
        :param formula_reg: Formula registry
        :param data_reg: Data registry
        :param out_reg: Outputs registry
        :param timestep: timestep used for dynamic calcs
        :param idx: index used in dynamic calcs
        """
        # the superclass Calculator.calculate() method
        base_calculator = super(LazyLoopingCalculator, self).calculate
        # call base calculator and return if there are no repeat args
        if not self.repeat_args:
            base_calculator(calc, formula_reg, data_reg, out_reg, timestep, idx)
            return
        # make dictionaries of the calculation data and outputs argument maps
        # this maps what the formulas and registries call the repeats arguments
        data_rargs, out_rargs = {}, {}  # allocate dictionaries for repeat args
        calc_data = calc['args'].get('data')
        calc_outs = calc['args'].get('outputs')
        # get dictionaries of repeat args from calculation data and outputs
        for rarg in self.repeat_args:
            # rarg could be either data or output so try both
            try:
                data_rargs[rarg] = calc_data[rarg]
            except (KeyError, TypeError):
                out_rargs[rarg] = calc_outs[rarg]
        # get values of repeat data and outputs from registries
        rargs = dict(index_registry(data_rargs, data_reg, timestep, idx),
                     **index_registry(out_rargs, out_reg, timestep, idx))
        rargkeys, rargvals = zip(*rargs.iteritems())  # split keys and values
        rargvals = zip(*rargvals)  # reshuffle values, should be same size?
        # allocate dictionary of empty numpy arrays for each return value
        returns = calc['returns']  # return keys
        retvals = {rv: [] for rv in returns}  # empty dictionary of return vals
        retvalu = {rv: None for rv in returns}  # dictionary of return units
        ret_var = {rv: {rv: [] for rv in returns}
                   for rv in returns}  # variances
        ret_unc = {rv: {rv: [] for rv in returns}
                   for rv in returns}  # uncertainty
        ret_jac = dict.fromkeys(returns)  # jacobian
        # get calc data and outputs keys to copy from registries
        try:
            calc_data_keys = calc_data.values()
        except (AttributeError, TypeError):
            calc_data_keys = []  # if there are no data, leave it empty
        try:
            calc_outs_keys = calc_outs.values()
        except (AttributeError, TypeError):
            calc_outs_keys = []  # if there are no outputs, leave it empty
        # copy returns and this calculations output arguments from output reg
        data_reg_copy = reg_copy(data_reg, calc_data_keys)
        out_reg_copy = reg_copy(out_reg, returns + calc_outs_keys)
        # loop over first repeat arg values and enumerate numpy indices as n
        for vals in rargvals:
            rargs_keys = dict(zip(rargkeys, vals))
            # this is the magic or garbage depending on how you look at it,
            # change the registry copies to only contain the values for this
            # iteration of the repeats
            # TODO: instead of using copies rewrite index_registry to do this
            # copies means that calculations can't use a registry backend that
            # uses shared memory, which will limit ability to run asynchronously
            for k, v in data_rargs.iteritems():
                data_reg_copy[v] = rargs_keys[k]
            for k, v in out_rargs.iteritems():
                out_reg_copy[v] = rargs_keys[k]
            # run base calculator to get retvals, var, unc and jac
            base_calculator(calc, formula_reg, data_reg_copy, out_reg_copy,
                            timestep, idx)
            # re-assign retvals for this index of repeats
            for rv, rval in retvals.iteritems():
                rval.append(out_reg_copy[rv].m)  # append magnitude to returns
                retvalu[rv] = out_reg_copy[rv].u  # save units for this repeat
                # re-assign variance for this index of repeats
                if out_reg_copy.variance.get(rv) is None:
                    continue
                for rv2, rval2 in ret_var.iteritems():
                    rval2[rv].append(out_reg_copy.variance[rv2][rv])
                    # uncertainty only on diagonal of variance
                    if rv == rv2:
                        ret_unc[rv][rv2].append(out_reg_copy.uncertainty[rv][rv2])
                    else:
                        # FIXME: inefficient to get length every iteration!
                        unc_size = len(out_reg_copy.uncertainty[rv][rv])
                        ret_unc[rv][rv2].append(Q_([0.]*unc_size, 'percent'))
                # jacobian is dictionary of returns versus arguments
                if ret_jac[rv] is None:
                    # first time through create dictionary of sensitivities
                    ret_jac[rv] = {o: v for o, v in
                                   out_reg_copy.jacobian[rv].iteritems()}
                else:
                    # next time through, vstack the sensitivities to existing
                    for o, v in out_reg_copy.jacobian[rv].iteritems():
                        ret_jac[rv][o] = np.vstack((ret_jac[rv][o], v))
        LOGGER.debug('ret_jac:\n%r', ret_jac)
        # TODO: handle jacobian for repeat args and for dynamic simulations
        # apply units if they were
        for k in retvals:
            if retvalu[k] is not None:
                if retvalu[k] == out_reg[k].u:
                    retvals[k] = Q_(retvals[k], retvalu[k])
                else:
                    retvals[k] = Q_(retvals[k], retvalu[k]).to(out_reg[k].u)
        # put return values into output registry
        if idx is None:
            out_reg.update(retvals)
            out_reg.variance.update(ret_var)
            out_reg.uncertainty.update(ret_unc)
            out_reg.jacobian.update(ret_jac)
        else:
            for k, v in retvals:
                out_reg[k][idx] = v
Calculate looping over specified repeat arguments.

        :param calc: Calculation to loop over.
        :param formula_reg: Formula registry
        :param data_reg: Data registry
        :param out_reg: Outputs registry
        :param timestep: timestep used for dynamic calcs
        :param idx: index used in dynamic calcs