redbirdpy 0.1.0__py3-none-any.whl → 0.2.0__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.
redbirdpy/__init__.py CHANGED
@@ -52,7 +52,7 @@ Author: Translated from Redbird MATLAB toolbox by Qianqian Fang (q.fang <at> neu
52
52
  License: GPL version 3
53
53
  """
54
54
 
55
- __version__ = "0.1.0"
55
+ __version__ = "0.2.0"
56
56
  __author__ = "Qianqian Fang"
57
57
 
58
58
  from . import forward
redbirdpy/solver.py CHANGED
@@ -3,11 +3,11 @@ Redbird Solver Module - Linear system solvers for FEM.
3
3
 
4
4
  Provides:
5
5
  femsolve: Main solver interface with automatic method selection
6
- get_solver_info: Query available solver backends
6
+ solverinfo: Query available solver backends
7
7
 
8
8
  Supported solvers:
9
9
  Direct: pardiso, umfpack, cholmod, superlu
10
- Iterative: blqmr, cg, cg+amg, gmres, bicgstab
10
+ Iterative: blqmr, cg, cg+amg, gmres, bicgstab, qmr, minres
11
11
 
12
12
  Dependencies:
13
13
  - blocksolver: For BLQMR iterative solver (complex symmetric systems)
@@ -15,16 +15,17 @@ Dependencies:
15
15
 
16
16
  __all__ = [
17
17
  "femsolve",
18
- "get_solver_info",
18
+ "solverinfo",
19
19
  ]
20
20
 
21
21
  import numpy as np
22
22
  from scipy import sparse
23
- from scipy.sparse.linalg import spsolve, cg, gmres, bicgstab, splu
23
+ from scipy.sparse.linalg import spsolve, cg, gmres, bicgstab, qmr, minres, splu
24
24
  from typing import Dict, Tuple, Optional, Union, List, Any
25
25
  import warnings
26
- from concurrent.futures import ProcessPoolExecutor
26
+ from multiprocessing import Pool
27
27
  import multiprocessing
28
+ import sys
28
29
 
29
30
  # =============================================================================
30
31
  # Solver Backend Detection
@@ -40,6 +41,21 @@ _HAS_BLQMR = False
40
41
  _pardiso_solve = None
41
42
  _pardiso_factorized = None
42
43
 
44
+
45
+ # Multiprocessing context - use 'spawn' for Python 3.14+ compatibility
46
+ # 'spawn' is safer and more portable, but 'fork' is faster on Unix (Python < 3.14)
47
+ def _get_mp_context():
48
+ """Get appropriate multiprocessing context based on Python version and platform."""
49
+ # Python 3.14+ or macOS: always use spawn for safety
50
+ if sys.version_info >= (3, 14) or sys.platform == "darwin":
51
+ return multiprocessing.get_context("spawn")
52
+ # Older Python on Linux: try fork first (faster), fallback to spawn
53
+ try:
54
+ return multiprocessing.get_context("fork")
55
+ except ValueError:
56
+ return multiprocessing.get_context("spawn")
57
+
58
+
43
59
  try:
44
60
  from pypardiso import spsolve as pardiso_solve, factorized as pardiso_factorized
45
61
 
@@ -121,11 +137,18 @@ def _solve_blqmr_batch(args):
121
137
  start_col,
122
138
  ) = args
123
139
 
124
- # Import blqmr in worker process
125
- from blocksolver import blqmr as worker_blqmr
140
+ # Import dependencies in worker process
141
+ try:
142
+ from blocksolver import blqmr as worker_blqmr
143
+ from scipy import sparse as worker_sparse
144
+ import numpy as worker_np
145
+ except ImportError as e:
146
+ raise ImportError(f"Worker process missing required imports: {e}")
126
147
 
127
148
  # Reconstruct sparse matrix in worker process
128
- A = sparse.csc_matrix((A_data, A_indices, A_indptr), shape=A_shape, dtype=A_dtype)
149
+ A = worker_sparse.csc_matrix(
150
+ (A_data, A_indices, A_indptr), shape=A_shape, dtype=A_dtype
151
+ )
129
152
 
130
153
  result = worker_blqmr(
131
154
  A,
@@ -146,7 +169,7 @@ def _solve_blqmr_batch(args):
146
169
 
147
170
  def _solve_iterative_column(args):
148
171
  """
149
- Worker function for parallel iterative solving (gmres, bicgstab, cg).
172
+ Worker function for parallel iterative solving (gmres, bicgstab, cg, qmr, minres).
150
173
 
151
174
  Solves a single RHS column using the specified iterative method.
152
175
  """
@@ -164,15 +187,17 @@ def _solve_iterative_column(args):
164
187
  use_amg,
165
188
  ) = args
166
189
 
167
- from scipy.sparse.linalg import gmres, bicgstab, cg
190
+ # Import dependencies in worker process
191
+ from scipy.sparse.linalg import gmres, bicgstab, cg, qmr, minres
168
192
  from scipy import sparse
193
+ import numpy as np
169
194
 
170
195
  # Reconstruct sparse matrix in worker process
171
196
  A = sparse.csc_matrix((A_data, A_indices, A_indptr), shape=A_shape, dtype=A_dtype)
172
197
 
173
198
  # Setup preconditioner if AMG requested
174
199
  M = None
175
- if use_amg and solver_type == "cg":
200
+ if use_amg and solver_type in ("cg", "minres"):
176
201
  try:
177
202
  import pyamg
178
203
 
@@ -188,6 +213,10 @@ def _solve_iterative_column(args):
188
213
  solver_func = bicgstab
189
214
  elif solver_type == "cg":
190
215
  solver_func = cg
216
+ elif solver_type == "qmr":
217
+ solver_func = qmr
218
+ elif solver_type == "minres":
219
+ solver_func = minres
191
220
  else:
192
221
  raise ValueError(f"Unknown solver type: {solver_type}")
193
222
 
@@ -252,12 +281,14 @@ def _blqmr_parallel(
252
281
  )
253
282
  )
254
283
 
255
- # Solve in parallel
284
+ # Solve in parallel with proper context
256
285
  x = np.zeros((n, ncol), dtype=out_dtype)
257
286
  max_flag = 0
258
287
 
259
- with ProcessPoolExecutor(max_workers=nthread) as executor:
260
- results = executor.map(_solve_blqmr_batch, batches)
288
+ # Get appropriate multiprocessing context
289
+ ctx = _get_mp_context()
290
+ with Pool(processes=nthread) as pool:
291
+ results = pool.map(_solve_blqmr_batch, batches)
261
292
 
262
293
  for batch_id, start_col, x_batch, batch_flag, niter, relres in results:
263
294
  end_col = start_col + x_batch.shape[1]
@@ -269,7 +300,7 @@ def _blqmr_parallel(
269
300
 
270
301
  if verbose:
271
302
  print(
272
- f"blqmr [{start_col+1}:{end_col}] (worker {batch_id}): "
303
+ f"blqmr [{start_col + 1}:{end_col}] (worker {batch_id}): "
273
304
  f"iter={niter}, relres={relres:.2e}, flag={batch_flag}"
274
305
  )
275
306
 
@@ -288,7 +319,7 @@ def _iterative_parallel(
288
319
  verbose: bool = False,
289
320
  ) -> Tuple[np.ndarray, int]:
290
321
  """
291
- Solve iterative methods (gmres, bicgstab, cg) in parallel.
322
+ Solve iterative methods (gmres, bicgstab, cg, qmr, minres) in parallel.
292
323
 
293
324
  Each RHS column is solved independently in a separate process.
294
325
  """
@@ -326,12 +357,14 @@ def _iterative_parallel(
326
357
  )
327
358
  )
328
359
 
329
- # Solve in parallel
360
+ # Solve in parallel with proper context
330
361
  x = np.zeros((n, ncol), dtype=out_dtype)
331
362
  max_flag = 0
332
363
 
333
- with ProcessPoolExecutor(max_workers=nthread) as executor:
334
- results = executor.map(_solve_iterative_column, tasks)
364
+ # Get appropriate multiprocessing context
365
+ ctx = _get_mp_context()
366
+ with Pool(processes=nthread) as pool:
367
+ results = pool.map(_solve_iterative_column, tasks)
335
368
 
336
369
  for col_idx, x_col, info in results:
337
370
  x[:, col_idx] = x_col
@@ -339,7 +372,7 @@ def _iterative_parallel(
339
372
 
340
373
  if verbose:
341
374
  status = "converged" if info == 0 else f"flag={info}"
342
- print(f"{solver_type} [col {col_idx+1}]: {status}")
375
+ print(f"{solver_type} [col {col_idx + 1}]: {status}")
343
376
 
344
377
  return x, max_flag
345
378
 
@@ -376,13 +409,16 @@ def femsolve(
376
409
  'cg+amg': CG with AMG preconditioner (SPD, requires pyamg)
377
410
  'gmres': GMRES
378
411
  'bicgstab': BiCGSTAB
412
+ 'qmr': Quasi-Minimal Residual
413
+ 'minres': MINRES (symmetric/Hermitian only)
414
+ 'minres+amg': MINRES with AMG preconditioner (symmetric, requires pyamg)
379
415
  **kwargs : dict
380
416
  tol : float - convergence tolerance (default: 1e-10)
381
417
  maxiter : int - maximum iterations (default: 1000)
382
418
  rhsblock : int - block size for blqmr (default: 8)
383
419
  nthread : int - parallel workers for iterative solvers
384
420
  (default: min(ncol, cpu_count), set to 1 to disable)
385
- Supported by: blqmr, gmres, bicgstab, cg, cg+amg
421
+ Supported by: blqmr, gmres, bicgstab, cg, cg+amg, qmr, minres, minres+amg
386
422
  verbose : bool - print solver progress (default: False)
387
423
  spd : bool - True if matrix is symmetric positive definite
388
424
  M, M1, M2 : preconditioners (disables parallel for gmres/bicgstab/cg)
@@ -468,6 +504,11 @@ def femsolve(
468
504
  # Solve real system (batch solve for all RHS at once)
469
505
  x_real = _pardiso_solve(A_real, rhs_real)
470
506
 
507
+ # Handle both 1D and 2D results from pardiso
508
+ if x_real.ndim == 1:
509
+ # Single RHS case - reshape to 2D for consistent indexing
510
+ x_real = x_real.reshape(-1, 1)
511
+
471
512
  # Reconstruct complex solution: x = x_r + j*x_i
472
513
  x = x_real[:n, :] + 1j * x_real[n:, :]
473
514
  else:
@@ -782,6 +823,121 @@ def femsolve(
782
823
  status = "converged" if info == 0 else f"flag={info}"
783
824
  print(f"bicgstab [col {i+1}]: {status}")
784
825
 
826
+ elif method == "qmr":
827
+ nthread = kwargs.get("nthread", None)
828
+ if nthread is None:
829
+ nthread = min(ncol, multiprocessing.cpu_count())
830
+ M = kwargs.get("M", None)
831
+
832
+ if nthread > 1 and ncol > 1 and M is None:
833
+ # Parallel solving (without custom preconditioner)
834
+ x, flag = _iterative_parallel(
835
+ Amat,
836
+ rhs,
837
+ "qmr",
838
+ tol=tol,
839
+ maxiter=maxiter,
840
+ nthread=nthread,
841
+ use_amg=False,
842
+ verbose=verbose,
843
+ )
844
+ else:
845
+ # Sequential solving
846
+ for i in range(ncol):
847
+ if np.any(rhs[:, i] != 0):
848
+ try:
849
+ x[:, i], info = qmr(
850
+ Amat, rhs[:, i], M1=M, rtol=tol, maxiter=maxiter
851
+ )
852
+ except TypeError:
853
+ x[:, i], info = qmr(
854
+ Amat, rhs[:, i], M1=M, tol=tol, maxiter=maxiter
855
+ )
856
+ flag = max(flag, info)
857
+ if verbose:
858
+ status = "converged" if info == 0 else f"flag={info}"
859
+ print(f"qmr [col {i+1}]: {status}")
860
+
861
+ elif method == "minres+amg":
862
+ if not _HAS_AMG:
863
+ warnings.warn("pyamg not available, falling back to MINRES")
864
+ return femsolve(Amat, rhs, method="minres", **kwargs)
865
+
866
+ if is_complex:
867
+ warnings.warn("minres+amg doesn't support complex, falling back to gmres")
868
+ return femsolve(Amat, rhs, method="gmres", **kwargs)
869
+
870
+ nthread = kwargs.get("nthread", None)
871
+ if nthread is None:
872
+ nthread = min(ncol, multiprocessing.cpu_count())
873
+
874
+ if nthread > 1 and ncol > 1:
875
+ # Parallel solving
876
+ x, flag = _iterative_parallel(
877
+ Amat,
878
+ rhs,
879
+ "minres",
880
+ tol=tol,
881
+ maxiter=maxiter,
882
+ nthread=nthread,
883
+ use_amg=True,
884
+ verbose=verbose,
885
+ )
886
+ else:
887
+ # Sequential solving
888
+ ml = _pyamg.smoothed_aggregation_solver(Amat.tocsr())
889
+ M = ml.aspreconditioner()
890
+
891
+ for i in range(ncol):
892
+ if np.any(rhs[:, i] != 0):
893
+ try:
894
+ x[:, i], info = minres(
895
+ Amat, rhs[:, i], M=M, rtol=tol, maxiter=maxiter
896
+ )
897
+ except TypeError:
898
+ x[:, i], info = minres(
899
+ Amat, rhs[:, i], M=M, tol=tol, maxiter=maxiter
900
+ )
901
+ flag = max(flag, info)
902
+ if verbose:
903
+ status = "converged" if info == 0 else f"flag={info}"
904
+ print(f"minres+amg [col {i+1}]: {status}")
905
+
906
+ elif method == "minres":
907
+ nthread = kwargs.get("nthread", None)
908
+ if nthread is None:
909
+ nthread = min(ncol, multiprocessing.cpu_count())
910
+ M = kwargs.get("M", None)
911
+
912
+ if nthread > 1 and ncol > 1 and M is None:
913
+ # Parallel solving (without custom preconditioner)
914
+ x, flag = _iterative_parallel(
915
+ Amat,
916
+ rhs,
917
+ "minres",
918
+ tol=tol,
919
+ maxiter=maxiter,
920
+ nthread=nthread,
921
+ use_amg=False,
922
+ verbose=verbose,
923
+ )
924
+ else:
925
+ # Sequential solving
926
+ for i in range(ncol):
927
+ if np.any(rhs[:, i] != 0):
928
+ try:
929
+ x[:, i], info = minres(
930
+ Amat, rhs[:, i], M=M, rtol=tol, maxiter=maxiter
931
+ )
932
+ except TypeError:
933
+ x[:, i], info = minres(
934
+ Amat, rhs[:, i], M=M, tol=tol, maxiter=maxiter
935
+ )
936
+ flag = max(flag, info)
937
+ if verbose:
938
+ status = "converged" if info == 0 else f"flag={info}"
939
+ print(f"minres [col {i+1}]: {status}")
940
+
785
941
  else:
786
942
  raise ValueError(f"Unknown solver: {method}")
787
943
 
@@ -792,7 +948,7 @@ def femsolve(
792
948
  return x, flag
793
949
 
794
950
 
795
- def get_solver_info() -> dict:
951
+ def solverinfo() -> dict:
796
952
  """Return information about available solvers."""
797
953
  info = {
798
954
  "direct_solver": _DIRECT_SOLVER,
@@ -802,7 +958,8 @@ def get_solver_info() -> dict:
802
958
  "has_amg": _HAS_AMG,
803
959
  "has_blqmr": _HAS_BLQMR,
804
960
  "complex_direct": "umfpack" if _HAS_UMFPACK else "superlu",
805
- "complex_iterative": ["gmres", "bicgstab"],
961
+ "complex_iterative": ["gmres", "bicgstab", "qmr"],
962
+ "symmetric_iterative": ["cg", "minres"],
806
963
  "cpu_count": multiprocessing.cpu_count(),
807
964
  }
808
965
 
@@ -811,4 +968,7 @@ def get_solver_info() -> dict:
811
968
  info["blqmr_has_numba"] = HAS_NUMBA
812
969
  info["complex_iterative"].insert(0, "blqmr")
813
970
 
971
+ if _HAS_AMG:
972
+ info["amg_iterative"] = ["cg+amg", "minres+amg"]
973
+
814
974
  return info
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redbirdpy
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: A Python toolbox for Diffuse Optical Tomography (DOT) and Near-Infrared Spectroscopy (NIRS)
5
5
  Home-page: https://github.com/fangq/redbirdpy
6
6
  Author: Qianqian Fang
@@ -14,7 +14,7 @@ Project-URL: Repository, https://github.com/fangq/redbirdpy
14
14
  Project-URL: Bug Tracker, https://github.com/fangq/redbirdpy/issues
15
15
  Keywords: Diffuse Optical Tomography,DOT,NIRS,Near-Infrared Spectroscopy,FEM,Finite Element Method,Biomedical Optics,Image Reconstruction,Inverse Problem,Photon Migration,Diffusion Equation,Tissue Optics
16
16
  Platform: any
17
- Classifier: Development Status :: 3 - Alpha
17
+ Classifier: Development Status :: 4 - Beta
18
18
  Classifier: Intended Audience :: Science/Research
19
19
  Classifier: Intended Audience :: Developers
20
20
  Classifier: Intended Audience :: Healthcare Industry
@@ -37,14 +37,12 @@ Description-Content-Type: text/markdown
37
37
  License-File: LICENSE.txt
38
38
  Requires-Dist: numpy>=1.15.0
39
39
  Requires-Dist: scipy>=1.0.0
40
- Provides-Extra: mesh
41
- Requires-Dist: iso2mesh>=0.5.4; extra == "mesh"
40
+ Requires-Dist: iso2mesh>=0.5.0
42
41
  Provides-Extra: dev
43
42
  Requires-Dist: pytest>=6.0; extra == "dev"
44
43
  Requires-Dist: pytest-cov>=2.0; extra == "dev"
45
44
  Requires-Dist: flake8>=3.0; extra == "dev"
46
45
  Provides-Extra: all
47
- Requires-Dist: iso2mesh>=0.5.4; extra == "all"
48
46
  Requires-Dist: matplotlib>=3.0; extra == "all"
49
47
  Dynamic: author
50
48
  Dynamic: home-page
@@ -53,13 +51,13 @@ Dynamic: maintainer
53
51
  Dynamic: platform
54
52
  Dynamic: requires-python
55
53
 
56
- ![Redbird Banner](./doc/images/redbird_banner.png)
54
+ ![Redbird Banner](https://raw.githubusercontent.com/fangq/redbird/refs/heads/master/doc/images/redbird_banner.png)
57
55
 
58
56
  # RedbirdPy - A Model-Based Diffuse Optical Imaging Toolbox for Python
59
57
 
60
- * **Copyright**: (C) Qianqian Fang (2005–2025) \<q.fang at neu.edu>
58
+ * **Copyright**: (C) Qianqian Fang (2005–2026) \<q.fang at neu.edu>
61
59
  * **License**: GNU Public License V3 or later
62
- * **Version**: 0.1.0
60
+ * **Version**: 0.2.0 (Flamingo)
63
61
  * **GitHub**: [https://github.com/fangq/redbirdpy](https://github.com/fangq/redbirdpy)
64
62
  * **Acknowledgement**: This project is supported by the US National Institute of Health (NIH)
65
63
  grant [R01-CA204443](https://reporter.nih.gov/project-details/10982160)
@@ -88,7 +86,7 @@ Dynamic: requires-python
88
86
 
89
87
  ## Introduction
90
88
 
91
- **Redbird-Python** is a Python translation of the [Redbird MATLAB toolbox](https://github.com/fangq/redbird) for diffuse optical imaging (DOI) and diffuse optical tomography (DOT). It provides a fast, experimentally-validated forward solver for the diffusion equation using the finite-element method (FEM), along with advanced non-linear image reconstruction algorithms.
89
+ **RedbirdPy** is a Python translation of the [Redbird MATLAB toolbox](https://github.com/fangq/redbird) for diffuse optical imaging (DOI) and diffuse optical tomography (DOT). It provides a fast, experimentally-validated forward solver for the diffusion equation using the finite-element method (FEM), along with advanced non-linear image reconstruction algorithms.
92
90
 
93
91
  Redbird is the result of over two decades of active research in DOT and image reconstruction. It has been the core data analysis tool in numerous publications related to optical breast imaging, prior-guided reconstruction techniques, multi-modal imaging, and wide-field DOT systems.
94
92
 
@@ -104,7 +102,7 @@ Redbird is the result of over two decades of active research in DOT and image re
104
102
 
105
103
  ### Validation
106
104
 
107
- The forward solver is carefully validated against Monte Carlo solvers—**MCX** and **MMC**. The diffusion approximation is valid in high-scattering media where the reduced scattering coefficient (μs') is much greater than the absorption coefficient (μa).
105
+ The forward solver is carefully validated against Monte Carlo solvers - **MCX** and **MMC**. The diffusion approximation is valid in high-scattering media where the reduced scattering coefficient (μs') is much greater than the absorption coefficient (μa).
108
106
 
109
107
  ---
110
108
 
@@ -112,15 +110,15 @@ The forward solver is carefully validated against Monte Carlo solvers—**MCX**
112
110
 
113
111
  ### Requirements
114
112
 
115
- - Python 3.8+
113
+ - Python 3.6+
116
114
  - NumPy
117
115
  - SciPy
116
+ - Iso2Mesh
118
117
 
119
118
  ### Basic Installation
120
119
 
121
120
  ```bash
122
121
  pip install numpy scipy
123
- # For mesh generation
124
122
  pip install iso2mesh # or from https://github.com/NeuroJSON/pyiso2mesh
125
123
  ```
126
124
 
@@ -131,7 +129,7 @@ pip install iso2mesh # or from https://github.com/NeuroJSON/pyiso2mesh
131
129
  pip install numba # JIT compilation
132
130
 
133
131
  # For accelerated solvers
134
- pip install blocksolver # or from https://github.com/fangq/
132
+ pip install blocksolver # or from https://github.com/fangq/blit
135
133
 
136
134
  # For other linear solvers
137
135
  pip install pypardiso # Intel MKL PARDISO (fastest direct solver)
@@ -147,7 +145,7 @@ cd redbirdpy
147
145
  pip install -e .
148
146
  ```
149
147
 
150
- Or simply add the `redbirdpy` folder to your Python path.
148
+ Or simply import `redbirdpy` from inside the repository's top folder.
151
149
 
152
150
  ---
153
151
 
@@ -201,12 +199,12 @@ Redbird performs two main tasks:
201
199
 
202
200
  Redbird supports four types of image reconstructions:
203
201
 
204
- | Mode | Description |
205
- |------|-------------|
206
- | **Bulk Fitting** | Estimate single set of properties for entire domain |
207
- | **Segmented** | One property set per labeled tissue segment ("hard-prior") |
202
+ | Mode | Description |
203
+ |------|---------------------------------------------------------------|
204
+ | **Bulk Fitting** | Estimate single set of properties for the entire domain |
205
+ | **Segmented** | One property set per labeled tissue segment ("hard-prior") |
208
206
  | **Soft-Prior** | Spatial priors as soft constraints (Laplacian, compositional) |
209
- | **Unconstrained** | Independent properties per node with Tikhonov regularization |
207
+ | **Unconstrained** | Independent properties per node with Tikhonov regularization |
210
208
 
211
209
  ---
212
210
 
@@ -265,9 +263,9 @@ Redbird supports four types of image reconstructions:
265
263
  | Function | Description |
266
264
  |----------|-------------|
267
265
  | `femsolve(A, b, method)` | Solve linear system with auto-selection |
268
- | `get_solver_info()` | Query available solver backends |
266
+ | `solverinfo()` | Query available solver backends |
269
267
 
270
- Supported solvers: `pardiso`, `umfpack`, `cholmod`, `superlu`, `blqmr`, `cg`, `cg+amg`, `gmres`, `bicgstab`
268
+ Supported solvers: `pardiso`, `umfpack`, `cholmod`, `superlu`, `blqmr`, `cg`, `cg+amg`, `gmres`, `minres`, `minres+amg`, `qmr`, `bicgstab`
271
269
 
272
270
  ### `redbirdpy.analytical` - Analytical Solutions
273
271
 
@@ -395,8 +393,8 @@ Configure similarly using `dettype`, `detparam1`, `detparam2`, `detpattern`.
395
393
 
396
394
  ```python
397
395
  cfg['prop'] = {
398
- '690': np.array([[0, 0, 1, 1], [0.012, 1.1, 0, 1.37]]),
399
- '830': np.array([[0, 0, 1, 1], [0.008, 0.9, 0, 1.37]])
396
+ '690': [[0, 0, 1, 1], [0.012, 1.1, 0, 1.37]],
397
+ '830': [[0, 0, 1, 1], [0.008, 0.9, 0, 1.37]]
400
398
  }
401
399
  ```
402
400
 
@@ -498,7 +496,7 @@ recon['prop'] = np.tile(cfg['prop'][1,:], (recon['node'].shape[0], 1))
498
496
  newrecon, resid = rb.run(cfg, recon, detphi0, lambda_=1e-4)[:2]
499
497
  ```
500
498
 
501
- ### Wide-Field Reconstruction
499
+ ### Wide-Field Forward and Reconstruction
502
500
 
503
501
  ```python
504
502
  # Create illumination patterns
@@ -585,12 +583,12 @@ If you use Redbird in your research, please cite:
585
583
 
586
584
  ## License
587
585
 
588
- GNU General Public License v3.0 or later - see [LICENSE](LICENSE) file for details.
586
+ GNU General Public License v3.0 or later - see [LICENSE](LICENSE.txt) file for details.
589
587
 
590
588
  ## Author
591
589
 
592
590
  **Qianqian Fang** (q.fang@neu.edu)
593
- Computational Optics & Translational Imaging Lab
591
+ Computational Optics & Translational Imaging (COTI) Lab
594
592
  Northeastern University
595
593
 
596
- Python translation based on the [Redbird MATLAB toolbox](https://github.com/fangq/redbirdpy).
594
+ Python translation based on the [Redbird MATLAB toolbox](https://github.com/fangq/redbird).
@@ -0,0 +1,13 @@
1
+ redbirdpy/__init__.py,sha256=-NzQLn3eHX7KZBmJOUN9IxLitR9GcmBTkEyu8S_k5Yc,3379
2
+ redbirdpy/analytical.py,sha256=9mMTU8EwDbRn5JqPsFgSdh0LL4WXc4BaXQpsECl_Wg4,26681
3
+ redbirdpy/forward.py,sha256=Gtu7v41h_AVMQ5sfyMSDkOIzzYTP2vn0SoxUQDR_lS8,18785
4
+ redbirdpy/property.py,sha256=fb8tOc7TLS7h6GQ61GjAbEwawJb5kLFULFm6-4U3MT0,18804
5
+ redbirdpy/recon.py,sha256=tnsVIYc6dMB5p9iWXLdOtdMnAe_YLHruci9g-WmvvS8,30290
6
+ redbirdpy/solver.py,sha256=0lF41cOv0rv3W1JvAYhkgVWiO3hP2QWdltmZl5UH_Y8,32100
7
+ redbirdpy/utility.py,sha256=F8JYSUex0zWPds-f1lerdcPRT3bvGEPVw2CinDvFzu0,35360
8
+ redbirdpy-0.2.0.dist-info/licenses/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
9
+ redbirdpy-0.2.0.dist-info/METADATA,sha256=GpCSlcR76xneykT8NM802lgjREa27_Cp4KeNH9kSYio,19640
10
+ redbirdpy-0.2.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
11
+ redbirdpy-0.2.0.dist-info/top_level.txt,sha256=BbzExHReBzfre6x0TePxSeA7BZK4skcjnnTkHOTDoyA,10
12
+ redbirdpy-0.2.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
13
+ redbirdpy-0.2.0.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- redbirdpy/__init__.py,sha256=I0dQ6LYcRWSL0Z525n52VE2BLEDQeTOQqM_EUwilgxk,3379
2
- redbirdpy/analytical.py,sha256=9mMTU8EwDbRn5JqPsFgSdh0LL4WXc4BaXQpsECl_Wg4,26681
3
- redbirdpy/forward.py,sha256=Gtu7v41h_AVMQ5sfyMSDkOIzzYTP2vn0SoxUQDR_lS8,18785
4
- redbirdpy/property.py,sha256=fb8tOc7TLS7h6GQ61GjAbEwawJb5kLFULFm6-4U3MT0,18804
5
- redbirdpy/recon.py,sha256=tnsVIYc6dMB5p9iWXLdOtdMnAe_YLHruci9g-WmvvS8,30290
6
- redbirdpy/solver.py,sha256=mhhbyxxZATm8v_lVRCsYnwug4fsVyOU2ym665jmFO2E,26049
7
- redbirdpy/utility.py,sha256=F8JYSUex0zWPds-f1lerdcPRT3bvGEPVw2CinDvFzu0,35360
8
- redbirdpy-0.1.0.dist-info/licenses/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
9
- redbirdpy-0.1.0.dist-info/METADATA,sha256=1FeYa9cvr6KwvOK-_nr9yfblMydktDCLQuv1mQDvAW8,19510
10
- redbirdpy-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
11
- redbirdpy-0.1.0.dist-info/top_level.txt,sha256=BbzExHReBzfre6x0TePxSeA7BZK4skcjnnTkHOTDoyA,10
12
- redbirdpy-0.1.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
13
- redbirdpy-0.1.0.dist-info/RECORD,,