Skip to content

Commit

Permalink
API: reduce size of wheels:
Browse files Browse the repository at this point in the history
- merge cython source files (reduce disk overhead from generated boilerplate code)
- exclude unused Python implementation of core algorithm from distributions
  • Loading branch information
neutrinoceros committed Jun 29, 2024
1 parent cdff96c commit 5dc7c07
Show file tree
Hide file tree
Showing 14 changed files with 362 additions and 219 deletions.
18 changes: 15 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
python -m build
unit-tests:
name: ${{matrix.os}} x py${{matrix.python-version}} ${{matrix.marker}}
strategy:
matrix:
os:
Expand All @@ -44,17 +45,24 @@ jobs:
- '3.10'
- '3.11'
- '3.12'

include:
- os: macos-latest
python-version: '3.12'
- os: windows-latest
python-version: '3.12'

# test with minimal requirements
- os: ubuntu-20.04
- marker: minimal
os: ubuntu-20.04
python-version: '3.10'
deps: minimal

# test GPGI_PY_LIB
#- marker: PY_LIB
# os: ubuntu-latest
# python-version: '3.12'

runs-on: ${{ matrix.os }}
steps:
- name: Checkout Source
Expand All @@ -73,8 +81,12 @@ jobs:
python -m pip install --requirement mindeps.txt
- name: Build library
env:
GPGI_PY_LIB: ${{ matrix.marker == 'PY_LIB' }}
# install in editable mode to allow coverage measurement
run: python -m pip install --editable .
run: |
echo GPGI_PY_LIB=$GPGI_PY_LIB
python -m pip install --editable .
- run: python -m pip install --requirement requirements/tests.txt

Expand All @@ -91,7 +103,7 @@ jobs:
if: matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v4
with:
name: gpgi_coverage_data-${{ matrix.os }}-${{ matrix.python-version }}
name: gpgi_coverage_data-${{matrix.os}}-${{matrix.python-version}}-${{matrix.marker}}
path: .coverage.*
if-no-files-found: ignore

