Skip to content

Commit

Permalink
add a lhapdf_compatibility class to avoid having to use lhapdf
Browse files Browse the repository at this point in the history
  • Loading branch information
scarlehoff committed Dec 4, 2023
1 parent 46bfe1a commit d1a7229
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 12 deletions.
23 changes: 23 additions & 0 deletions n3fit/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# n3fit
tensorflow
psutil
# evolven3fit
eko
# validphys
pineappl
reportengine
validobj
prompt_toolkit
## hyperopt
hyperopt
seaborn

# not available from pypi
# lhapdf
# instead install:
pdfflow
lhapdf_management

# if lhapdf_management needs to be initialized:
# LHAPDF_DATA_PATH=$(python -c 'from pathlib import Path ; from sys import prefix ; print(Path(prefix) / "share" / "LHAPDF")' ; lhapdf-management update

4 changes: 1 addition & 3 deletions n3fit/runcards/examples/Basic_runcard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ description: Basic runcard
# ewk: apply ewk k-factors
# sys: systematics treatment (see systypes)
dataset_inputs:
- { dataset: SLACP_dwsh, frac: 0.5}
- { dataset: NMCPD_dw, frac: 0.5 }
- { dataset: ATLASZPT8TEVMDIST, frac: 0.75, sys: 10, cfac: [QCD] }

############################################################
Expand All @@ -31,7 +29,7 @@ datacuts:

############################################################
theory:
theoryid: 200 # database id
theoryid: 400 # database id

sampling:
separate_multiplicative: true
Expand Down
5 changes: 5 additions & 0 deletions n3fit/src/n3fit/backends/keras_backend/internal_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ def set_number_of_cores(max_cores=None):
max_cores: int
Maximum number of cores to be used
"""
try:
import lhapdf
except ModuleNotFoundError:
# If LHAPDF is not working then that means we already have initialized tensorflow at this point
return
# Find how many cores we have and how many threads per core
cores = psutil.cpu_count(logical=False)
logical = psutil.cpu_count(logical=True)
Expand Down
3 changes: 1 addition & 2 deletions validphys2/src/validphys/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
import os
import sys

import lhapdf

from reportengine import app
from validphys import mplstyles, uploadutils
from validphys.config import Config, Environment
from validphys.lhapdf_compatibility import lhapdf

providers = [
"validphys.results",
Expand Down
3 changes: 1 addition & 2 deletions validphys2/src/validphys/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import platform
import tempfile

import lhapdf
from matplotlib import scale as mscale

from reportengine.checks import CheckError, check, make_argcheck, make_check
Expand Down Expand Up @@ -65,7 +64,7 @@ def check_can_save_grid(ns, **kwags):
if not ns['installgrid']:
return

write_path = lhapdf.paths()[-1]
write_path = lhaindex.get_lha_paths()[-1]
try:
tempfile.TemporaryFile(dir=write_path)
except OSError as e:
Expand Down
3 changes: 1 addition & 2 deletions validphys2/src/validphys/lhaindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
import os.path as osp
import re

import lhapdf

from reportengine.compat import yaml
from validphys.lhapdf_compatibility import lhapdf

_indexes_to_names = None
_names_to_indexes = None
Expand Down
113 changes: 113 additions & 0 deletions validphys2/src/validphys/lhapdf_compatibility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""
Module for LHAPDF compatibility backends
If LHAPDF is installed, the module will transparently hand over everything to LHAPDF
if LHAPDF is not available, it will try to use a combination of the packages
`lhapdf-management` and `pdfflow`
which cover all the features of LHAPDF used during the fit (and likely most of validphys)
Eventually this module will allow us to transition to an under-development python/rust
PDF interpolation library.
"""
import numpy as np

try:
import lhapdf

USING_LHAPDF = True
except ModuleNotFoundError:
import logging

import lhapdf_management as lhapdf
import pdfflow

