def gather_fit_data(fit_count, maxfev): fn_format = "fits.fit_count={fit_count}_maxfev={maxfev}.txt" try: return utils.load_table(fn_format.format(**locals())) except OSError: pass d = utils.filter_preferred_ml(utils.load_all()) d = d[~d["method"].isin(["imsrg[f]+eom[n]"])] results = [] with multiprocessing.Pool(4) as p: results = p.map( functools.partial(gather_fit_data_inner, fit_count=fit_count, maxfev=maxfev), tuple( d.groupby( ["label", "interaction", "num_filled", "freq", "method"]))) d = pd.DataFrame.from_records(itertools.chain(*results)) print("{} fits failed, out of {}".format( (d["fit_method"] == "fixedab").sum(), len(d))) # fit_count=5: # maxfev=default: 198 fits failed, out of 2247 # maxfev=10k: 40 fits failed, out of 2248 # maxfev=100k: 0 fits failed cols = """ interaction label freq num_filled method best_chisq best_coefficient best_coefficient_err best_constant best_constant_err best_fixedab_constant_err best_exponent best_exponent_err best_fit_method best_fit_stop chisq coefficient coefficient_err constant constant_err fixedab_constant_err exponent exponent_err fit_method fit_stop rel_discrep rel_discrep_err rel_dist rel_dist_err """.split() assert len(d.columns) == len(cols) utils.save_table(fn_format.format(**locals()), d[cols]) return d
def plot(label, num_filled, freq, num_shells_range, interaction="normal"): d = utils.load_all() d = utils.filter_preferred_ml(d) d = d[(d["method"] != "imsrg[f]+eom[n]") & (d["method"] != "magnus_quads+eom") & (d["interaction"] == interaction) & (d["label"] == label) & (d["num_filled"] == num_filled) & (d["num_shells"] >= num_shells_range[0]) & (d["num_shells"] <= num_shells_range[1]) & (d["freq"] == 1.0)] num_particles = num_filled * (num_filled + 1) energy_type = {"ground": "ground state", "add": "addition", "rm": "removal"}[label] fig, ax = plt.subplots() fig.set_size_inches((4, 3)) for method, case in d.groupby("method"): case = case.sort_values("num_shells") xs = case["num_shells"].astype(int) ys = case["energy"] ax.plot(xs, ys, "-x", label=utils.METHOD_LABEL[method], color=utils.METHOD_COLOR[method]) ax.get_xaxis().set_major_locator( matplotlib.ticker.MaxNLocator(integer=True)) ax.set_xlabel("K (number of shells)") ax.set_ylabel("E (energy)") ax.legend() fig.tight_layout() utils.savefig(fig, "by-num-shells-{num_particles}-{num_filled}-" "{label}-{ml}-{interaction}" .format(**locals()))
def plot(label, num_filled, freq, num_shells_range, interaction="normal"): d = utils.load_all() d = utils.filter_preferred_ml(d) d = d[(d["method"] != "imsrg[f]+eom[n]") & (d["method"] != "magnus_quads+eom") & (d["interaction"] == interaction) & (d["label"] == label) & (d["num_filled"] == num_filled) & (d["num_shells"] >= num_shells_range[0]) & (d["num_shells"] <= num_shells_range[1]) & (d["freq"] == 1.0)] num_particles = num_filled * (num_filled + 1) energy_type = {"ground": "ground state", "add": "addition", "rm": "removal"}[label] fig, ax = plt.subplots() fig.set_size_inches((4, 3)) for method, case in d.groupby("method"): case = case.sort_values("num_shells") xs = case["num_shells"].astype(int) ys = case["energy"] ax.plot(xs, ys, "-x", label=utils.METHOD_LABEL[method], color=utils.METHOD_COLOR[method]) ax.get_xaxis().set_major_locator( matplotlib.ticker.MaxNLocator(integer=True))
def gather_fit_data(fit_count, maxfev): fn_format = "fits.fit_count={fit_count}_maxfev={maxfev}.txt" try: return utils.load_table(fn_format.format(**locals())) except OSError: pass d = utils.filter_preferred_ml(utils.load_all()) d = d[~d["method"].isin(["imsrg[f]+eom[n]"])] results = [] with multiprocessing.Pool(4) as p: results = p.map( functools.partial(gather_fit_data_inner, fit_count=fit_count, maxfev=maxfev), tuple(d.groupby(["label", "interaction", "num_filled", "freq", "method"]))) d = pd.DataFrame.from_records(itertools.chain(*results)) print("{} fits failed, out of {}" .format((d["fit_method"] == "fixedab").sum(), len(d))) # fit_count=5: # maxfev=default: 198 fits failed, out of 2247 # maxfev=10k: 40 fits failed, out of 2248 # maxfev=100k: 0 fits failed cols = """ interaction label freq num_filled method best_chisq best_coefficient best_coefficient_err best_constant best_constant_err best_fixedab_constant_err best_exponent best_exponent_err best_fit_method best_fit_stop chisq coefficient coefficient_err constant constant_err fixedab_constant_err exponent exponent_err fit_method fit_stop rel_discrep rel_discrep_err rel_dist rel_dist_err """.split() assert len(d.columns) == len(cols) utils.save_table(fn_format.format(**locals()), d[cols]) return d
def plot(label, num_filled, freq, num_shells_range): method_blacklist = [ "imsrg[f]+eom[n]", "magnus_quads+eom", "fci", "hf", ] if label != "ground": method_blacklist.append("imsrg") fit_data = fits.load_fit_data(label) d = utils.load_all() d = utils.filter_preferred_ml(d) d = d[~d["method"].isin(method_blacklist) & (d["interaction"] == "normal") & (d["label"] == label) & (d["num_filled"] == num_filled) & (d["num_shells"] >= num_shells_range[0]) & (d["num_shells"] <= num_shells_range[1]) & (d["freq"] == freq)] num_particles = num_filled * (num_filled + 1) energy_type = { "ground": "ground state", "add": "addition", "rm": "removal" }[label] fig, ax = plt.subplots(1, 2) fig.set_size_inches((6.5, 2.3)) base_markersize = 5 xc = np.linspace(num_shells_range[0] - 0.5, num_shells_range[1] + 0.5, 200) for method, case in d.groupby("method"): case = case.sort_values("num_shells") xs = case["num_shells"].astype(int) ys = case["energy"] marker = utils.METHOD_MARKER[method] style = { "marker": marker, "markerfacecolor": "none", "markersize": (utils.MARKERSIZE_CORRECTION.get(marker, 1.0) * base_markersize), "color": utils.METHOD_COLOR[method], "label": utils.METHOD_LABEL[method], } xms = 0.5 * (xs[1:] + xs[:-1]) yps = abs(ys.diff() / xs.diff()) ax[0].plot(xms, yps, linestyle="none", **style) ax[1].plot(xs, ys, linestyle="none", **style) p = fits.get_fit_params(fit_data, np.max(xs), num_particles, freq, method) ax[0].plot( xc, (abs(p["coefficient"] * p["exponent"]) * xc**(p["exponent"] - 1)), **utils.merge_dicts(style, {"marker": ""})) ax[1].plot(xc, p["coefficient"] * xc**p["exponent"] + p["constant"], **utils.merge_dicts(style, {"marker": ""}))
def plot(label, num_filled, freq, num_shells_range, interaction="normal"): d_dmc = utils.load_all_dmc() d_dmc = d_dmc[(d_dmc["interaction"] == interaction) & (d_dmc["label"] == label) & (d_dmc["num_filled"] == num_filled) & (d_dmc["freq"] == freq)] d_dmc = d_dmc.set_index(["num_particles", "freq"]) d = utils.load_all() d = utils.filter_preferred_ml(d) d = d[(d["method"] != "imsrg[f]+eom[n]") & (d["method"] != "magnus_quads+eom") & (d["interaction"] == interaction) & (d["label"] == label) & (d["num_filled"] == num_filled) & (d["num_shells"] >= num_shells_range[0]) & (d["num_shells"] <= num_shells_range[1]) & (d["freq"] == freq)] num_particles = num_filled * (num_filled + 1) energy_type = { "ground": "ground state", "add": "addition", "rm": "removal" }[label] fig, ax = plt.subplots() fig.set_size_inches((3.2, 2.7)) base_markersize = 5 for method, case in d.groupby("method"): case = case.sort_values("num_shells") xs = case["num_shells"].astype(int) ys = case["energy"] marker = utils.METHOD_MARKER[method] style = { "marker": marker, "markerfacecolor": "none", "markersize": (utils.MARKERSIZE_CORRECTION.get(marker, 1.0) * base_markersize), "color": utils.METHOD_COLOR[method], "label": utils.METHOD_LABEL[method], } ax.plot(xs, ys, **style)
def load_full_fit_data(fit_count=DEFAULT_FIT_COUNT, maxfev=DEFAULT_MAXFEV): '''Load fit data from file if available. Otherwise calculate the fits.''' fn = "fit_data.fit_count={fit_count}_maxfev={maxfev}.txt".format( **locals()) try: return utils.load_table(fn) except OSError: pass sys.stderr.write("Fit data has not yet been calculated. " "This may take a few minutes...\n") sys.stderr.flush() d = utils.filter_preferred_ml(utils.load_all()) d = d[~d["method"].isin(["imsrg[f]+eom[n]"])] with multiprocessing.Pool(4) as p: results_s, missing_num_shells = zip(*p.map( functools.partial( gather_fit_data, fit_count=fit_count, maxfev=maxfev), tuple( d.groupby([ "label", "interaction", "num_filled", "freq", "method" ])))) results = itertools.chain(*results_s) missing_fn = ("fits_missing_points." "fit_count={fit_count}_maxfev={maxfev}.log".format( **locals())) utils.save_table(missing_fn.format(**locals()), pd.DataFrame.from_records(missing_num_shells)) sys.stderr.write("Missing data points logged to: {}\n".format(missing_fn)) sys.stderr.flush() d = pd.DataFrame.from_records(results) num_failed = (d["fit_method"] == "fixedab").sum() if num_failed: sys.stderr.write("{} out of {} fits failed\n".format( num_failed, len(d))) sys.stderr.flush() utils.save_table(fn, d) return d
def main(label): num_shells_range = { 6: [3.5, 14.5], 12: [4.5, 16.5], 20: [6.5, 16.5], 30: [9.5, 16.5], 42: [11.5, 20.5], 56: [14.5, 20.5], } num_particles_ticks = [6, 30, 56] LEGEND_FACET_IDX = 2 if label == "ground": freq_ticks = [0.28, 1.0] methods = ["mp2", "imsrg", "ccsd", "fci"] fn = "../Manuscript/fig-gs2.pdf" else: freq_ticks = [0.28, 1.0] # 0.28 needed to show DMC results fn = "../Manuscript/fig-{}2.pdf".format(label) methods = ["imsrg+qdpt3", "imsrg+eom", "ccsd+eom"] d = utils.load_all() d_dmc = utils.load_all_dmc() d = utils.filter_preferred_ml(d) del d["ml"] d = d[d["interaction"] == "normal"] del d["interaction"] d = d[d["label"] == label] d_dmc = d_dmc[d_dmc["label"] == label] del d["label"] del d_dmc["label"] del d["num_filled"] d_dmc = d_dmc.set_index(["num_particles", "freq"]) facet_x = { "col": "num_particles", "symbol": "N", "ticks": num_particles_ticks, } facet_y = { "col": "freq", "symbol": "\omega", "ticks": freq_ticks, } facet_to_num_particles_freq = lambda x, y: (x, y) has_dmc = False width = 6.5 height = 3 base_markersize = 5.0 fig = plt.figure(figsize=(width, height)) gs = matplotlib.gridspec.GridSpec(len(facet_y["ticks"]), len(facet_x["ticks"])) for (fct_x, fct_y), d in d.groupby([facet_x["col"], facet_y["col"]]): num_particles, freq = facet_to_num_particles_freq(fct_x, fct_y) try: gi = (facet_x["ticks"].index(fct_x) + facet_y["ticks"].index(fct_y) * len(facet_x["ticks"])) except ValueError: continue if gi == LEGEND_FACET_IDX: continue ax = fig.add_subplot(gs[gi]) try: sel_dmc = d_dmc.loc[(num_particles, freq)] except KeyError: pass else: has_dmc = True ax.axhline(sel_dmc["energy"], color=utils.METHOD_COLOR["dmc"], linestyle=utils.DMC_LINESTYLE) for method, d in d.groupby("method"): if method not in methods: continue d = d[(d["num_shells"] >= num_shells_range[num_particles][0]) & (d["num_shells"] <= num_shells_range[num_particles][1])] d = d.sort_values(["num_shells"]) marker = utils.METHOD_MARKER[method] ax.plot(d["num_shells"], d["energy"], marker=marker, markerfacecolor="none", markersize=(utils.MARKERSIZE_CORRECTION.get(marker, 1.0) * base_markersize), color=utils.METHOD_COLOR[method]) title = ("${} = {}$\n${} = {}$" .format(facet_x["symbol"], fct_x, facet_y["symbol"], fct_y)) ax.text(1.0 - 2.65 / width, 0.6, title, color="#505050", horizontalalignment="left", transform=ax.transAxes, fontsize=12) ax.set_xlim(num_shells_range[num_particles]) fig.text(0.5, 0.05 / height, "$K$ (number of shells)", horizontalalignment="center", verticalalignment="bottom", transform=ax.transAxes) fig.text(0.05 / width, 0.5, "${}$".format(utils.ENERGY_SYMBOL[label]), horizontalalignment="left", verticalalignment="center", transform=ax.transAxes, rotation="vertical") # phantom lines to configure the legend markersize = (utils.MARKERSIZE_CORRECTION.get(marker, 1.0) * base_markersize) lines = [matplotlib.lines.Line2D([], [], marker=utils.METHOD_MARKER[method], markersize=markersize, color=utils.METHOD_COLOR[method], label=utils.METHOD_LABEL[method]) for method in methods] if has_dmc: lines.append(matplotlib.lines.Line2D([], [], linestyle=utils.DMC_LINESTYLE, color=utils.METHOD_COLOR["dmc"], label=utils.METHOD_LABEL["dmc"])) ax = fig.add_subplot(gs[LEGEND_FACET_IDX]) ax.axis("off") ax.legend(handles=lines, loc="center", frameon=False, bbox_to_anchor=(0.5, 0.5 - 0.1 / height)) left_margin = 0.1 right_margin = 0.0 top_margin = 0.0 bottom_margin = 0.1 gs.tight_layout(fig, rect=[left_margin / width, bottom_margin / height, 1.0 - right_margin / width, 1.0 - top_margin / height]) utils.savefig(fig, fn=fn)
def plot(fit_count=5, log=False, maxfev=0, plot_type="scatter", stat="err", hf=False): dorig = utils.filter_preferred_ml(utils.load_all()) d_good = utils.load_table("fits_good.txt") d_good = d_good.groupby( ["interaction", "label", "freq", "num_filled", "method"] ).first() d = gather_fit_data(fit_count=fit_count, maxfev=maxfev) d = d[d["interaction"] == "normal"] # d = d[d["label"] == "add"] # d = d[d["method"] == "imsrg"] # d = d[d["num_filled"] == 5] # d = d[d["freq"] == 0.1] d = d[d["fit_method"] != "fixedab"] doriggrps = dorig.groupby(["interaction", "label", "freq", "num_filled", "method"]) d["rel_constant_err"] = d["constant_err"] / d["constant"] d["rel_best_constant_err"] = d["best_constant_err"] / d["best_constant"] d["label_is_ground"] = d["label"] == "ground" d["good"] = d.apply(lambda r: d_good.loc[ (r["interaction"], r["label"], r["freq"], r["num_filled"], r["method"])]["good"], axis=1) d["rel_chi"] = d["chisq"]**.5 / d["constant"] d["rel_reduced_chi"] = d["rel_chi"] / (fit_count - 3) d["rel_best_chisq"] = d["best_chisq"]**.5 / d["best_constant"] d["rel_best_reduced_chisq"] = d["rel_best_chisq"] / (fit_count - 3) d = d[(d["rel_best_reduced_chisq"] < 1e-6)] d["fixedab_with_hf"] = ( ((d["fit_method"] == "fixedab") == (d["method"].isin(["hf", "hf+qdpt3"]))) | (d["fit_method"] == "full") ) color_col = "method" bin_transform = TRANSFORM_ID bin_transform = TRANSFORM_LOG_ABS if color_col in ["exponent", "rel_dist", "rel_constant_err", "rel_best_constant_err", "rel_best_chisq", "rel_chi", "rel_reduced_chi", "chi_ratio"]: num_bins = 16 d = d.replace([np.inf, -np.inf], np.nan).dropna(subset=[color_col]) binf = bin_transform[0] bininvf = bin_transform[1] color_bins = pd.cut(binf(abs(d[color_col])), num_bins) d["color_bin_start"] = color_bins.map( lambda bin: bininvf(parse_bin(bin)[0])) d["color_bin_stop"] = color_bins.map( lambda bin: bininvf(parse_bin(bin)[1])) color_bin_cols = ["color_bin_start", "color_bin_stop"] else: color_bin_cols = [color_col] max_bins = len(d[color_bin_cols[0]].unique()) fig, ax = plt.subplots() def on_pick_event(event): x = list(event.artist.get_xdata()[event.ind])[0] y = list(event.artist.get_ydata()[event.ind])[0] sel = d[(abs(d["x"] - x) <= 1e-20) & (abs(d["y"] - y) <= 1e-20)] print(sel.transpose().to_csv()) if len(sel) != 1: print('>> not found <<') return sel = sel.iloc[0] grp = doriggrps.get_group((sel["interaction"], sel["label"], sel["freq"], sel["num_filled"], sel["method"])) fig, ax = plt.subplots(2) ax[0].plot(grp["num_shells"], grp["energy"], "x") fit_start = sel["fit_stop"] + 1 - fit_count ax[0].axvspan(fit_start, sel["fit_stop"], color="#cccccc") xs = np.linspace(grp["num_shells"].min(), grp["num_shells"].max()) ax[0].plot(xs, sel["coefficient"] * xs ** sel["exponent"] + sel["constant"]) subgrp = grp[grp["num_shells"].between( fit_start-0.1, sel["fit_stop"]+0.1)] last_constant = sel["constant"] last_constant_err = sel["constant_err"] def random_weight(count): weights = np.zeros(count) for i in range(count): weights[np.random.randint(0, count)] += 1 return weights p0 = [sel["coefficient"], sel["exponent"], sel["constant"]] p = p0 x = subgrp["num_shells"] y = subgrp["energy"] constants = [] constants.append(p[2]) print(f"x = np.array({list(x)})") print(f"y = np.array({list(y)})") ax[1].plot(x, (p[0] * x ** p[1] + p[2] - y), "-x") ax[1].axhline(0.0, linestyle=":") for i in range(10): count = len(x) weights = random_weight(count) + 1e-99 if sum(weights > 0.1) <= 3: # can't fit with this few points continue try: p, cov = scipy.optimize.curve_fit( lambda x, a, b, c: a * x ** b + c, x, y, sigma=1.0 / weights ** 0.5, p0=p0, maxfev=100000) except RuntimeError as e: print(e) continue chisq = np.average((p[0] * x ** p[1] + p[2] - y) ** 2, weights=weights) * len(x) constant = p[2] constant_err = cov[2, 2] ** 0.5 constants.append(p[2]) last_constant = constant last_constant_err = constant_err print("result", np.mean(constants), np.std(constants)) print("rel", np.std(constants) / np.mean(constants)) ax[0].set_ylim([max(ax[0].get_ylim()[0], 0.0), min(ax[0].get_ylim()[1], np.max(y))]) ax[0].plot(xs, p[0] * xs ** p[1] + p[2], ":", color="lime") fig.canvas.mpl_connect("pick_event", on_pick_event) d["quality"] = np.log10(d["constant_err"]/d["chisq"]**0.5) # hf has unique behaviors (what about mp2?) if hf: d = d[d["method"] == "hf"] else: d = d[d["method"] != "hf"] if stat == "err": d = d[d["quality"] > 0] d["y"] = d["rel_discrep"] / d["rel_constant_err"] if stat == "hessian": d["x"] = d["quality"] elif stat == "err": d["x"] = np.log10(d["rel_constant_err"]) else: assert False d["y_err"] = d["rel_discrep_err"] / d["rel_discrep"] * d["y"] d = d[(d["rel_constant_err"] > 0) & (d["rel_constant_err"] < np.inf)] if plot_type == "contour": if hf: hf_suffix = "HF" else: hf_suffix = "non-HF" # ranged = mesh; lim = view if stat == "err": if hf: nx = 20 ny = 20 xrange = (-7, -1) yrange = (-5, 5) xlim = (-6, -2) ylim = (-4, 4) title = ("discrepancy vs fit uncertainty " f"({hf_suffix})") else: nx = 20 ny = 40 xrange = (-7, -1) yrange = (-50, 50) xlim = (-6, -2) ylim = (-40, 40) title = ("discrepancy vs fit uncertainty " f"(filtered: Q > 0, {hf_suffix})") xlabel = r"$\log_{10}\left(\frac{\sigma_c}{c}\right)$" ylabel = r"$\frac{\varepsilon}{\sigma_c}$" elif stat == "hessian": if hf: nx = 20 ny = 40 xrange = (-0.6, 1.5) yrange = (-10, 10) xlim = (-0.4, 1.1) ylim = (-10, 10) else: nx = 20 ny = 40 xrange = (-0.6, 2.1) yrange = (-200, 200) xlim = (-0.4, 1.7) ylim = (-150, 150) title = ("spread of “actual” discrepancy vs quality " f"({hf_suffix})") xlabel = (r"$Q = \log_{10}\left(\frac{\sigma_c}" r"{\sqrt{\mathtt{RSS}}}\right)$") ylabel = r"$\frac{\varepsilon}{\sigma_c}$" else: assert False ax.plot(d["x"], d["y"], "o", markersize=1, picker=3, color="white", markeredgewidth=0) dx = (xrange[1] - xrange[0]) / (nx - 1) h, x, y = np.histogram2d(d["x"], d["y"], bins=(nx, ny - 1), range=((xrange[0] - 0.5 * dx, xrange[1] + 0.5 * dx), yrange)) ch = np.concatenate([np.zeros((nx, 1)), np.cumsum(h, axis=1)], axis=1) z = ch / ch[..., -1, np.newaxis] x, y = np.meshgrid(0.5 * (x[1:] + x[:-1]), y, indexing="ij") levels = np.linspace(-2.0, 2.0, 5) levels = 0.5 + 0.5 * scipy.special.erf(2.0 ** -0.5 * levels) ax.axhline(-1.0, linestyle="--", color="white", linewidth=0.5) ax.axhline(1.0, linestyle="--", color="white", linewidth=0.5) ax.contour(x, y, z, levels=levels, colors="white", alpha=0.3) cs = ax.contourf(x, y, z, levels=np.linspace(0.0, 1.0, 300), # note: translucent cmaps tend to cause artifacts cmap=CMAP_FOLDED_VIRIDIS, linestyle=":") for c in cs.collections: # http://stackoverflow.com/a/32911283 c.set_edgecolor("face") fig.colorbar(cs) ax.set_title(title) ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) ax.set_xlim(xlim) ax.set_ylim(ylim) elif plot_type == "scatter": cmap = utils.CMAP_RAINBOW for i, (bin, g) in enumerate(sorted(d.groupby(color_bin_cols))): color = cmap(float(i) / max_bins) ax.plot(g["x"], g["y"], ".", label=str(bin), color=color, markersize=10, markeredgewidth=0, alpha=0.5, picker=2) ax.legend() fn = f"fit-predictiveness-{plot_type}-{fit_count}-{stat}-{hf}" fig.tight_layout() utils.savefig(fig, fn)
def plot(label, freq, num_filled, fit_start, fit_stop=np.inf, fit_ranges={}, interaction="normal", methods=None, badness_threshold=LOGDERIV_BADNESS_THRESHOLD, plot=True, maxfev=0): '''label: ground, add, or rm. fit_ranges: {method: (start, stop)} Used to adjust the fit_range of a specific method (overrides fit_start and fit_stop).''' d_dmc = utils.load_all_dmc() d = utils.load_all() d = utils.filter_preferred_ml(d) d = d[~d["method"].isin(["imsrg[f]+eom[n]"])] # filters d = d[d["interaction"] == interaction] d = d[d["num_filled"] == num_filled] d = d[d["freq"] == freq] d = d[d["label"] == label] if methods is not None: d = d[d["method"].isin(methods)] if label == "ground": e_sym = "E/N" e_text = "energy per particle" d["energy"] /= d["num_particles"] d_dmc["energy"] /= d_dmc["num_particles"] d_dmc["energy_err"] /= d_dmc["num_particles"] else: e_sym = "ε" e_text = "energy" default_fit_range = (fit_start, fit_stop) fit_results = plot_fits( plot=plot, data=d, get_fit_range=lambda method: fit_ranges.get(method, default_fit_range), badness_threshold=badness_threshold, x_col="num_shells", x_label="K (number of shells)", y_col="energy", y_label=f"{e_sym} ({e_text})", absdydx_label=f"|∂{e_sym}/∂K|", title_cols=["label", "num_filled", "num_particles", "freq"], get_title="{label}, N={num_particles}, ω={freq}".format, get_fn="fit-{label}-{num_filled}-{freq}".format, color_cols=["method"], get_color=utils.METHOD_COLOR.get, get_color_label=utils.METHOD_LABEL.get, get_dmc=utils.filter_eq(d_dmc, ["label", "num_filled", "freq"], check_unused_kwargs=False), dmc_label="DMC", dmc_yerr_col="energy_err", maxfev=maxfev, ) results = [] for method, fit_result in sorted(fit_results.items()): results.append({ "interaction": interaction, "label": label, "freq": freq, "num_filled": num_filled, "method": method, "fit_result": fit_result, }) return results
def save_table(path, label, num_shells=NUM_SHELLS, num_particles=[6, 12, 20, 30, 42, 56], freqs=[0.1, 0.28, 1.0]): d = utils.load_all() d = utils.filter_preferred_ml(d) del d["ml"] d = d[d["interaction"] == "normal"] del d["interaction"] d = d[d["label"] == label] del d["label"] del d["num_filled"] d = d.set_index(["num_shells", "num_particles", "freq", "method"]) if label == "ground": methods = ["hf", "mp2", "imsrg", "ccsd"] header = r""" \begin{tabular}{S[table-format=2.0]SS[table-format=2.0]S[table-format=3.5]S[table-format=3.5]S[table-format=3.5]S[table-format=3.5]}% \hline\hline {$N$} & {$\omega$} & {$K$} & {HF} & {MP2} & {IM-SRG(2)} & {CCSD} \\ """[1:] else: methods = ["hf+qdpt3", "imsrg+qdpt3", "imsrg+eom", "ccsd+eom"] header = r""" \begin{tabular}{S[table-format=2.0]SS[table-format=2.0]S[table-format=3.5]S[table-format=3.5]S[table-format=3.5]S[table-format=3.5]}% \hline\hline {$N$} & {$\omega$} & {$K$} & {HF} & {IM-SRG(2)} & {IMSRG(2)} & {CCSD} \\ {} & {} & {} & {+QDPT3} & {+QDPT3} & {+EOM} & {+EOM} \\ """[1:] c = d["energy"] s = [] s.append(header) for num_shells, num_particles in zip(num_shells, num_particles): s.append("\\hline\n") for freq in freqs: row = [num_particles, freq, num_shells] for method in methods: def get(): # to allow early returns key = (num_shells, num_particles, freq, method) if key not in d.index: return None return d.loc[key]["energy"] value = get() if value is None: if ("imsrg" in method and (num_shells, num_particles, freq) in KNOWN_NC_IMSRG): value = "n.c." if ("ccsd" in method and (num_shells, num_particles, freq) in KNOWN_NC_CCSD): value = "n.c." row.append(render_entry(value)) s.append(" & ".join(map(str, row)) + " \\\\\n") s.append("\\hline\\hline\n\\end{tabular}") with open(path, "w") as f: f.write("".join(s)) return d
def plot(fit_count=fits.DEFAULT_FIT_COUNT, log=False, maxfev=fits.DEFAULT_MAXFEV, plot_type="scatter", stat="err", hf=False): dorig = utils.filter_preferred_ml(utils.load_all()) d_good = utils.load_table("fits_good.txt") d_good = d_good.groupby( ["interaction", "label", "freq", "num_filled", "method"] ).first() d = fits.load_predictive_data(fit_count=fit_count, maxfev=maxfev) d = d[d["interaction"] == "normal"] # d = d[d["label"] == "add"] # d = d[d["method"] == "imsrg"] # d = d[d["num_filled"] == 5] # d = d[d["freq"] == 0.1] d = d[d["fit_method"] != "fixedab"] doriggrps = dorig.groupby(["interaction", "label", "freq", "num_filled", "method"]) d["rel_constant_err"] = d["constant_err"] / d["constant"] d["rel_best_constant_err"] = d["best_constant_err"] / d["best_constant"] d["label_is_ground"] = d["label"] == "ground" d["good"] = d.apply(functools.partial(is_good, d_good), axis=1) d["rel_chi"] = d["chisq"]**.5 / d["constant"] d["rel_reduced_chi"] = d["rel_chi"] / (fit_count - 3) d["rel_best_chisq"] = d["best_chisq"]**.5 / d["best_constant"] d["rel_best_reduced_chisq"] = d["rel_best_chisq"] / (fit_count - 3) d = d[(d["rel_best_reduced_chisq"] < 1e-6)] d["fixedab_with_hf"] = ( ((d["fit_method"] == "fixedab") == (d["method"].isin(["hf", "hf+qdpt3"]))) | (d["fit_method"] == "full") ) color_col = "method" bin_transform = TRANSFORM_ID bin_transform = TRANSFORM_LOG_ABS if color_col in ["exponent", "rel_dist", "rel_constant_err", "rel_best_constant_err", "rel_best_chisq", "rel_chi", "rel_reduced_chi", "chi_ratio"]: num_bins = 16 d = d.replace([np.inf, -np.inf], np.nan).dropna(subset=[color_col]) binf = bin_transform[0] bininvf = bin_transform[1] color_bins = pd.cut(binf(abs(d[color_col])), num_bins) d["color_bin_start"] = color_bins.map( lambda bin: bininvf(parse_bin(bin)[0])) d["color_bin_stop"] = color_bins.map( lambda bin: bininvf(parse_bin(bin)[1])) color_bin_cols = ["color_bin_start", "color_bin_stop"] else: color_bin_cols = [color_col] max_bins = len(d[color_bin_cols[0]].unique()) fig, ax = plt.subplots() def on_pick_event(event): x = list(event.artist.get_xdata()[event.ind])[0] y = list(event.artist.get_ydata()[event.ind])[0] sel = d[(abs(d["x"] - x) <= 1e-20) & (abs(d["y"] - y) <= 1e-20)] print(sel.transpose().to_csv()) if len(sel) != 1: print('>> not found <<') return sel = sel.iloc[0] grp = doriggrps.get_group((sel["interaction"], sel["label"], sel["freq"], sel["num_filled"], sel["method"])) fig, ax = plt.subplots(2) ax[0].plot(grp["num_shells"], grp["energy"], "x") fit_start = sel["fit_stop"] + 1 - fit_count ax[0].axvspan(fit_start, sel["fit_stop"], color="#cccccc") xs = np.linspace(grp["num_shells"].min(), grp["num_shells"].max()) ax[0].plot(xs, sel["coefficient"] * xs ** sel["exponent"] + sel["constant"]) subgrp = grp[grp["num_shells"].between( fit_start-0.1, sel["fit_stop"]+0.1)] last_constant = sel["constant"] last_constant_err = sel["constant_err"] def random_weight(count): weights = np.zeros(count) for i in range(count): weights[np.random.randint(0, count)] += 1 return weights p0 = [sel["coefficient"], sel["exponent"], sel["constant"]] p = p0 x = subgrp["num_shells"] y = subgrp["energy"] constants = [] constants.append(p[2]) print(f"x = np.array({list(x)})") print(f"y = np.array({list(y)})") ax[1].plot(x, (p[0] * x ** p[1] + p[2] - y), "-x") ax[1].axhline(0.0, linestyle=":") for i in range(10): count = len(x) weights = random_weight(count) + 1e-99 if sum(weights > 0.1) <= 3: # can't fit with this few points continue try: p, cov = scipy.optimize.curve_fit( lambda x, a, b, c: a * x ** b + c, x, y, sigma=1.0 / weights ** 0.5, p0=p0, maxfev=100000) except RuntimeError as e: print(e) continue chisq = np.average((p[0] * x ** p[1] + p[2] - y) ** 2, weights=weights) * len(x) constant = p[2] constant_err = cov[2, 2] ** 0.5 constants.append(p[2]) last_constant = constant last_constant_err = constant_err print("result", np.mean(constants), np.std(constants)) print("rel", np.std(constants) / np.mean(constants)) ax[0].set_ylim([max(ax[0].get_ylim()[0], 0.0), min(ax[0].get_ylim()[1], np.max(y))]) ax[0].plot(xs, p[0] * xs ** p[1] + p[2], ":", color="lime") fig.canvas.mpl_connect("pick_event", on_pick_event) d["quality"] = np.log10(d["constant_err"]/d["chisq"]**0.5) # hf has unique behaviors (what about mp2?) if hf: d = d[d["method"] == "hf"] else: d = d[d["method"] != "hf"] if stat == "err": d = d[d["quality"] > 0] d["y"] = d["rel_discrep"] / d["rel_constant_err"] if stat == "hessian": d["x"] = d["quality"] elif stat == "err": d["x"] = np.log10(d["rel_constant_err"]) else: assert False d["y_err"] = d["rel_discrep_err"] / d["rel_discrep"] * d["y"] d = d[(d["rel_constant_err"] > 0) & (d["rel_constant_err"] < np.inf)] if plot_type == "contour": if hf: hf_suffix = "HF" else: hf_suffix = "non-HF" # ranged = mesh; lim = view if stat == "err": if hf: nx = 20 ny = 20 xrange = (-7, -1) yrange = (-5, 5) xlim = (-6, -2) ylim = (-4, 4) title = ("discrepancy vs fit uncertainty " f"({hf_suffix})") else: nx = 20 ny = 40 xrange = (-7, -1) yrange = (-50, 50) xlim = (-6, -2) ylim = (-40, 40) title = ("discrepancy vs fit uncertainty " f"(filtered: Q > 0, {hf_suffix})") xlabel = r"$\log_{10}\left(\frac{\sigma_c}{c}\right)$" ylabel = r"$\frac{\varepsilon}{\sigma_c}$" elif stat == "hessian": if hf: nx = 20 ny = 40 xrange = (-0.6, 1.5) yrange = (-10, 10) xlim = (-0.4, 1.1) ylim = (-10, 10) else: nx = 20 ny = 40 xrange = (-0.6, 2.1) yrange = (-200, 200) xlim = (-0.4, 1.7) ylim = (-150, 150) title = ("spread of “actual” discrepancy vs quality " f"({hf_suffix})") xlabel = (r"$Q = \log_{10}\left(\frac{\sigma_c}" r"{\sqrt{\mathtt{RSS}}}\right)$") ylabel = r"$\frac{\varepsilon}{\sigma_c}$" else: assert False ax.plot(d["x"], d["y"], "o", markersize=1, picker=3, color="white", markeredgewidth=0) dx = (xrange[1] - xrange[0]) / (nx - 1) h, x, y = np.histogram2d(d["x"], d["y"], bins=(nx, ny - 1), range=((xrange[0] - 0.5 * dx, xrange[1] + 0.5 * dx), yrange)) ch = np.concatenate([np.zeros((nx, 1)), np.cumsum(h, axis=1)], axis=1) z = ch / ch[..., -1, np.newaxis] x, y = np.meshgrid(0.5 * (x[1:] + x[:-1]), y, indexing="ij") levels = np.linspace(-2.0, 2.0, 5) levels = 0.5 + 0.5 * scipy.special.erf(2.0 ** -0.5 * levels) ax.axhline(-1.0, linestyle="--", color="white", linewidth=0.5) ax.axhline(1.0, linestyle="--", color="white", linewidth=0.5) ax.contour(x, y, z, levels=levels, colors="white", alpha=0.3) cs = ax.contourf(x, y, z, levels=np.linspace(0.0, 1.0, 300), # note: translucent cmaps tend to cause artifacts cmap=CMAP_FOLDED_VIRIDIS, linestyle=":") for c in cs.collections: # http://stackoverflow.com/a/32911283 c.set_edgecolor("face") fig.colorbar(cs) ax.set_title(title) ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) ax.set_xlim(xlim) ax.set_ylim(ylim) elif plot_type == "scatter": cmap = utils.CMAP_RAINBOW for i, (bin, g) in enumerate(sorted(d.groupby(color_bin_cols))): color = cmap(float(i) / max_bins) ax.plot(g["x"], g["y"], ".", label=str(bin), color=color, markersize=10, markeredgewidth=0, alpha=0.5, picker=2) ax.legend() fn = f"fit-predictiveness-{plot_type}-{fit_count}-{stat}-{hf}" fig.tight_layout() utils.savefig(fig, fn)
def plot(label, freq, num_filled, fit_start, fit_stop=np.inf, fit_ranges={}, interaction="normal", methods=None, badness_threshold=LOGDERIV_BADNESS_THRESHOLD, plot=True): '''label: ground, add, or rm. fit_ranges: {method: (start, stop)} Used to adjust the fit_range of a specific method (overrides fit_start and fit_stop).''' d_dmc = utils.load_all_dmc() d = utils.load_all() d = utils.filter_preferred_ml(d) d = d[~d["method"].isin(["imsrg[f]+eom[n]"])] # filters d = d[d["interaction"] == interaction] d = d[d["num_filled"] == num_filled] d = d[d["freq"] == freq] d = d[d["label"] == label] if methods is not None: d = d[d["method"].isin(methods)] if label == "ground": e_sym = "E/N" e_text = "energy per particle" d["energy"] /= d["num_particles"] d_dmc["energy"] /= d_dmc["num_particles"] d_dmc["energy_err"] /= d_dmc["num_particles"] else: e_sym = "ε" e_text = "energy" default_fit_range = (fit_start, fit_stop) fit_results = plot_fits( plot=plot, data=d, get_fit_range=lambda method: fit_ranges.get(method, default_fit_range), badness_threshold=badness_threshold, x_col="num_shells", x_label="K (number of shells)", y_col="energy", y_label=f"{e_sym} ({e_text})", absdydx_label=f"|∂{e_sym}/∂K|", title_cols=["label", "num_filled", "num_particles", "freq"], get_title="{label}, N={num_particles}, ω={freq}".format, get_fn="fit-{label}-{num_filled}-{freq}".format, color_cols=["method"], get_color=utils.METHOD_COLOR.get, get_color_label=utils.METHOD_LABEL.get, get_dmc=utils.filter_eq(d_dmc, ["label", "num_filled", "freq"], check_unused_kwargs=False), dmc_label="DMC", dmc_yerr_col="energy_err", ) results = [] for method, fit_result in sorted(fit_results.items()): results.append({ "interaction": interaction, "label": label, "freq": freq, "num_filled": num_filled, "method": method, "fit_result": fit_result, }) return results