Expand Down
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ __pycache__
MANIFEST
build
dist
src/gpgi/clib/*.html
src/gpgi/clib/*.so
src/gpgi/clib/*.c
src/gpgi/_lib.html
src/gpgi/_lib.*.so
src/gpgi/_lib.c
6 changes: 4 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
include LICENCE
include src/gpgi/py.typed
include src/gpgi/clib/*.pyx
exclude src/gpgi/clib/*.c
include src/gpgi/_lib.pyi
include src/gpgi/_lib.pyx
exclude src/gpgi/_lib.c
exclude src/gpgi/_lib.py

recursive-exclude tests *
exclude .pre-commit-config.yaml
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "gpgi"
version = "1.0.0"
version = "2.0.dev0"
description = "A Generic Particle+Grid Interface"
authors = [
{ name = "C.M.T. Robert" },
Expand Down Expand Up @@ -56,7 +56,7 @@ include = [
omit = [
"src/gpgi/_backports.py",
"src/gpgi/_typing.py",
"src/gpgi/lib/*.py",
"src/gpgi/_lib.py",
]

[tool.coverage.report]
Expand Down
50 changes: 27 additions & 23 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
import os
from distutils.extension import Extension
from pathlib import Path

import numpy
import numpy as np
from Cython.Build import cythonize
from setuptools import setup

SRC_DIR = Path(__file__).parent / "src" / "gpgi"

def make_ext(path: str) -> Extension:
name, _ = os.path.splitext(path)
name = name.replace("/", ".")

return Extension(
name,
sources=[f"src/{path}"],
include_dirs=[numpy.get_include()],
define_macros=[
# keep in sync with runtime requirements (pyproject.toml)
("NPY_TARGET_VERSION", "NPY_1_23_API_VERSION"),
("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION"),
],
)


setup(
ext_modules=cythonize(
if os.getenv("GPGI_PY_LIB", "0").lower() in ("1", "true"):
if not SRC_DIR.joinpath("_lib.py").exists():
raise RuntimeError(
"GPGI's pure Python implementation can only be built "
"from the development version in editable mode."
)
ext_modules = []
for sofile in SRC_DIR.glob("*.so"):
os.remove(sofile)
else:
ext_modules = cythonize(
[
make_ext("gpgi/clib/_indexing.pyx"),
make_ext("gpgi/clib/_deposition_methods.pyx"),
Extension(
"gpgi._lib",
sources=["src/gpgi/_lib.pyx"],
include_dirs=[np.get_include()],
define_macros=[
# keep in sync with runtime requirements (pyproject.toml)
("NPY_TARGET_VERSION", "NPY_1_23_API_VERSION"),
("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION"),
],
)
],
compiler_directives={"language_level": 3},
),
)
)

setup(ext_modules=ext_modules)
2 changes: 0 additions & 2 deletions src/gpgi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

from .types import Dataset, FieldMap, Geometry, Grid, ParticleSet

__version__ = "1.0.0"


def load(
*,
Expand Down
79 changes: 78 additions & 1 deletion src/gpgi/lib/_deposition_methods.py → src/gpgi/_lib.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,81 @@
"""Python implementations of deposition algorithms (dev only)."""

import numpy as np


def _deposit_ngp(
def _index_particles(
cell_edges_x1,
cell_edges_x2,
cell_edges_x3,
particles_x1,
particles_x2,
particles_x3,
dx,
out,
):
if cell_edges_x3.shape[0] > 1:
ndim = 3
elif cell_edges_x2.shape[0] > 1:
ndim = 2
else:
ndim = 1

particle_count = particles_x1.shape[0]

for ipart in range(particle_count):
x = particles_x1[ipart]
if dx[0] > 0:
out[ipart, 0] = int((x - cell_edges_x1[0]) // dx[0])
else:
iL = 1
iR = cell_edges_x1.shape[0] - 2
idx = (iL + iR) // 2
while idx != iL:
if cell_edges_x1[idx] > x:
iR = idx
else:
iL = idx
idx = (iL + iR) // 2
out[ipart, 0] = idx

if ndim < 2:
continue

x = particles_x2[ipart]
if dx[1] > 0:
out[ipart, 1] = int((x - cell_edges_x2[0]) // dx[1])
else:
iL = 1
iR = cell_edges_x2.shape[00] - 2
idx = (iL + iR) // 2
while idx != iL:
if cell_edges_x2[idx] > x:
iR = idx
else:
iL = idx
idx = (iL + iR) // 2
out[ipart, 1] = idx

if ndim < 3:
continue

x = particles_x3[ipart]
if dx[2] > 0:
out[ipart, 2] = int((x - cell_edges_x3[0]) // dx[2])
else:
iL = 1
iR = cell_edges_x3.shape[0] - 2
idx = (iL + iR) // 2
while idx != iL:
if cell_edges_x3[idx] > x:
iR = idx
else:
iL = idx
idx = (iL + iR) // 2
out[ipart, 2] = idx


def _deposit_ngp_impl(
cell_edges_x1,
cell_edges_x2,
cell_edges_x3,
Expand All @@ -23,6 +97,9 @@ def _deposit_ngp(
out[md_idx] += field[ipart] * weight_field[ipart]


_deposit_ngp_1D = _deposit_ngp_2D = _deposit_ngp_3D = _deposit_ngp_impl


def _deposit_cic_1D(
cell_edges_x1,
cell_edges_x2,
Expand Down
124 changes: 124 additions & 0 deletions src/gpgi/_lib.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import numpy as np
from numpy.typing import NDArray

NDArrayReal = NDArray[np.float64 | np.float32]
NDArrayUInt = NDArray[np.uint16]

def _index_particles(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
dx: NDArrayReal,
out: NDArrayUInt,
) -> None: ...
def _deposit_ngp_1D(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
field: NDArrayReal,
weight_field: NDArrayReal,
hci: NDArrayUInt, # dim: 2
out: NDArrayReal,
) -> None: ...
def _deposit_ngp_2D(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
field: NDArrayReal,
weight_field: NDArrayReal,
hci: NDArrayUInt, # dim: 2
out: NDArrayReal,
) -> None: ...
def _deposit_ngp_3D(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
field: NDArrayReal,
weight_field: NDArrayReal,
hci: NDArrayUInt, # dim: 2
out: NDArrayReal,
) -> None: ...
def _deposit_cic_1D(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
field: NDArrayReal,
weight_field: NDArrayReal,
hci: NDArrayUInt, # dim: 2
out: NDArrayReal,
) -> None: ...
def _deposit_cic_2D(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
field: NDArrayReal,
weight_field: NDArrayReal,
hci: NDArrayUInt, # dim: 2
out: NDArrayReal,
) -> None: ...
def _deposit_cic_3D(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
field: NDArrayReal,
weight_field: NDArrayReal,
hci: NDArrayUInt, # dim: 2
out: NDArrayReal,
) -> None: ...
def _deposit_tsc_1D(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
field: NDArrayReal,
weight_field: NDArrayReal,
hci: NDArrayUInt, # dim: 2
out: NDArrayReal,
) -> None: ...
def _deposit_tsc_2D(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
field: NDArrayReal,
weight_field: NDArrayReal,
hci: NDArrayUInt, # dim: 2
out: NDArrayReal,
) -> None: ...
def _deposit_tsc_3D(
cell_edges_x1: NDArrayReal,
cell_edges_x2: NDArrayReal,
cell_edges_x3: NDArrayReal,
particles_x1: NDArrayReal,
particles_x2: NDArrayReal,
particles_x3: NDArrayReal,
field: NDArrayReal,
weight_field: NDArrayReal,
hci: NDArrayUInt, # dim: 2
out: NDArrayReal,
) -> None: ...
Loading

0 comments on commit 5dc7c07

Please sign in to comment.