-
Notifications
You must be signed in to change notification settings - Fork 10
Use eko v0.15 #2181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use eko v0.15 #2181
Changes from all commits
3bac746
243b2e2
14afdc5
075c51e
13937ac
5c8fa60
d3d4268
112499f
1bcb0f6
fbdb062
6e9bc4f
a1c0d2b
4235b1f
1147216
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
# Ignore auto generated module references | ||
source/modules | ||
source/theories.csv | ||
source/theories_central.csv |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,17 @@ | ||
from collections import defaultdict | ||
import dataclasses | ||
import json | ||
import logging | ||
import pathlib | ||
import sys | ||
|
||
from ekobox import apply, genpdf, info_file | ||
from joblib import Parallel, delayed | ||
import numpy as np | ||
import psutil | ||
|
||
import eko | ||
from eko import basis_rotation, runner | ||
from eko.interpolation import XGrid | ||
from eko.io import manipulate | ||
from validphys.utils import yaml_safe | ||
|
||
from . import eko_utils, utils | ||
|
@@ -24,19 +25,9 @@ | |
"level": logging.DEBUG, | ||
} | ||
|
||
NUM_CORES = psutil.cpu_count(logical=False) | ||
|
||
|
||
def evolve_fit( | ||
fit_folder, | ||
q_fin, | ||
q_points, | ||
op_card_dict, | ||
theory_card_dict, | ||
force, | ||
eko_path, | ||
dump_eko=None, | ||
ncores=1, | ||
fit_folder, q_fin, q_points, op_card_dict, theory_card_dict, force, eko_path, dump_eko=None | ||
): | ||
""" | ||
Evolves all the fitted replica in fit_folder/nnfit | ||
|
@@ -106,10 +97,7 @@ def evolve_fit( | |
else: | ||
raise ValueError(f"dump_eko not provided and {eko_path=} not found") | ||
|
||
with eko.EKO.edit(eko_path) as eko_op: | ||
x_grid_obj = eko.interpolation.XGrid(x_grid) | ||
eko.io.manipulate.xgrid_reshape(eko_op, targetgrid=x_grid_obj, inputgrid=x_grid_obj) | ||
|
||
# Open the EKO in read-only mode, if it needs to be manipulated keep it in memory | ||
with eko.EKO.read(eko_path) as eko_op: | ||
# Read the cards directly from the eko to make sure they are consistent | ||
theory = eko_op.theory_card | ||
|
@@ -118,6 +106,42 @@ def evolve_fit( | |
_logger.debug(f"Theory card: {json.dumps(theory.raw)}") | ||
_logger.debug(f"Operator card: {json.dumps(op.raw)}") | ||
|
||
eko_original_xgrid = eko_op.xgrid | ||
if XGrid(x_grid) != eko_original_xgrid: | ||
# If the xgrid of the eko is not directly usable, construct a copy in memory | ||
# by replacing the internal inventory of operators in a readonly copy | ||
new_xgrid = XGrid(x_grid) | ||
new_metadata = dataclasses.replace(eko_op.metadata, xgrid=new_xgrid) | ||
|
||
new_operators = {} | ||
for target_key in eko_op.operators: | ||
elem = eko_op[target_key.ep] | ||
|
||
if eko_op.metadata.version == "0.13.4": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to support 0.13.4? EKO itself currently only supports There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was debating myself whether to include this or not, but in the end I decided to be nice. There are some theories people use that have 0.13.4, and this will let them use it for some time (unless you are now forbidding these for being read at all, when I tested this PR they were read but they were not 100% correct). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking to NNPDF/eko#448 I think they are still read - @evagroenendijk do you agree? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think indeed they are read but a while ago when I tested versions <0.13.5 did not exactly reproduce the benchmark |
||
# For eko 0.13.4 xgrid is the internal interpolation so we need to check | ||
# whether the rotation is truly needed | ||
# <in practice> this means checking whether the operator shape matches the grid | ||
oplen = elem.operator.shape[-1] | ||
if oplen != len(eko_original_xgrid): | ||
# The operator and its xgrid have different shape | ||
# either prepare an identity, or this EKO is not supported | ||
if oplen != len(x_grid): | ||
raise ValueError( | ||
f"The operator at {eko_path} is not usable, version not supported" | ||
) | ||
eko_original_xgrid = XGrid(x_grid) | ||
|
||
new_operators[target_key] = manipulate.xgrid_reshape( | ||
elem, | ||
eko_original_xgrid, | ||
op.configs.interpolation_polynomial_degree, | ||
targetgrid=XGrid(x_grid), | ||
inputgrid=XGrid(x_grid), | ||
) | ||
|
||
new_inventory = dataclasses.replace(eko_op.operators, cache=new_operators) | ||
eko_op = dataclasses.replace(eko_op, metadata=new_metadata, operators=new_inventory) | ||
|
||
# Modify the info file with the fit-specific info | ||
info = info_file.build(theory, op, 1, info_update={}) | ||
info["NumMembers"] = "REPLACE_NREP" | ||
|
@@ -126,21 +150,49 @@ def evolve_fit( | |
info["XMax"] = float(x_grid[-1]) | ||
# Save the PIDs in the info file in the same order as in the evolution | ||
info["Flavors"] = basis_rotation.flavor_basis_pids | ||
info["NumFlavors"] = theory.heavy.num_flavs_max_pdf | ||
info.setdefault("NumFlavors", 5) | ||
dump_info_file(usr_path, info) | ||
|
||
def _wrap_evolve(pdf, replica): | ||
evolved_blocks = evolve_exportgrid(pdf, eko_op, x_grid) | ||
dump_evolved_replica(evolved_blocks, usr_path, int(replica.removeprefix("replica_"))) | ||
|
||
# Choose the number of cores to be the Minimal value | ||
nb_cores = min(NUM_CORES, abs(ncores)) | ||
Parallel(n_jobs=nb_cores)( | ||
delayed(_wrap_evolve)(pdf, r) for r, pdf in initial_PDFs_dict.items() | ||
) | ||
# Read the information from all the sorted replicas into what eko wants | ||
n_replicas = len(initial_PDFs_dict) | ||
all_replicas = [] | ||
for rep_idx in range(1, n_replicas + 1): | ||
# swap photon position to match eko.basis_rotation.flavor_basis_pids | ||
pdfgrid = np.array(initial_PDFs_dict[f"replica_{rep_idx}"]["pdfgrid"]) | ||
pdfgrid = np.append(pdfgrid[:, -1].reshape(x_grid.size, 1), pdfgrid[:, :-1], axis=1) | ||
# and divide by x | ||
all_replicas.append(pdfgrid.T / x_grid) | ||
|
||
# output is {(Q2, nf): (replica, flavour, x)} | ||
all_evolved, _ = apply.apply_grids(eko_op, np.array(all_replicas)) | ||
|
||
# Now, replica by replica, break into nf blocks | ||
targetgrid = eko_op.xgrid.tolist() | ||
by_nf = defaultdict(list) | ||
for q2, nf in sorted(eko_op.evolgrid, key=lambda ep: ep[1]): | ||
by_nf[nf].append(q2) | ||
q2block_per_nf = {nf: sorted(q2s) for nf, q2s in by_nf.items()} | ||
|
||
for replica in range(n_replicas): | ||
blocks = [] | ||
for nf, q2grid in q2block_per_nf.items(): | ||
|
||
def pdf_xq2(pid, x, Q2): | ||
x_idx = targetgrid.index(x) | ||
pid_idx = info["Flavors"].index(pid) | ||
return x * all_evolved[(Q2, nf)][replica][pid_idx][x_idx] | ||
|
||
block = genpdf.generate_block( | ||
pdf_xq2, | ||
xgrid=targetgrid, | ||
sorted_q2grid=q2grid, | ||
pids=basis_rotation.flavor_basis_pids, | ||
) | ||
blocks.append(block) | ||
dump_evolved_replica(blocks, usr_path, replica + 1) | ||
|
||
# remove folder: | ||
# The function dump_evolved_replica dumps the replica files in a temporary folder | ||
# The function dump_evolved_replica uses a temporary folder | ||
# We need then to remove it after fixing the position of those replica files | ||
(usr_path / "nnfit" / usr_path.stem).rmdir() | ||
|
||
|
@@ -169,52 +221,6 @@ def load_fit(usr_path): | |
return pdf_dict | ||
|
||
|
||
def evolve_exportgrid(exportgrid, eko, x_grid): | ||
""" | ||
Evolves the provided exportgrid for the desired replica with the eko and returns the evolved block | ||
|
||
Parameters | ||
---------- | ||
exportgrid: dict | ||
exportgrid of pdf at fitting scale | ||
eko: eko object | ||
eko operator for evolution | ||
xgrid: list | ||
xgrid to be used as the targetgrid | ||
Returns | ||
------- | ||
: list(np.array) | ||
list of evolved blocks | ||
""" | ||
# construct LhapdfLike object | ||
pdf_grid = np.array(exportgrid["pdfgrid"]).transpose() | ||
pdf_to_evolve = utils.LhapdfLike(pdf_grid, exportgrid["q20"], x_grid) | ||
# evolve pdf | ||
evolved_pdf = apply.apply_pdf(eko, pdf_to_evolve) | ||
# generate block to dump | ||
targetgrid = eko.bases.targetgrid.tolist() | ||
|
||
# Finally separate by nf block (and order per nf/q) | ||
by_nf = defaultdict(list) | ||
for q, nf in sorted(eko.evolgrid, key=lambda ep: ep[1]): | ||
by_nf[nf].append(q) | ||
q2block_per_nf = {nf: sorted(qs) for nf, qs in by_nf.items()} | ||
|
||
blocks = [] | ||
for nf, q2grid in q2block_per_nf.items(): | ||
|
||
def pdf_xq2(pid, x, Q2): | ||
x_idx = targetgrid.index(x) | ||
return x * evolved_pdf[(Q2, nf)]["pdfs"][pid][x_idx] | ||
|
||
block = genpdf.generate_block( | ||
pdf_xq2, xgrid=targetgrid, sorted_q2grid=q2grid, pids=basis_rotation.flavor_basis_pids | ||
) | ||
blocks.append(block) | ||
|
||
return blocks | ||
|
||
|
||
def dump_evolved_replica(evolved_blocks, usr_path, replica_num): | ||
""" | ||
Dump the evolved replica given by evolved_block as the replica num "replica_num" in | ||
|
Uh oh!
There was an error while loading. Please reload this page.