From 17033fcec8bc55320ae1eb0b0d4d060524294928 Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Fri, 10 Jan 2025 16:07:30 +0200 Subject: [PATCH 1/9] Improve assets script and attempt pytest fix --- .github/workflows/unittests-rust.yml | 3 +-- .github/workflows/unittests.yml | 15 +++++++++++++++ crates/dekoder/tests/data/download.sh | 3 --- download-test-assets.sh | 8 -------- tests/data/assets.sh | 17 +++++++++++++++++ 5 files changed, 33 insertions(+), 13 deletions(-) delete mode 100755 crates/dekoder/tests/data/download.sh delete mode 100755 download-test-assets.sh create mode 100755 tests/data/assets.sh diff --git a/.github/workflows/unittests-rust.yml b/.github/workflows/unittests-rust.yml index 0f07005dc..cd84830fc 100644 --- a/.github/workflows/unittests-rust.yml +++ b/.github/workflows/unittests-rust.yml @@ -16,8 +16,7 @@ jobs: - name: Download test data if: steps.cache-test-data.outputs.cache-hit != 'true' run: | - cd crates/dekoder/tests/data - ./download.sh + ./test/data/assets.sh - uses: actions/setup-python@v5 - name: Install task runner run: pip install poethepoet diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index a21b8531e..ee8df1d64 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -3,7 +3,22 @@ name: Python unit tests on: push jobs: + data: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Get test data + id: cache-test-data + uses: actions/cache@v4 + with: + path: test-data + key: test-data-v1 + - name: Download test data + if: steps.cache-test-data.outputs.cache-hit != 'true' + run: | + ./test/data/assets.sh test: + needs: data strategy: matrix: python-version: ["3.9", "3.10", "3.11", "3.12"] diff --git a/crates/dekoder/tests/data/download.sh b/crates/dekoder/tests/data/download.sh deleted file mode 100755 index afcc880ec..000000000 --- a/crates/dekoder/tests/data/download.sh +++ /dev/null @@ -1,3 +0,0 @@ -# upload: scp v0.15.tar nnpdf@data.nnpdf.science:WEB/eko/test-data - -curl -s -C - -O 'https://data.nnpdf.science/eko/test-data/v0.15.tar' diff --git a/download-test-assets.sh b/download-test-assets.sh deleted file mode 100755 index 5b45e10b6..000000000 --- a/download-test-assets.sh +++ /dev/null @@ -1,8 +0,0 @@ -# upload: scp v0.15.tar nnpdf@data.nnpdf.science:WEB/eko/test-data - -curl -s -C - -o './tests/data/v0.15.tar' 'https://data.nnpdf.science/eko/test-data/v0.15.tar' -curl -s -C - -o './tests/data/v0.13.tar' 'https://data.nnpdf.science/eko/test-data/ekov013.tar' -curl -s -C - -o './tests/data/v0.14.tar' 'https://data.nnpdf.science/eko/test-data/ekov014.tar' - - - diff --git a/tests/data/assets.sh b/tests/data/assets.sh new file mode 100755 index 000000000..9d96539ac --- /dev/null +++ b/tests/data/assets.sh @@ -0,0 +1,17 @@ +#!/usr/bin/bash +# upload: scp v0.15.tar nnpdf@data.nnpdf.science:WEB/eko/test-data + +# Server path +URL="https://data.nnpdf.science/eko/test-data/" +# local paths +PYDATADIR="tests/data/" +RUSTDATADIR="crates/dekoder/tests/data/" + +# download from the server +curl -s -C - -o "./${PYDATADIR}v0.13.tar" "${URL}ekov013.tar" +curl -s -C - -o "./${PYDATADIR}v0.14.tar" "${URL}ekov014.tar" +curl -s -C - -o "./${PYDATADIR}v0.15.tar" "${URL}v0.15.tar" +# expose to Rust +if [ ! -f "./${RUSTDATADIR}v0.15.tar" ]; then + ln -s "./../../../../${PYDATADIR}v0.15.tar" "./${RUSTDATADIR}" +fi From 3d9c9b17602960fee08559c4a606a763f4644112 Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Fri, 10 Jan 2025 16:09:13 +0200 Subject: [PATCH 2/9] Fix plural typo in workflow --- .github/workflows/unittests-rust.yml | 2 +- .github/workflows/unittests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unittests-rust.yml b/.github/workflows/unittests-rust.yml index cd84830fc..c9ea5097f 100644 --- a/.github/workflows/unittests-rust.yml +++ b/.github/workflows/unittests-rust.yml @@ -16,7 +16,7 @@ jobs: - name: Download test data if: steps.cache-test-data.outputs.cache-hit != 'true' run: | - ./test/data/assets.sh + ./tests/data/assets.sh - uses: actions/setup-python@v5 - name: Install task runner run: pip install poethepoet diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index ee8df1d64..447f84717 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -16,7 +16,7 @@ jobs: - name: Download test data if: steps.cache-test-data.outputs.cache-hit != 'true' run: | - ./test/data/assets.sh + ./tests/data/assets.sh test: needs: data strategy: From 4ed730f7ea489e42dc1ce43d5586ed7860da4f7a Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Fri, 10 Jan 2025 16:32:31 +0200 Subject: [PATCH 3/9] Fix some py unit tests --- .github/workflows/unittests.yml | 15 --------- tests/conftest.py | 2 +- tests/eko/io/test_metadata.py | 6 ++-- tests/eko/io/test_struct.py | 4 +-- tests/eko/runner/test_legacy.py | 58 --------------------------------- 5 files changed, 6 insertions(+), 79 deletions(-) delete mode 100644 tests/eko/runner/test_legacy.py diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 447f84717..a21b8531e 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -3,22 +3,7 @@ name: Python unit tests on: push jobs: - data: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Get test data - id: cache-test-data - uses: actions/cache@v4 - with: - path: test-data - key: test-data-v1 - - name: Download test data - if: steps.cache-test-data.outputs.cache-hit != 'true' - run: | - ./tests/data/assets.sh test: - needs: data strategy: matrix: python-version: ["3.9", "3.10", "3.11", "3.12"] diff --git a/tests/conftest.py b/tests/conftest.py index 4ff7a8224..8ce700e46 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -90,7 +90,7 @@ def _create(self): lx = len(self.operator.xgrid) lpids = len(self.operator.pids) for mu2, op in self._operators( - mugrid=self.operator.evolgrid, shape=(lpids, lx) + mugrid=self.operator.evolgrid, shape=(lpids, lx, lpids, lx) ).items(): self.cache[mu2] = op diff --git a/tests/eko/io/test_metadata.py b/tests/eko/io/test_metadata.py index cdc3308c9..852e1a0be 100644 --- a/tests/eko/io/test_metadata.py +++ b/tests/eko/io/test_metadata.py @@ -12,7 +12,7 @@ def test_metadata(tmp_path, caplog): m.update() assert "no file" in caplog.text with pytest.raises(RuntimeError): - m.path + _ = m.path # now modify m.path = tmp_path m.update() @@ -22,11 +22,11 @@ def test_metadata(tmp_path, caplog): assert p.metadata.is_file() assert "version" in p.metadata.read_text() # change version - m.version = "0.0.0-a1~really1.0.0" + m.version = "0.0.1" m.update() # if I read back the thing should be what I set mn = metadata.Metadata(origin=(1.0, 3), xgrid=[0.1, 1.0]) mm = metadata.Metadata.load(tmp_path) assert m.path == tmp_path assert mm.version != mn.version - assert mm.version == "0.0.0-a1~really1.0.0" + assert mm.version == "0.0.1" diff --git a/tests/eko/io/test_struct.py b/tests/eko/io/test_struct.py index 1370ccdb6..e0c056da1 100644 --- a/tests/eko/io/test_struct.py +++ b/tests/eko/io/test_struct.py @@ -119,7 +119,7 @@ def test_copy(self, eko_factory: EKOFactory, tmp_path: pathlib.Path): mugrid = [(mu, nf)] eko_factory.operator.mugrid = mugrid eko1 = eko_factory.get() - v = np.random.rand(2, 2) + v = np.random.rand(2, 2, 2, 2) opv = struct.Operator(operator=v) eko1[ep] = opv np.testing.assert_allclose(eko1[ep].operator, v) @@ -128,7 +128,7 @@ def test_copy(self, eko_factory: EKOFactory, tmp_path: pathlib.Path): with EKO.edit(p) as eko2: np.testing.assert_allclose(eko1[ep].operator, v) np.testing.assert_allclose(eko2[ep].operator, v) - vv = np.random.rand(2, 2) + vv = np.random.rand(2, 2, 2, 2) opvv = struct.Operator(operator=vv) eko2[ep] = opvv np.testing.assert_allclose(eko1[ep].operator, v) diff --git a/tests/eko/runner/test_legacy.py b/tests/eko/runner/test_legacy.py deleted file mode 100644 index aed8df0ac..000000000 --- a/tests/eko/runner/test_legacy.py +++ /dev/null @@ -1,58 +0,0 @@ -import copy -import enum - -import pytest - -import eko -from eko import EKO -from eko.io.runcards import TheoryCard -from eko.quantities.heavy_quarks import QuarkMassScheme - -from . import check_shapes - - -def test_raw(theory_card, operator_card, tmp_path): - """We don't check the content here, but only the shape.""" - path = tmp_path / "eko.tar" - tc = theory_card - oc = operator_card - r = eko.runner.legacy.Runner(tc, oc, path=path) - r.compute() - with EKO.read(path) as eko_: - check_shapes(eko_, eko_.xgrid, eko_.xgrid, tc, oc) - - -def test_mass_scheme(theory_card, operator_card, tmp_path): - """We don't check the content here, but only the shape.""" - - # wrong mass scheme - class FakeEM(enum.Enum): - BLUB = "blub" - - path = tmp_path / "eko.tar" - theory_card.heavy.masses_scheme = FakeEM.BLUB - with pytest.raises(ValueError, match="BLUB"): - eko.runner.legacy.Runner(theory_card, operator_card, path=path) - # MSbar scheme - theory_card.heavy.masses_scheme = QuarkMassScheme.MSBAR - theory_card.couplings.ref = (91.0, 5) - theory_card.heavy.masses.c.scale = 2 - theory_card.heavy.masses.b.scale = 4.5 - theory_card.heavy.masses.t.scale = 173.07 - r = eko.runner.legacy.Runner(theory_card, operator_card, path=path) - r.compute() - with EKO.read(path) as eko_: - check_shapes(eko_, eko_.xgrid, eko_.xgrid, theory_card, operator_card) - - -def test_vfns(theory_ffns, operator_card, tmp_path): - path = tmp_path / "eko.tar" - tc: TheoryCard = theory_ffns(3) - oc = copy.deepcopy(operator_card) - tc.heavy.matching_ratios.c = 1.0 - tc.heavy.matching_ratios.b = 1.0 - tc.order = (2, 0) - r = eko.runner.legacy.Runner(tc, oc, path=path) - r.compute() - with EKO.read(path) as eko_: - check_shapes(eko_, eko_.xgrid, eko_.xgrid, tc, oc) From 43c843486930c4b5de1224207f57f5d79c2a9637 Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Mon, 13 Jan 2025 11:11:34 +0200 Subject: [PATCH 4/9] Remove whitespace in docs --- doc/source/theory/N3LO_ad.rst | 15 +++++++-------- doc/source/theory/pQCD.rst | 7 +++---- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/doc/source/theory/N3LO_ad.rst b/doc/source/theory/N3LO_ad.rst index 3a9141203..81ab1ab67 100644 --- a/doc/source/theory/N3LO_ad.rst +++ b/doc/source/theory/N3LO_ad.rst @@ -8,22 +8,22 @@ since in Mellin space they include harmonics sum up to weight 7, for which an analytical expression is not available. We provide two different types of approximations, depending on the key ``use_fhmruvv``. -The theory card parameter ``n3lo_ad_variation=(gg, gq, qg, qq, nsp, nsm, nsv)``, +The theory card parameter ``n3lo_ad_variation=(gg, gq, qg, qq, nsp, nsm, nsv)``, which is set to ``(0,0,0,0,0,0,0)`` as default, can be varied to obtain parametrization uncertainties. In particular: -* ``use_fhmruvv = True`` (default option) adopts the parametrizations as provided - in :cite:`Moch:2017uml,Falcioni:2023luc,Falcioni:2023vqq,Falcioni:2024xyt,Falcioni:2024qpd`. - For each of the 7 splitting functions, the approximation error can be obtained by varying - the entries of ``n3lo_ad_variation`` in the range: ``0``, +* ``use_fhmruvv = True`` (default option) adopts the parametrizations as provided + in :cite:`Moch:2017uml,Falcioni:2023luc,Falcioni:2023vqq,Falcioni:2024xyt,Falcioni:2024qpd`. + For each of the 7 splitting functions, the approximation error can be obtained by varying + the entries of ``n3lo_ad_variation`` in the range: ``0``, cental value (default), ``1`` down variation, ``2`` up variation. * ``use_fhmruvv = False`` adopts an in-house parametrization, constructed as described below. - In this case only variations of the singlet sector are available. Currently one + In this case only variations of the singlet sector are available. Currently one can vary ``n3lo_ad_variation`` in the range: ``0-19`` for ``gg``, ``0-15`` for ``gg``, ``0-15`` for ``qg``, ``0-6`` for ``qq``. - Note these approximations will be no longer updated and are now deprecated. + Note these approximations will be no longer updated and are now deprecated. In house approximation @@ -294,7 +294,6 @@ The difference between the known moments and the known limits is parametrized in Mellin space using different basis, in order to estimate the uncertainties of our determination. - Uncertainties estimation ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/source/theory/pQCD.rst b/doc/source/theory/pQCD.rst index 27c5cb543..100994c0c 100644 --- a/doc/source/theory/pQCD.rst +++ b/doc/source/theory/pQCD.rst @@ -51,7 +51,6 @@ can be specified at ``scale_ref`` along with ``nf_ref`` and, the computed result depend on the number of flavors at the target scale, see :meth:`eko.couplings.Couplings.a_s` An example how the evolution path is determined is given :doc:`here`. - QCD Splitting Functions ----------------------- @@ -86,8 +85,8 @@ At |NLO|, the singlet entry of the quark-quark anomalous dimension can be decomp \gamma^{(1)}_{qq} =\gamma^{(1)}_{ps} + \gamma^{(1)}_{ns,+} The non-singlet sector in the polarized case swaps the plus and minus non-singlet relative to the unpolarized case. -This is because the polarized non-singlet splitting functions are defined as the difference between the probability of the polarized parton splitting -into daughter partons of the same flavour and same helicity and daughters of a different flavours and opposite helicity. +This is because the polarized non-singlet splitting functions are defined as the difference between the probability of the polarized parton splitting +into daughter partons of the same flavour and same helicity and daughters of a different flavours and opposite helicity. The first moments of the anomalous dimensions are: .. math :: @@ -103,7 +102,7 @@ At |NNLO| the non-singlet is further decomposed into the helicity difference qua where :math:`\gamma^{(2)}_{ns,-}` is the minus flavour asymmetry non-singlet and :math:`\gamma^{(2)}_{ns,s}` the sea-like polarized non-singlet. The singlet entry :math:`\gamma^{(2)}_{qq}` is defined as above in the |NLO| case. -Finally the violation of the axial current conservation :math:`\bar{\psi} \gamma_\mu \gamma_5 \bar{\psi}` only through +Finally the violation of the axial current conservation :math:`\bar{\psi} \gamma_\mu \gamma_5 \bar{\psi}` only through loop corrections impose the following relations to the singlet splittings at all orders :cite:`Moch:2014sna` : .. math :: From c161129cd859025845e41bcfdc8268346ad1e17f Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Mon, 13 Jan 2025 11:16:30 +0200 Subject: [PATCH 5/9] Run ruff --- doc/source/overview/tutorials/alpha_s.ipynb | 3 ++- doc/source/overview/tutorials/dglap.ipynb | 1 + doc/source/overview/tutorials/pdf.ipynb | 12 ++++++++---- src/ekobox/evol_pdf.py | 2 +- src/ekomark/benchmark/runner.py | 2 +- .../unpolarized/space_like/as4/fhmruvv/ggg.py | 3 +-- tests/eko/evolution_operator/test_flavors.py | 4 ++-- .../polarized/space_like/test_ad_as2.py | 8 ++------ .../unpolarized/space_like/test_init.py | 14 ++++++++++++-- 9 files changed, 30 insertions(+), 19 deletions(-) diff --git a/doc/source/overview/tutorials/alpha_s.ipynb b/doc/source/overview/tutorials/alpha_s.ipynb index a87682407..287d295ee 100644 --- a/doc/source/overview/tutorials/alpha_s.ipynb +++ b/doc/source/overview/tutorials/alpha_s.ipynb @@ -34,8 +34,9 @@ "outputs": [], "source": [ "import numpy as np\n", + "\n", "from eko.couplings import Couplings\n", - "from eko.quantities.couplings import CouplingsInfo, CouplingEvolutionMethod\n", + "from eko.quantities.couplings import CouplingEvolutionMethod, CouplingsInfo\n", "from eko.quantities.heavy_quarks import QuarkMassScheme\n", "\n", "# set the (alpha_s, alpha_em) reference values\n", diff --git a/doc/source/overview/tutorials/dglap.ipynb b/doc/source/overview/tutorials/dglap.ipynb index 98cb4a6e1..b23bc43d8 100644 --- a/doc/source/overview/tutorials/dglap.ipynb +++ b/doc/source/overview/tutorials/dglap.ipynb @@ -35,6 +35,7 @@ ], "source": [ "import pathlib\n", + "\n", "import eko\n", "\n", "eko.version.__version__" diff --git a/doc/source/overview/tutorials/pdf.ipynb b/doc/source/overview/tutorials/pdf.ipynb index 38ddcd63d..a001ba5bc 100644 --- a/doc/source/overview/tutorials/pdf.ipynb +++ b/doc/source/overview/tutorials/pdf.ipynb @@ -50,9 +50,11 @@ "outputs": [], "source": [ "import pathlib\n", - "import eko\n", + "\n", "from banana import toy\n", "\n", + "import eko\n", + "\n", "pdf = toy.mkPDF(\"\", 0)" ] }, @@ -341,11 +343,13 @@ ], "source": [ "from math import nan\n", - "import numpy as np\n", + "\n", "import lhapdf\n", - "from ekobox.cards import example\n", + "import numpy as np\n", + "\n", "from eko.interpolation import make_grid\n", - "from eko.quantities.heavy_quarks import QuarkMassRef, HeavyQuarks\n", + "from eko.quantities.heavy_quarks import HeavyQuarks, QuarkMassRef\n", + "from ekobox.cards import example\n", "\n", "# get the PDF object\n", "ct14llo = lhapdf.mkPDF(\"CT14llo\")\n", diff --git a/src/ekobox/evol_pdf.py b/src/ekobox/evol_pdf.py index b629dd249..6de6db087 100644 --- a/src/ekobox/evol_pdf.py +++ b/src/ekobox/evol_pdf.py @@ -58,7 +58,7 @@ def evolve_pdfs( # equal points are allowed by LHAPDF if q2block_per_nf[nfs[j]][-1] > q2block_per_nf[nfs[j + 1]][0]: raise ValueError( - f"Last scale point for nf={nfs[j]} is bigger than first in nf={nfs[j+1]}" + f"Last scale point for nf={nfs[j]} is bigger than first in nf={nfs[j + 1]}" ) # update op and th cards diff --git a/src/ekomark/benchmark/runner.py b/src/ekomark/benchmark/runner.py index a1d79c67a..e2ea83091 100644 --- a/src/ekomark/benchmark/runner.py +++ b/src/ekomark/benchmark/runner.py @@ -102,7 +102,7 @@ def run_me(self, theory, ocard, _pdf): print(f"Operator written to {path}") else: # load - print(f"Using cached eko data: {os.path.relpath(path,os.getcwd())}") + print(f"Using cached eko data: {os.path.relpath(path, os.getcwd())}") if self.plot_operator: from ekomark.plots import ( # pylint:disable=import-error,import-outside-toplevel diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py index 71b29d988..cd680c765 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py @@ -180,8 +180,7 @@ def gamma_gg(n, nf, cache, variation): - 705978.0 * (-(1 / (-1 + n) ** 2) + 1 / n**2) - 2192234.0 * 1 / ((-1 + n) * n) + 1730508.0 * (1 / (2 + 3 * n + n**2)) - + 353143.0 - * ((12 + 9 * n + n**2) / (6 * n + 11 * n**2 + 6 * n**3 + n**4)) + + 353143.0 * ((12 + 9 * n + n**2) / (6 * n + 11 * n**2 + 6 * n**3 + n**4)) - 2602682.0 * (-(1 / n**2) + 1 / (1 + n) ** 2) + 178960.0 * 2 / n**3 - 218133.0 * (-(6 / n**4)) diff --git a/tests/eko/evolution_operator/test_flavors.py b/tests/eko/evolution_operator/test_flavors.py index 2f3761404..90c33adcb 100644 --- a/tests/eko/evolution_operator/test_flavors.py +++ b/tests/eko/evolution_operator/test_flavors.py @@ -144,8 +144,8 @@ def test_rotate_matching_qed(): def test_rotate_matching_is_inv(): def replace_names(k): for q in range(4, 6 + 1): - k = k.replace(br.quark_names[q - 1] + "+", f"T{q**2-1}").replace( - br.quark_names[q - 1] + "-", f"V{q**2-1}" + k = k.replace(br.quark_names[q - 1] + "+", f"T{q**2 - 1}").replace( + br.quark_names[q - 1] + "-", f"V{q**2 - 1}" ) return k diff --git a/tests/ekore/anomalous_dimensions/polarized/space_like/test_ad_as2.py b/tests/ekore/anomalous_dimensions/polarized/space_like/test_ad_as2.py index 06ed35541..19b48f0c9 100755 --- a/tests/ekore/anomalous_dimensions/polarized/space_like/test_ad_as2.py +++ b/tests/ekore/anomalous_dimensions/polarized/space_like/test_ad_as2.py @@ -34,10 +34,7 @@ def test_qg_momentum(): cache = harmonics.cache.reset() np.testing.assert_allclose( -as2.gamma_qg(N, nf, cache), - 4 - * nf - * (0.574074 * CF - 2 * CA * (-7 / 18 + 1 / 6 * (5 - np.pi**2 / 3))) - * TR, + 4 * nf * (0.574074 * CF - 2 * CA * (-7 / 18 + 1 / 6 * (5 - np.pi**2 / 3))) * TR, ) @@ -60,8 +57,7 @@ def test_gg_momentum(): cache = harmonics.cache.reset() np.testing.assert_almost_equal( -as2.gamma_gg(N, nf, cache), - 4 - * (-1.7537256813471833 * CA**2 + ((29 * CA) / 27 - (28 * CF) / 27) * nf * TR), + 4 * (-1.7537256813471833 * CA**2 + ((29 * CA) / 27 - (28 * CF) / 27) * nf * TR), ) diff --git a/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_init.py b/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_init.py index f726f5248..487653b98 100644 --- a/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_init.py +++ b/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_init.py @@ -118,7 +118,12 @@ def test_gamma_ns(): # as4 assert_allclose( ad_us.gamma_ns( - (4, 0), br.non_singlet_pids_map["ns-"], 1, nf, n3lo_ad_variation, use_fhmruvv = False + (4, 0), + br.non_singlet_pids_map["ns-"], + 1, + nf, + n3lo_ad_variation, + use_fhmruvv=False, ), np.zeros(4), atol=2e-4, @@ -126,7 +131,12 @@ def test_gamma_ns(): # N3LO valence has a spurious pole, need to add a small shift assert_allclose( ad_us.gamma_ns( - (4, 0), br.non_singlet_pids_map["nsV"], 1 + 1e-6, nf, n3lo_ad_variation, use_fhmruvv = False + (4, 0), + br.non_singlet_pids_map["nsV"], + 1 + 1e-6, + nf, + n3lo_ad_variation, + use_fhmruvv=False, ), np.zeros(4), atol=5e-4, From a4f8b371f9720b6dfc6ded975cb210b73c12ecd5 Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Mon, 13 Jan 2025 11:23:10 +0200 Subject: [PATCH 6/9] Undo EKOFactory bug --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 8ce700e46..4ff7a8224 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -90,7 +90,7 @@ def _create(self): lx = len(self.operator.xgrid) lpids = len(self.operator.pids) for mu2, op in self._operators( - mugrid=self.operator.evolgrid, shape=(lpids, lx, lpids, lx) + mugrid=self.operator.evolgrid, shape=(lpids, lx) ).items(): self.cache[mu2] = op From dc3e725def3866716e98c90b2225732f321b790c Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Mon, 13 Jan 2025 11:32:12 +0200 Subject: [PATCH 7/9] Recover benchmarks --- benchmarks/eko/benchmark_evol_to_unity.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/benchmarks/eko/benchmark_evol_to_unity.py b/benchmarks/eko/benchmark_evol_to_unity.py index c466d00d8..abe659730 100644 --- a/benchmarks/eko/benchmark_evol_to_unity.py +++ b/benchmarks/eko/benchmark_evol_to_unity.py @@ -1,4 +1,5 @@ import pathlib +from dataclasses import dataclass import numpy as np import pytest @@ -10,11 +11,17 @@ from eko.io.runcards import OperatorCard, TheoryCard from eko.matchings import Segment from eko.quantities.couplings import CouplingsInfo -from eko.runner.legacy import Runner +from eko.runner.parts import _evolve_configs, _managers # from ekore.matching_conditions.operator_matrix_element import OperatorMatrixElement +@dataclass(frozen=True) +class FakeEKO: + theory_card: TheoryCard + operator_card: OperatorCard + + def update_cards(theory: TheoryCard, operator: OperatorCard): theory.couplings = CouplingsInfo( alphas=0.35, @@ -44,16 +51,12 @@ def test_operator_grid( ): """Test that eko_forward @ eko_backward gives ID matrix or zeros.""" update_cards(theory_card, operator_card) - g = Runner( - theory_card=theory_card, - operators_card=operator_card, - path=tmp_path / "eko.tar", - ).op_grid + f = FakeEKO(theory_card, operator_card) seg = Segment(30, 50, 4) seg_back = Segment(50, 30, 4) - o = Operator(g.config, g.managers, seg) - o_back = Operator(g.config, g.managers, seg_back) + o = Operator(_evolve_configs(f), _managers(f), seg) + o_back = Operator(_evolve_configs(f), _managers(f), seg_back) o.compute() o_back.compute() From 29c401d078d96bc296ce9dfbdc903f10c04a6d16 Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Mon, 13 Jan 2025 13:19:34 +0200 Subject: [PATCH 8/9] Remove ev_op/grid --- benchmarks/eko/benchmark_evol_to_unity.py | 2 - doc/source/code/Operators.rst | 12 -- src/eko/evolution_operator/__init__.py | 23 +- src/eko/evolution_operator/grid.py | 204 ------------------ .../operator_matrix_element.py | 16 +- src/eko/runner/parts.py | 5 +- tests/eko/evolution_operator/test_grid.py | 55 ----- 7 files changed, 35 insertions(+), 282 deletions(-) delete mode 100644 src/eko/evolution_operator/grid.py delete mode 100644 tests/eko/evolution_operator/test_grid.py diff --git a/benchmarks/eko/benchmark_evol_to_unity.py b/benchmarks/eko/benchmark_evol_to_unity.py index abe659730..3526c56b4 100644 --- a/benchmarks/eko/benchmark_evol_to_unity.py +++ b/benchmarks/eko/benchmark_evol_to_unity.py @@ -1,4 +1,3 @@ -import pathlib from dataclasses import dataclass import numpy as np @@ -47,7 +46,6 @@ def test_operator_grid( self, theory_card: TheoryCard, operator_card: OperatorCard, - tmp_path: pathlib.Path, ): """Test that eko_forward @ eko_backward gives ID matrix or zeros.""" update_cards(theory_card, operator_card) diff --git a/doc/source/code/Operators.rst b/doc/source/code/Operators.rst index c58a64b37..b7c6a7250 100644 --- a/doc/source/code/Operators.rst +++ b/doc/source/code/Operators.rst @@ -19,10 +19,7 @@ The classes are nested as follows: PhysicalOperator [label="PhysicalOperator"]; Operator [label="Operator" ]; OME [label="OME" ]; - OperatorGrid [label="OperatorGrid"]; - OperatorGrid -> Operator; - OperatorGrid -> OME; Operator -> PhysicalOperator [weight=100,style=dashed]; PhysicalOperator -> ndarray [style=dashed]; OME -> MatchingCondition [weight=100,style=dashed]; @@ -31,17 +28,8 @@ The classes are nested as follows: OpMember -> PhysicalOperator [dir=back]; OME -> OpMember; OpMember -> MatchingCondition [dir=back]; - - OperatorGrid -> OpMember -> ndarray [style=invis]; } -- :class:`~eko.evolution_operator.grid.OperatorGrid` - - * is the master class which administrates all operator tasks - * is instantiated once for each run - * holds all necessary :doc:`configurations ` - * holds all necessary instances of the :doc:`/code/Utilities` - - :class:`~eko.evolution_operator.Operator` * represents a configuration for a fixed final scale :math:`Q_1^2` diff --git a/src/eko/evolution_operator/__init__.py b/src/eko/evolution_operator/__init__.py index bd1b19d65..366f934c9 100644 --- a/src/eko/evolution_operator/__init__.py +++ b/src/eko/evolution_operator/__init__.py @@ -7,6 +7,7 @@ import logging import os import time +from dataclasses import dataclass from multiprocessing import Pool from typing import Dict, Tuple @@ -21,6 +22,8 @@ from .. import basis_rotation as br from .. import interpolation, mellin from .. import scale_variations as sv +from ..couplings import Couplings +from ..interpolation import InterpolatorDispatcher from ..io.types import EvolutionMethod, OperatorLabel from ..kernels import ev_method from ..kernels import non_singlet as ns @@ -28,7 +31,7 @@ from ..kernels import singlet as s from ..kernels import singlet_qed as qed_s from ..kernels import valence_qed as qed_v -from ..matchings import Segment, lepton_number +from ..matchings import Atlas, Segment, lepton_number from ..member import OpMember from ..scale_variations import expanded as sv_expanded from ..scale_variations import exponentiated as sv_exponentiated @@ -608,6 +611,15 @@ def quad_ker_qed( """Map of all operators.""" +@dataclass(frozen=True) +class Managers: + """Set of steering objects.""" + + atlas: Atlas + couplings: Couplings + interpolator: InterpolatorDispatcher + + class Operator(sv.ScaleVariationModeMixin): """Internal representation of a single EKO. @@ -637,7 +649,12 @@ class Operator(sv.ScaleVariationModeMixin): full_labels_qed: Tuple[OperatorLabel, ...] = br.full_unified_labels def __init__( - self, config, managers, segment: Segment, mellin_cut=5e-2, is_threshold=False + self, + config, + managers: Managers, + segment: Segment, + mellin_cut=5e-2, + is_threshold=False, ): self.config = config self.managers = managers @@ -669,7 +686,7 @@ def xif2(self): return self.config["xif2"] @property - def int_disp(self): + def int_disp(self) -> InterpolatorDispatcher: """Return the interpolation dispatcher.""" return self.managers.interpolator diff --git a/src/eko/evolution_operator/grid.py b/src/eko/evolution_operator/grid.py deleted file mode 100644 index 9279e1f66..000000000 --- a/src/eko/evolution_operator/grid.py +++ /dev/null @@ -1,204 +0,0 @@ -"""Define operators container and computing workflow. - -The first is the driver class of eko as it is the one that collects all -the previously instantiated information and does the actual computation -of the Q2s. -""" - -import logging -from dataclasses import dataclass -from typing import Any, Dict, List, Optional - -import numpy as np -import numpy.typing as npt - -from .. import member -from .. import scale_variations as sv -from ..couplings import Couplings -from ..interpolation import InterpolatorDispatcher -from ..io.runcards import Configs, Debug -from ..io.types import EvolutionPoint as EPoint -from ..io.types import Order, SquaredScale -from ..matchings import Atlas, Segment, flavor_shift, is_downward_path -from . import Operator, OpMembers, flavors, matching_condition, physical -from .operator_matrix_element import OperatorMatrixElement - -logger = logging.getLogger(__name__) - -OpDict = Dict[str, Optional[npt.NDArray]] -"""In particular, only the ``operator`` and ``error`` fields are expected.""" - - -@dataclass(frozen=True) -class Managers: - """Set of steering objects.""" - - atlas: Atlas - couplings: Couplings - interpolator: InterpolatorDispatcher - - -class OperatorGrid(sv.ScaleVariationModeMixin): - """Collection of evolution operators for several scales. - - The operator grid is the driver class of the evolution. - - It receives as input a threshold holder and a generator of a_s. - From that point onwards it can compute any operator at any q2. - - Attributes - ---------- - config: dict - q2_grid: np.ndarray - managers: dict - """ - - def __init__( - self, - mu2grid: List[EPoint], - order: Order, - masses: List[float], - mass_scheme, - thresholds_ratios: List[float], - xif: float, - n3lo_ad_variation: tuple, - matching_order: Order, - configs: Configs, - debug: Debug, - atlas: Atlas, - couplings: Couplings, - interpol_dispatcher: InterpolatorDispatcher, - use_fhmruvv: bool, - ): - # check - config: Dict[str, Any] = {} - config["order"] = order - config["xif2"] = xif**2 - config["HQ"] = mass_scheme - config["ModSV"] = configs.scvar_method - config["n3lo_ad_variation"] = n3lo_ad_variation - config["use_fhmruvv"] = use_fhmruvv - - for i, q in enumerate("cbt"): - config[f"m{q}"] = masses[i] - config["thresholds_ratios"] = thresholds_ratios - method = config["method"] = configs.evolution_method.value - config["backward_inversion"] = configs.inversion_method - config["ev_op_max_order"] = configs.ev_op_max_order - config["ev_op_iterations"] = configs.ev_op_iterations - config["n_integration_cores"] = configs.n_integration_cores - config["debug_skip_singlet"] = debug.skip_singlet - config["debug_skip_non_singlet"] = debug.skip_non_singlet - config["polarized"] = configs.polarized - config["time_like"] = configs.time_like - config["matching_order"] = matching_order - - if order == (1, 0) and method != "iterate-exact": - logger.warning("Evolution: In LO we use the exact solution always!") - - logger.info(dict(polarized=configs.polarized)) - logger.info(dict(time_like=configs.time_like)) - - self.config = config - self.q2_grid = mu2grid - self.managers = Managers( - atlas=atlas, - couplings=couplings, - interpolator=interpol_dispatcher, - ) - self._threshold_operators: Dict[Segment, Operator] = {} - self._matching_operators: Dict[SquaredScale, OpMembers] = {} - - def get_threshold_operators(self, path: List[Segment]) -> List[Operator]: - """Generate the threshold operators. - - This method is called everytime the OperatorGrid is asked for a - grid on Q^2 with a list of the relevant areas. If new threshold - operators need to be computed, they will be cached in an - internal dictionary. - - The internal dictionary is self._threshold_operators and its - structure is: (q2_from, q2_to) -> eko.operators.Operator - - It computes and stores the necessary macthing operators. - """ - # The base area is always that of the reference q - thr_ops = [] - # is_downward point to smaller nf - is_downward = is_downward_path(path) - shift = flavor_shift(is_downward) - for seg in path[:-1]: - kthr = self.config["thresholds_ratios"][seg.nf - shift] - ome = OperatorMatrixElement( - self.config, - self.managers, - seg.nf - shift + 3, - seg.target, - is_downward, - np.log(kthr), - self.config["HQ"] == "MSBAR", - ) - if seg not in self._threshold_operators: - # Compute the operator and store it - logger.info("Prepare threshold operator") - op_th = Operator(self.config, self.managers, seg, is_threshold=True) - op_th.compute() - self._threshold_operators[seg] = op_th - thr_ops.append(self._threshold_operators[seg]) - - # Compute the matching conditions and store it - if seg.target not in self._matching_operators: - ome.compute() - self._matching_operators[seg.target] = ome.op_members - return thr_ops - - def compute(self) -> Dict[EPoint, dict]: - """Compute all ekos for the `q2grid`.""" - return {q2: self.generate(q2) for q2 in self.q2_grid} - - def generate(self, q2: EPoint) -> OpDict: - r"""Compute a single EKO. - - eko :math:`\mathbf E(Q^2 \leftarrow Q_0^2)` in flavor basis as - numpy array. - """ - # The lists of areas as produced by the thresholds - path = self.managers.atlas.path(q2) - # Prepare the path for the composition of the operator - thr_ops = self.get_threshold_operators(path) - # we start composing with the highest operator ... - operator = Operator(self.config, self.managers, path[-1]) - operator.compute() - - is_downward = is_downward_path(path) - qed = self.config["order"][1] > 0 - - final_op = physical.PhysicalOperator.ad_to_evol_map( - operator.op_members, operator.nf, operator.q2_to, qed - ) - # and multiply the lower ones from the right - for op in reversed(list(thr_ops)): - phys_op = physical.PhysicalOperator.ad_to_evol_map( - op.op_members, op.nf, op.q2_to, qed - ) - - # join with the basis rotation, since matching requires c+ (or likewise) - nf_match = op.nf - 1 if is_downward else op.nf - matching = matching_condition.MatchingCondition.split_ad_to_evol_map( - self._matching_operators[op.q2_to], - nf_match, - op.q2_to, - qed=qed, - ) - if is_downward: - invrot = member.ScalarOperator.promote_names( - flavors.rotate_matching_inverse(op.nf, qed), op.q2_to - ) - final_op = final_op @ matching @ invrot @ phys_op - else: - rot = member.ScalarOperator.promote_names( - flavors.rotate_matching(op.nf + 1, qed), op.q2_to - ) - final_op = final_op @ rot @ matching @ phys_op - values, errors = final_op.to_flavor_basis_tensor(qed) - return {"operator": values, "error": errors} diff --git a/src/eko/evolution_operator/operator_matrix_element.py b/src/eko/evolution_operator/operator_matrix_element.py index 098b52db2..e7d51df9f 100644 --- a/src/eko/evolution_operator/operator_matrix_element.py +++ b/src/eko/evolution_operator/operator_matrix_element.py @@ -5,6 +5,7 @@ import enum import functools import logging +from typing import Optional import numba as nb import numpy as np @@ -18,7 +19,7 @@ from ..io.types import InversionMethod from ..matchings import Segment from ..scale_variations.exponentiated import gamma_variation -from . import Operator, QuadKerBase +from . import Managers, Operator, QuadKerBase logger = logging.getLogger(__name__) @@ -31,7 +32,7 @@ class MatchingMethods(enum.IntEnum): BACKWARD_EXPANDED = enum.auto() -def matching_method(s: InversionMethod) -> MatchingMethods: +def matching_method(s: Optional[InversionMethod]) -> MatchingMethods: """Return the matching method. Parameters @@ -241,7 +242,16 @@ class OperatorMatrixElement(Operator): # still valid in QED since Sdelta and Vdelta matchings are diagonal full_labels_qed = copy.deepcopy(full_labels) - def __init__(self, config, managers, nf, q2, is_backward, L, is_msbar): + def __init__( + self, + config, + managers: Managers, + nf: int, + q2: float, + is_backward: bool, + L: float, + is_msbar: bool, + ): super().__init__(config, managers, Segment(q2, q2, nf)) self.backward_method = matching_method( config["backward_inversion"] if is_backward else None diff --git a/src/eko/runner/parts.py b/src/eko/runner/parts.py index 002caddde..96c4d9ace 100644 --- a/src/eko/runner/parts.py +++ b/src/eko/runner/parts.py @@ -15,14 +15,13 @@ from .. import evolution_operator as evop from ..evolution_operator import matching_condition, physical from ..evolution_operator import operator_matrix_element as ome -from ..evolution_operator.grid import Managers from ..io import EKO from ..io.items import Evolution, Matching, Operator from ..quantities.heavy_quarks import QuarkMassScheme from . import commons -def _managers(eko: EKO) -> Managers: +def _managers(eko: EKO) -> evop.Managers: """Collect managers for operator computation. .. todo:: @@ -31,7 +30,7 @@ def _managers(eko: EKO) -> Managers: """ tcard = eko.theory_card ocard = eko.operator_card - return Managers( + return evop.Managers( atlas=commons.atlas(tcard, ocard), couplings=commons.couplings(tcard, ocard), interpolator=commons.interpolator(ocard), diff --git a/tests/eko/evolution_operator/test_grid.py b/tests/eko/evolution_operator/test_grid.py deleted file mode 100644 index f06c152fc..000000000 --- a/tests/eko/evolution_operator/test_grid.py +++ /dev/null @@ -1,55 +0,0 @@ -"""Checks that the operator grid works as intended. - -These test can be slow as they require the computation of several values -of Q But they should be fast as the grid is very small. It does *not* -test whether the result is correct, it can just test that it is sane -""" - - -# from eko.runner import legacy - -# def test_compute_mu2grid(theory_ffns, operator_card, tmp_path): -# mugrid = [(10.0, 5), (100.0, 5)] -# operator_card.mugrid = mugrid -# opgrid = legacy.Runner( -# theory_ffns(3), operator_card, path=tmp_path / "eko.tar" -# ).op_grid -# opg = opgrid.compute() -# assert len(opg) == len(mugrid) -# assert all(k in op for k in ["operator", "error"] for op in opg.values()) - - -# def test_grid_computation_VFNS(theory_card, operator_card, tmp_path): -# """Checks that the grid can be computed.""" -# mugrid = [(3, 4), (5, 5), (5, 4)] -# operator_card.mugrid = mugrid -# opgrid = legacy.Runner( -# theory_card, operator_card, path=tmp_path / "eko.tar" -# ).op_grid -# operators = opgrid.compute() -# assert len(operators) == len(mugrid) - - -# def test_mod_expanded(theory_card, theory_ffns, operator_card, tmp_path: pathlib.Path): -# mugrid = [(3, 4)] -# operator_card.mugrid = mugrid -# operator_card.configs.scvar_method = eko.io.types.ScaleVariationsMethod.EXPANDED -# epsilon = 1e-1 -# path = tmp_path / "eko.tar" -# for is_ffns, nf0 in zip([False, True], [5, 3]): -# if is_ffns: -# theory = theory_ffns(nf0) -# else: -# theory = theory_card -# theory.order = (1, 0) -# operator_card.init = (operator_card.init[0], nf0) -# path.unlink(missing_ok=True) -# opgrid = legacy.Runner(theory, operator_card, path=path).op_grid -# opg = opgrid.compute() -# theory.xif = 1.0 + epsilon -# path.unlink(missing_ok=True) -# sv_opgrid = legacy.Runner(theory, operator_card, path=path).op_grid -# sv_opg = sv_opgrid.compute() -# np.testing.assert_allclose( -# opg[(9, 4)]["operator"], sv_opg[(9, 4)]["operator"], atol=2.5 * epsilon -# ) From eb347df0a1ee4bc7f75f6d8abab56a18e8be83ec Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Mon, 13 Jan 2025 14:02:36 +0200 Subject: [PATCH 9/9] Recover rustify --- src/eko/evolution_operator/__init__.py.patch | 40 +++++++++++++------ .../operator_matrix_element.py.patch | 17 ++++---- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/eko/evolution_operator/__init__.py.patch b/src/eko/evolution_operator/__init__.py.patch index a4951e687..5be808c60 100644 --- a/src/eko/evolution_operator/__init__.py.patch +++ b/src/eko/evolution_operator/__init__.py.patch @@ -1,8 +1,8 @@ diff --git a/src/eko/evolution_operator/__init__.py b/src/eko/evolution_operator/__init__.py -index bd1b19d6..f543f7bc 100644 +index 366f934c..73edf44f 100644 --- a/src/eko/evolution_operator/__init__.py +++ b/src/eko/evolution_operator/__init__.py -@@ -3,16 +3,16 @@ r"""Contains the central operator classes. +@@ -3,7 +3,6 @@ r"""Contains the central operator classes. See :doc:`Operator overview `. """ @@ -10,6 +10,7 @@ index bd1b19d6..f543f7bc 100644 import logging import os import time +@@ -11,13 +10,10 @@ from dataclasses import dataclass from multiprocessing import Pool from typing import Dict, Tuple @@ -17,14 +18,28 @@ index bd1b19d6..f543f7bc 100644 import numba as nb import numpy as np -from scipy import integrate +- +-import ekore.anomalous_dimensions.polarized.space_like as ad_ps +-import ekore.anomalous_dimensions.unpolarized.space_like as ad_us +-import ekore.anomalous_dimensions.unpolarized.time_like as ad_ut +from scipy import LowLevelCallable, integrate - import ekore.anomalous_dimensions.polarized.space_like as ad_ps - import ekore.anomalous_dimensions.unpolarized.space_like as ad_us -@@ -32,91 +32,10 @@ from ..matchings import Segment, lepton_number + from .. import basis_rotation as br + from .. import interpolation, mellin +@@ -26,100 +22,12 @@ from ..couplings import Couplings + from ..interpolation import InterpolatorDispatcher + from ..io.types import EvolutionMethod, OperatorLabel + from ..kernels import ev_method +-from ..kernels import non_singlet as ns +-from ..kernels import non_singlet_qed as qed_ns +-from ..kernels import singlet as s +-from ..kernels import singlet_qed as qed_s +-from ..kernels import valence_qed as qed_v +-from ..matchings import Atlas, Segment, lepton_number ++from ..matchings import Atlas, Segment from ..member import OpMember - from ..scale_variations import expanded as sv_expanded - from ..scale_variations import exponentiated as sv_exponentiated +-from ..scale_variations import expanded as sv_expanded +-from ..scale_variations import exponentiated as sv_exponentiated +from .quad_ker import cb_quad_ker_qcd logger = logging.getLogger(__name__) @@ -114,7 +129,7 @@ index bd1b19d6..f543f7bc 100644 spec = [ ("is_singlet", nb.boolean), ("is_QEDsinglet", nb.boolean), -@@ -188,421 +107,6 @@ class QuadKerBase: +@@ -191,422 +99,6 @@ class QuadKerBase: return self.path.prefactor * pj * self.path.jac @@ -533,10 +548,11 @@ index bd1b19d6..f543f7bc 100644 - ) - return ker - - +- OpMembers = Dict[OperatorLabel, OpMember] """Map of all operators.""" -@@ -792,49 +296,6 @@ class Operator(sv.ScaleVariationModeMixin): + +@@ -809,49 +301,6 @@ class Operator(sv.ScaleVariationModeMixin): """Return the evolution method.""" return ev_method(EvolutionMethod(self.config["method"])) @@ -586,7 +602,7 @@ index bd1b19d6..f543f7bc 100644 def initialize_op_members(self): """Init all operators with the identity or zeros.""" eye = OpMember( -@@ -857,10 +318,14 @@ class Operator(sv.ScaleVariationModeMixin): +@@ -874,10 +323,14 @@ class Operator(sv.ScaleVariationModeMixin): else: self.op_members[n] = zero.copy() @@ -605,7 +621,7 @@ index bd1b19d6..f543f7bc 100644 """Run the integration for each grid point. Parameters -@@ -875,18 +339,53 @@ class Operator(sv.ScaleVariationModeMixin): +@@ -892,18 +345,53 @@ class Operator(sv.ScaleVariationModeMixin): """ column = [] k, logx = log_grid diff --git a/src/eko/evolution_operator/operator_matrix_element.py.patch b/src/eko/evolution_operator/operator_matrix_element.py.patch index ef2f684e2..b664364a5 100644 --- a/src/eko/evolution_operator/operator_matrix_element.py.patch +++ b/src/eko/evolution_operator/operator_matrix_element.py.patch @@ -1,13 +1,14 @@ diff --git a/src/eko/evolution_operator/operator_matrix_element.py b/src/eko/evolution_operator/operator_matrix_element.py -index 098b52db..b56e27d1 100644 +index e7d51df9..0f999809 100644 --- a/src/eko/evolution_operator/operator_matrix_element.py +++ b/src/eko/evolution_operator/operator_matrix_element.py -@@ -3,22 +3,19 @@ evolution.""" +@@ -3,23 +3,19 @@ evolution.""" import copy import enum -import functools import logging + from typing import Optional +import ekors import numba as nb @@ -21,14 +22,14 @@ index 098b52db..b56e27d1 100644 from .. import scale_variations as sv from ..io.types import InversionMethod from ..matchings import Segment - from ..scale_variations.exponentiated import gamma_variation --from . import Operator, QuadKerBase -+from . import Operator +-from ..scale_variations.exponentiated import gamma_variation +-from . import Managers, Operator, QuadKerBase ++from . import Managers, Operator +from .quad_ker import cb_quad_ker_ome logger = logging.getLogger(__name__) -@@ -78,8 +75,6 @@ def build_ome(A, matching_order, a_s, backward_method): +@@ -79,8 +75,6 @@ def build_ome(A, matching_order, a_s, backward_method): # Print; # .end ome = np.eye(len(A[0]), dtype=np.complex_) @@ -37,7 +38,7 @@ index 098b52db..b56e27d1 100644 if backward_method is MatchingMethods.BACKWARD_EXPANDED: # expended inverse if matching_order[0] >= 1: -@@ -102,105 +97,6 @@ def build_ome(A, matching_order, a_s, backward_method): +@@ -103,105 +97,6 @@ def build_ome(A, matching_order, a_s, backward_method): return ome @@ -143,7 +144,7 @@ index 098b52db..b56e27d1 100644 class OperatorMatrixElement(Operator): r"""Internal representation of a single |OME|. -@@ -290,41 +186,15 @@ class OperatorMatrixElement(Operator): +@@ -300,41 +195,15 @@ class OperatorMatrixElement(Operator): ) return labels