raystrack 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
raystrack/params.py ADDED
@@ -0,0 +1,129 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import asdict, dataclass
4
+ from typing import Any, Dict
5
+
6
+
7
+ @dataclass
8
+ class MatrixParams:
9
+ """Configuration for scene-to-scene view-factor solves.
10
+
11
+ Parameters
12
+ ----------
13
+ samples : int
14
+ Quasi-Monte Carlo grid per side used for emission per emitter.
15
+ rays : int
16
+ Rays per grid cell.
17
+ seed : int
18
+ Base RNG seed. Each emitter/iteration derives its own sub-seed.
19
+ bvh : {"auto","off","builtin"}
20
+ Toggle a built-in BVH for faster visibility.
21
+ device : {"auto","gpu","cpu"}
22
+ Visibility device. GPU uses CUDA hitmask kernels. CPU uses numba njit.
23
+ cuda_async : bool
24
+ Use pinned memory + streams for overlap on CUDA.
25
+ gpu_raygen : bool
26
+ Generate rays on GPU to avoid H2D copies of rays.
27
+ max_iters : int
28
+ Maximum number of Monte-Carlo iterations.
29
+ tol : float
30
+ Convergence tolerance. Interpretation depends on ``tol_mode``.
31
+ tol_mode : {"delta", "stderr"}
32
+ - "delta": stop when successive cumulative estimates change by < tol.
33
+ - "stderr": stop when per-iteration replicate standard error is <= tol.
34
+ min_iters : int
35
+ Minimum number of Monte-Carlo iterations before a convergence check.
36
+ convergence_interval : int
37
+ Check convergence every N iterations. Values > 1 mainly help the CUDA
38
+ path by reducing host-side convergence work.
39
+ reciprocity : bool
40
+ Also compute inverse view factors via reciprocity.
41
+ enforce_reciprocity_rowsum : bool
42
+ After computation, enforce reciprocity and make each row sum to 1 using
43
+ symmetric diagonal scaling.
44
+ flip_faces : bool
45
+ If True, flip emitter triangle winding during emission sampling.
46
+ """
47
+ samples: int = 16
48
+ rays: int = 128
49
+ seed: int = 1
50
+ bvh: str = "auto"
51
+ device: str = "auto"
52
+ cuda_async: bool = True
53
+ gpu_raygen: bool = True
54
+ max_iters: int = 100
55
+ tol: float = 1e-4
56
+ tol_mode: str = "stderr"
57
+ min_iters: int = 5
58
+ convergence_interval: int = 1
59
+ reciprocity: bool = True
60
+ enforce_reciprocity_rowsum: bool = False
61
+ flip_faces: bool = False
62
+
63
+ def as_dict(self) -> Dict[str, Any]:
64
+ return asdict(self)
65
+
66
+ @classmethod
67
+ def from_dict(cls, data: Dict[str, Any]) -> "MatrixParams":
68
+ return cls(**data)
69
+
70
+
71
+ @dataclass
72
+ class SkyParams:
73
+ """Configuration for merged sky view-factor solves.
74
+
75
+ Parameters
76
+ ----------
77
+ samples : int
78
+ Quasi-Monte Carlo grid per side used for emission per emitter.
79
+ rays : int
80
+ Rays per grid cell.
81
+ seed : int
82
+ Base RNG seed. Each emitter/iteration derives its own sub-seed.
83
+ bvh : {"auto","off","builtin"}
84
+ Toggle a built-in BVH for faster visibility.
85
+ device : {"auto","gpu","cpu"}
86
+ Visibility device. GPU uses CUDA hitmask kernels. CPU uses numba njit.
87
+ cuda_async : bool
88
+ Use pinned memory + streams for overlap on CUDA.
89
+ gpu_raygen : bool
90
+ Generate rays on GPU to avoid H2D copies of rays.
91
+ max_iters : int
92
+ Maximum number of Monte-Carlo iterations.
93
+ tol : float
94
+ Convergence tolerance. Interpretation depends on ``tol_mode``.
95
+ tol_mode : {"delta", "stderr"}
96
+ - "delta": stop when successive cumulative estimates change by < tol.
97
+ - "stderr": stop when per-iteration replicate standard error is <= tol.
98
+ min_iters : int
99
+ Minimum number of Monte-Carlo iterations before a convergence check.
100
+ convergence_interval : int
101
+ Check convergence every N iterations. Values > 1 mainly help the CUDA
102
+ path by reducing host-side convergence work.
103
+ discrete : bool
104
+ If True, return 145 directional patches. If False, return a single
105
+ merged "Sky" entry.
106
+ """
107
+ samples: int = 16
108
+ rays: int = 128
109
+ seed: int = 1
110
+ bvh: str = "auto"
111
+ device: str = "auto"
112
+ cuda_async: bool = True
113
+ gpu_raygen: bool = True
114
+ max_iters: int = 100
115
+ tol: float = 1e-4
116
+ tol_mode: str = "stderr"
117
+ min_iters: int = 5
118
+ convergence_interval: int = 1
119
+ discrete: bool = False
120
+
121
+ def as_dict(self) -> Dict[str, Any]:
122
+ return asdict(self)
123
+
124
+ @classmethod
125
+ def from_dict(cls, data: Dict[str, Any]) -> "SkyParams":
126
+ return cls(**data)
127
+
128
+
129
+ __all__ = ["MatrixParams", "SkyParams"]
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ """Utility subpackage exports.
4
+
5
+ This module re-exports commonly used helpers so callers can do:
6
+ from raystrack.utils import cached_halton, flatten_receivers, build_rays
7
+
8
+ Keeping imports light: avoid importing CUDA-specific modules here so that the
9
+ package imports cleanly on systems without CUDA. Heavy modules are loaded on
10
+ first use by their direct importers.
11
+ """
12
+
13
+ # Lightweight, CPU-safe helpers
14
+ from .halton import cached_halton # noqa: F401
15
+ from .geometry import flatten_receivers, flip_meshes # noqa: F401
16
+ from .ray_builder import build_rays # noqa: F401
17
+
18
+ __all__ = [
19
+ "cached_halton",
20
+ "flatten_receivers",
21
+ "flip_meshes",
22
+ "build_rays",
23
+ ]
raystrack/utils/bvh.py ADDED
@@ -0,0 +1,74 @@
1
+ from __future__ import annotations
2
+ import numpy as np
3
+
4
+ LEAF_SIZE = 8 # triangles per leaf
5
+
6
+
7
+ def _tri_bounds(p0: np.ndarray, p1: np.ndarray, p2: np.ndarray):
8
+ bmin = np.minimum(np.minimum(p0, p1), p2)
9
+ bmax = np.maximum(np.maximum(p0, p1), p2)
10
+ centroid = (p0 + p1 + p2) / 3.0
11
+ return bmin.astype(np.float32), bmax.astype(np.float32), centroid.astype(np.float32)
12
+
13
+
14
+ def build_bvh(v0: np.ndarray, e1: np.ndarray, e2: np.ndarray,
15
+ leaf_size: int = LEAF_SIZE):
16
+ """Return BVH arrays and triangle permutation."""
17
+ m = v0.shape[0]
18
+ tmin = np.empty((m, 3), np.float32)
19
+ tmax = np.empty((m, 3), np.float32)
20
+ cent = np.empty((m, 3), np.float32)
21
+ for i in range(m):
22
+ p0 = v0[i]
23
+ p1 = v0[i] + e1[i]
24
+ p2 = v0[i] + e2[i]
25
+ bmin, bmax, c = _tri_bounds(p0, p1, p2)
26
+ tmin[i] = bmin
27
+ tmax[i] = bmax
28
+ cent[i] = c
29
+
30
+ bb_min, bb_max = [], []
31
+ left, right = [], []
32
+ start, count = [], []
33
+ order: list[int] = []
34
+
35
+ def add_node(idxs: np.ndarray) -> int:
36
+ node = len(bb_min)
37
+ bb_min.append(np.zeros(3, np.float32))
38
+ bb_max.append(np.zeros(3, np.float32))
39
+ left.append(-1)
40
+ right.append(-1)
41
+ start.append(0)
42
+ count.append(0)
43
+
44
+ bmin = tmin[idxs].min(axis=0)
45
+ bmax = tmax[idxs].max(axis=0)
46
+ bb_min[node][:] = bmin
47
+ bb_max[node][:] = bmax
48
+
49
+ if len(idxs) <= leaf_size:
50
+ start[node] = len(order)
51
+ count[node] = len(idxs)
52
+ order.extend(idxs.tolist())
53
+ else:
54
+ ext = bmax - bmin
55
+ axis = int(np.argmax(ext))
56
+ idxs_sorted = idxs[np.argsort(cent[idxs, axis])]
57
+ mid = idxs_sorted.size // 2
58
+ l = add_node(idxs_sorted[:mid])
59
+ r = add_node(idxs_sorted[mid:])
60
+ left[node] = l
61
+ right[node] = r
62
+ return node
63
+
64
+ add_node(np.arange(m, dtype=np.int32))
65
+ perm = np.array(order, dtype=np.int32)
66
+ return (np.asarray(bb_min, np.float32),
67
+ np.asarray(bb_max, np.float32),
68
+ np.asarray(left, np.int32),
69
+ np.asarray(right, np.int32),
70
+ np.asarray(start, np.int32),
71
+ np.asarray(count, np.int32),
72
+ perm)
73
+
74
+ __all__ = ["build_bvh", "LEAF_SIZE"]