log = logging.getLogger(__name__)
log.warning("LHAPDF was not found, using an alternative backend")

USING_LHAPDF = False


class _PDFFlowPDF:
"""Wrapper around the PDFFlow PDF so that it can be used as an LHAPDF
set by validphys
Takes as input a pdf_meta object (which is a PDFset from lhapdf_management
and which knows _where_ the PDF needs to be loaded from) and a single member
Loading the PDF is done in a lazy manner since most of the time only a few members are needed.
"""

def __init__(self, pdf_meta, member):
if USING_LHAPDF:
raise ValueError("PDFFlow should not be instantiated when using LHAPDF")

self._pdf_meta = pdf_meta
self._m = member
self._pdf = None

@property
def pdf(self):
if self._pdf is None:
pdf_def = f"{self._pdf_meta.name}/{self._m}"
self._pdf = pdfflow.mkPDF(pdf_def, self._pdf_meta.path.parent)
return self._pdf

@property
def flavors(self):
return self._pdf_meta.info["Flavors"]

def _xfxQ_all_pid(self, x, q):
if isinstance(x, float):
x = np.array([x])
if isinstance(q, float):
q = np.array([q])

res = self.pdf.py_xfxQ2_allpid(x, q**2).numpy()
return dict(zip(self.flavors, res.T))

def xfxQ(self, a, b, c=None):
"""Wrapper for the LHAPDF xfxQ function
This is an overloaded function in LHAPDF so depending
on the number of arguments we will do:
xfxQ(flavours, x, Q)
or
xfxQ(x, q)
And x/q/flavours can be either an scalar or an array
"""
if c is None:
return self._xfxQ_all_pid(a, b)

# PDFFlow doesn't allow to ask for flavours that do not exist
ret_dict = self.xfxQ(b, c)
zeros = np.zeros_like(b)
return [ret_dict.get(i, zeros) for i in a]


def make_pdf(pdf_name, member=None):
"""Load a PDF
if member is given, load the single member otherwise, load the entire set as a list
if LHAPDF is provided, it returns LHAPDF PDF instances
otherwise it returns and object which is _compatible_ with LHAPDF
for lhapdf functions for the selected backend
Parameters:
----------
pdf_name: str
name of the PDF to load
member: int
index of the member of the PDF to load
Returns:
-------
list(pdf_sets)
"""
if USING_LHAPDF:
if member is None:
return lhapdf.mkPDFs(pdf_name)
return [lhapdf.mkPDF(pdf_name, member)]

pdf_meta = lhapdf.load_pdf_meta(pdf_name)
if member is None:
return [_PDFFlowPDF(pdf_meta, m) for m in len(pdf_meta)]
return [_PDFFlowPDF(pdf_meta, member)]
7 changes: 4 additions & 3 deletions validphys2/src/validphys/lhapdfset.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
"""
import logging

import lhapdf
import numpy as np

from validphys.lhapdf_compatibility import make_pdf

log = logging.getLogger(__name__)


Expand All @@ -46,9 +47,9 @@ def __init__(self, name, error_type):
self._error_type = error_type
if self.is_t0:
# If at this point we already know this is a T0 set, load only the CV
self._lhapdf_set = [lhapdf.mkPDF(name)]
self._lhapdf_set = make_pdf(name, 0)
else:
self._lhapdf_set = lhapdf.mkPDFs(name)
self._lhapdf_set = make_pdf(name)
self._flavors = None

@property
Expand Down
1 change: 1 addition & 0 deletions validphys2/src/validphys/photon/compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class Photon:
"""Photon class computing the photon array with the LuxQED approach."""

def __init__(self, theoryid, lux_params, replicas):
import fiatlux
theory = theoryid.get_description()
fiatlux_runcard = FIATLUX_DEFAULT
fiatlux_runcard["qed_running"] = bool(np.isclose(theory["Qedref"], theory["Qref"]))
Expand Down

0 comments on commit d1a7229

Please sign in to comment.