From 247bb33e9b6364eae22266f1048a3c00b1baaf72 Mon Sep 17 00:00:00 2001 From: wilsonm <michael.wilson@ed.ac.uk> Date: Tue, 22 Sep 2020 13:38:35 +0100 Subject: [PATCH] update vp-nextfitruncard to use the API, update the relevant provider to be able to update description and reformate provider plus docstring --- validphys2/src/validphys/eff_exponents.py | 68 +++++++++---- .../validphys/scripts/vp_nextfitruncard.py | 98 +++---------------- 2 files changed, 59 insertions(+), 107 deletions(-) diff --git a/validphys2/src/validphys/eff_exponents.py b/validphys2/src/validphys/eff_exponents.py index 172589f387..937b969c21 100644 --- a/validphys2/src/validphys/eff_exponents.py +++ b/validphys2/src/validphys/eff_exponents.py @@ -400,40 +400,64 @@ fmt = lambda a: float(significant_digits(a, 4)) next_fit_eff_exps_table = collect("next_effective_exponents_table", ("fitpdfandbasis",)) -def next_effective_exponents_yaml(fit: FitSpec, next_fit_eff_exps_table): - """-Returns a table in yaml format called NextEffExps.yaml - -Prints the yaml table in the report - using `effective_exponents_table` this provider outputs the yaml runcard to run - a fit with identical input as the specified `fit` with the t0 and preprocessing iterated. - This action must be used in a report and should be wrapped in a code block to be formatted - correctly, for example: +def next_effective_exponents_yaml( + fit: FitSpec, next_fit_eff_exps_table, _updated_description=None +): + """ + Using `effective_exponents_table` this provider outputs the yaml runcard + used to specify settings of ``fit`` but having iterated the following + sections: + - Modifies the random seeds + - Updates the preprocessing exponents + - Updates the description if ``_updated_description`` is provided + + this should facilitate running a new fit with identical input settings + as the specified ``fit`` with the t0, seeds and preprocessing iterated. + + This action can be used in a report but should be wrapped in a code block + to be formatted correctly, for example: ```yaml {@next_effective_exponents_runcard@} ``` - """ + alternatively, using the API, the yaml dump returned by this function can + be written to a file e.g + + >>> from validphys.api import API + >>> yaml_output = API.next_effective_exponents_yaml( + ... fit=<fit name>, + ... _updated_description="My iterated fit" + ... ) + >>> with open("output.yml", "w+") as f: + ... f.write(yaml_output) + """ df_effexps = next_fit_eff_exps_table[0] # Use round trip loader rather than safe_load in fit.as_input() - with open(fit.path/'filter.yml', 'r') as f: + with open(fit.path / "filter.yml", "r") as f: filtermap = yaml.load(f, yaml.RoundTripLoader) - previous_exponents = filtermap['fitting']['basis'] - basis = filtermap['fitting']['fitbasis'] + previous_exponents = filtermap["fitting"]["basis"] + basis = filtermap["fitting"]["fitbasis"] checked = check_basis(basis, None) - basis = checked['basis'] - flavours = checked['flavours'] + basis = checked["basis"] + flavours = checked["flavours"] runcard_flavours = basis.to_known_elements( - [ref_fl['fl'] for ref_fl in previous_exponents]).tolist() + [ref_fl["fl"] for ref_fl in previous_exponents] + ).tolist() for fl in flavours: - alphas = df_effexps.loc[(f'${fl}$', r'$\alpha$')].values - betas = df_effexps.loc[(f'${fl}$', r'$\beta$')].values - previous_exponents[runcard_flavours.index(fl)]['smallx'] = [fmt(alpha) for alpha in alphas] - previous_exponents[runcard_flavours.index(fl)]['largex'] = [fmt(beta) for beta in betas] - #iterate t0 - filtermap['datacuts']['t0pdfset'] = fit.name + alphas = df_effexps.loc[(f"${fl}$", r"$\alpha$")].values + betas = df_effexps.loc[(f"${fl}$", r"$\beta$")].values + previous_exponents[runcard_flavours.index(fl)]["smallx"] = [ + fmt(alpha) for alpha in alphas + ] + previous_exponents[runcard_flavours.index(fl)]["largex"] = [ + fmt(beta) for beta in betas + ] + # iterate t0 + filtermap["datacuts"]["t0pdfset"] = fit.name # Update seeds with pseudorandom numbers between 0 and 1e10 # Check if seeds exist especially since extra seeds needed in n3fit vs nnfit @@ -450,4 +474,8 @@ def next_effective_exponents_yaml(fit: FitSpec, next_fit_eff_exps_table): if "filterseed" in closuretest_data: closuretest_data["filterseed"] = random.randrange(0, 1e10) + # update description if necessary + if _updated_description is not None: + filtermap["description"] = _updated_description + return yaml.dump(filtermap, Dumper=yaml.RoundTripDumper) diff --git a/validphys2/src/validphys/scripts/vp_nextfitruncard.py b/validphys2/src/validphys/scripts/vp_nextfitruncard.py index 0386067006..ed7f0c1114 100644 --- a/validphys2/src/validphys/scripts/vp_nextfitruncard.py +++ b/validphys2/src/validphys/scripts/vp_nextfitruncard.py @@ -19,19 +19,12 @@ import argparse import os import pathlib import sys -import random import logging import prompt_toolkit -import NNPDF as nnpath - -from reportengine.compat import yaml from reportengine import colors -from reportengine.floatformatting import significant_digits -from validphys.eff_exponents import next_effective_exponents_table -from validphys.loader import Loader, PDFNotFound -from validphys.pdfbases import check_basis +from validphys.api import API # Take command line arguments @@ -97,94 +90,25 @@ def main(): # Check whether runcard with same name already exists in the path if runcard_path_out.exists() and not force: log.error( - f"Destination path {runcard_path_out.absolute()} already exists. If you wish to " - "overwrite it, use the --force option." - ) - sys.exit(1) - - results_path = pathlib.Path(nnpath.get_results_path()) - fit_path = results_path / input_fit - - if not fit_path.is_dir(): - log.error( - "Could not find the specified fit. The following path is not a directory: " - f"{fit_path.absolute()}. If the requested fit does exist, you can download it with " - "`vp-get fit <fit_name>`." + "Destination path %s already exists. If you wish to " + "overwrite it, use the --force option.", + runcard_path_out.absolute(), ) sys.exit(1) - runcard_path_in = fit_path / "filter.yml" - - with open(runcard_path_in, "r") as infile: - runcard_data = yaml.load(infile, Loader=yaml.RoundTripLoader) - log.info(f"Input runcard successfully read from {runcard_path_in.absolute()}.") - - # Update runcard with settings needed for iteration - # Update description of fit interactively - description = runcard_data["description"] + description = API.fit(fit=input_fit).as_input()["description"] + updated_description = interactive_description(description) - runcard_data["description"] = updated_description - - # Iterate t0 - runcard_data["datacuts"]["t0pdfset"] = input_fit - - # Update seeds with pseudorandom numbers between 0 and 1e10 - # Check if seeds exist especially since extra seeds needed in n3fit vs nnfit - # Start with seeds in "fitting" section of runcard - fitting_data = runcard_data["fitting"] - fitting_seeds = ["seed", "trvlseed", "nnseed", "mcseed"] - - for seed in fitting_seeds: - if seed in fitting_data: - fitting_data[seed] = random.randrange(0, 1e10) - - # Next "closuretest" section of runcard - closuretest_data = runcard_data["closuretest"] - if "filterseed" in closuretest_data: - closuretest_data["filterseed"] = random.randrange(0, 1e10) - - # Update preprocessing exponents - # Firstly, find new exponents from PDF set that corresponds to fit - basis = runcard_data["fitting"]["fitbasis"] - checked = check_basis(basis, None) - basis = checked["basis"] - flavours = checked["flavours"] - l = Loader() - try: - pdf = l.check_pdf(input_fit) - except PDFNotFound: - log.error( - f"Could not find the PDF set {input_fit}. If the requested PDF set does exist, you can " - "download it with `vp-get pdf <pdf_name>`." - ) - sys.exit(1) - new_exponents = next_effective_exponents_table( - pdf=pdf, basis=basis, flavours=flavours - ) - # Define function that we will use to round exponents to 4 significant figures - rounder = lambda a: float(significant_digits(a, 4)) - - # Update previous_exponents with new values - previous_exponents = runcard_data["fitting"]["basis"] - runcard_flavours = basis.to_known_elements( - [ref_fl["fl"] for ref_fl in previous_exponents] - ).tolist() - for fl in flavours: - alphas = new_exponents.loc[(f"${fl}$", r"$\alpha$")].values - betas = new_exponents.loc[(f"${fl}$", r"$\beta$")].values - previous_exponents[runcard_flavours.index(fl)]["smallx"] = [ - rounder(alpha) for alpha in alphas - ] - previous_exponents[runcard_flavours.index(fl)]["largex"] = [ - rounder(beta) for beta in betas - ] + iterated_runcard_yaml = API.next_effective_exponents_yaml( + fit=input_fit, _updated_description=updated_description + ) # Write new runcard to file with open(runcard_path_out, "w") as outfile: - yaml.dump(runcard_data, outfile, Dumper=yaml.RoundTripDumper) - log.info(f"Runcard for iterated fit written to {runcard_path_out.absolute()}.") + outfile.write(iterated_runcard_yaml) + log.info("Runcard for iterated fit written to %s.", runcard_path_out.absolute()) # Open new runcard with default editor, or if one is not set, with vi EDITOR = os.environ.get("EDITOR") if os.environ.get("EDITOR") else "vi" -- GitLab