goad-py 0.3.0__cp38-abi3-musllinux_1_2_aarch64.whl → 0.4.2__cp38-abi3-musllinux_1_2_aarch64.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.

Potentially problematic release.


This version of goad-py might be problematic. Click here for more details.

goad_py/__init__.py CHANGED
@@ -1,5 +1,7 @@
1
- from .goad_py import *
1
+ # Re-export everything from the compiled Rust module
2
+ from goad_py._goad_py import *
2
3
 
3
- __doc__ = goad_py.__doc__
4
- if hasattr(goad_py, "__all__"):
5
- __all__ = goad_py.__all__
4
+ # Import Python modules
5
+ from .convergence import Convergence, Convergable, ConvergenceResults
6
+
7
+ __all__ = ['Convergence', 'Convergable', 'ConvergenceResults']
Binary file
goad_py/convergence.py ADDED
@@ -0,0 +1,382 @@
1
+ from dataclasses import dataclass
2
+ from typing import List, Dict, Optional, Tuple
3
+ import numpy as np
4
+ from . import _goad_py as goad
5
+
6
+
7
+ @dataclass
8
+ class Convergable:
9
+ """Represents a variable to monitor for convergence."""
10
+ variable: str # 'asymmetry', 'scatt', 'ext', or 'albedo'
11
+ tolerance_type: str = 'relative' # 'relative' or 'absolute'
12
+ tolerance: float = 0.01
13
+
14
+ def __post_init__(self):
15
+ valid_variables = {'asymmetry', 'scatt', 'ext', 'albedo'}
16
+ if self.variable not in valid_variables:
17
+ raise ValueError(f"Invalid variable '{self.variable}'. Must be one of {valid_variables}")
18
+
19
+ valid_types = {'relative', 'absolute'}
20
+ if self.tolerance_type not in valid_types:
21
+ raise ValueError(f"Invalid tolerance_type '{self.tolerance_type}'. Must be one of {valid_types}")
22
+
23
+ if self.tolerance <= 0:
24
+ raise ValueError(f"Tolerance must be positive, got {self.tolerance}")
25
+
26
+
27
+ @dataclass
28
+ class ConvergenceResults:
29
+ """Results from a convergence study."""
30
+ converged: bool
31
+ n_orientations: int
32
+ values: Dict[str, float] # Final mean values for each tracked variable
33
+ sem_values: Dict[str, float] # Final SEM values for each tracked variable
34
+ mueller_1d: Optional[np.ndarray] = None
35
+ mueller_2d: Optional[np.ndarray] = None
36
+ convergence_history: List[Tuple[int, str, float]] = None # (n_orientations, variable, sem)
37
+ warning: Optional[str] = None
38
+
39
+
40
+ class Convergence:
41
+ """Runs multiple MultiProblems until convergence criteria are met."""
42
+
43
+ def __init__(
44
+ self,
45
+ settings: goad.Settings,
46
+ convergables: List[Convergable],
47
+ batch_size: int = 24,
48
+ max_orientations: int = 100_000,
49
+ min_batches: int = 10,
50
+ mueller_1d: bool = True,
51
+ mueller_2d: bool = False
52
+ ):
53
+ """
54
+ Initialize a convergence study.
55
+
56
+ Args:
57
+ settings: GOAD settings for the simulation
58
+ convergables: List of variables to monitor for convergence
59
+ batch_size: Number of orientations per iteration
60
+ max_orientations: Maximum total orientations before stopping
61
+ min_batches: Minimum number of batches before allowing convergence
62
+ mueller_1d: Whether to collect 1D Mueller matrices
63
+ mueller_2d: Whether to collect 2D Mueller matrices
64
+ """
65
+ self.settings = settings
66
+ self.convergables = convergables
67
+ self.batch_size = batch_size
68
+ self.max_orientations = max_orientations
69
+ self.min_batches = min_batches
70
+ self.mueller_1d = mueller_1d
71
+ self.mueller_2d = mueller_2d
72
+
73
+ # Validate inputs
74
+ if not convergables:
75
+ raise ValueError("Must specify at least one convergable")
76
+
77
+ if batch_size <= 0:
78
+ raise ValueError(f"batch_size must be positive, got {batch_size}")
79
+
80
+ if max_orientations <= 0:
81
+ raise ValueError(f"max_orientations must be positive, got {max_orientations}")
82
+
83
+ if min_batches <= 0:
84
+ raise ValueError(f"min_batches must be positive, got {min_batches}")
85
+
86
+ # Initialize tracking variables
87
+ self.n_orientations = 0
88
+ self.convergence_history = []
89
+
90
+ # Batch-based statistics tracking for rigorous SEM calculation
91
+ self.batch_data = [] # List of batch statistics
92
+
93
+ # Mueller matrix accumulation
94
+ self.mueller_1d_sum = None
95
+ self.mueller_2d_sum = None
96
+
97
+ def _update_statistics(self, results: goad.Results, batch_size: int):
98
+ """Update statistics with new batch results.
99
+
100
+ Args:
101
+ results: Results from a MultiProblem run (pre-averaged over batch_size orientations)
102
+ batch_size: Number of orientations in this batch
103
+ """
104
+ # Check for None values indicating Custom binning
105
+ if (results.asymmetry is None or results.scat_cross is None or
106
+ results.ext_cross is None or results.albedo is None):
107
+ raise ValueError(
108
+ "Received None values for integrated properties. "
109
+ "This likely means Custom binning scheme is being used. "
110
+ "Convergence requires Simple or Interval binning schemes."
111
+ )
112
+
113
+ # Store batch data for proper statistical analysis
114
+ batch_info = {
115
+ 'batch_size': batch_size,
116
+ 'values': {},
117
+ 'weights': {}
118
+ }
119
+
120
+ # Store values and weights for tracked variables
121
+ for conv in self.convergables:
122
+ if conv.variable == 'asymmetry':
123
+ batch_info['values']['asymmetry'] = results.asymmetry
124
+ batch_info['weights']['asymmetry'] = results.scat_cross
125
+ elif conv.variable == 'scatt':
126
+ batch_info['values']['scatt'] = results.scat_cross
127
+ batch_info['weights']['scatt'] = 1.0 # Equal weighting
128
+ elif conv.variable == 'ext':
129
+ batch_info['values']['ext'] = results.ext_cross
130
+ batch_info['weights']['ext'] = 1.0 # Equal weighting
131
+ elif conv.variable == 'albedo':
132
+ batch_info['values']['albedo'] = results.albedo
133
+ batch_info['weights']['albedo'] = results.ext_cross + results.scat_cross
134
+
135
+ self.batch_data.append(batch_info)
136
+
137
+ # Update Mueller matrices if enabled
138
+ if self.mueller_1d and results.mueller_1d is not None:
139
+ mueller_1d_array = np.array(results.mueller_1d)
140
+ if self.mueller_1d_sum is None:
141
+ self.mueller_1d_sum = mueller_1d_array * batch_size
142
+ else:
143
+ self.mueller_1d_sum += mueller_1d_array * batch_size
144
+
145
+ if self.mueller_2d and results.mueller is not None:
146
+ mueller_2d_array = np.array(results.mueller)
147
+ if self.mueller_2d_sum is None:
148
+ self.mueller_2d_sum = mueller_2d_array * batch_size
149
+ else:
150
+ self.mueller_2d_sum += mueller_2d_array * batch_size
151
+
152
+ # Update total orientation count
153
+ self.n_orientations += batch_size
154
+
155
+ def _calculate_mean_and_sem(self, variable: str) -> Tuple[float, float]:
156
+ """Calculate mean and standard error of the mean for a variable using batch data.
157
+
158
+ Args:
159
+ variable: Variable name
160
+
161
+ Returns:
162
+ Tuple of (mean, sem)
163
+ """
164
+ if not self.batch_data:
165
+ return 0.0, float('inf')
166
+
167
+ # Extract batch values and weights
168
+ batch_values = []
169
+ batch_weights = []
170
+ batch_sizes = []
171
+
172
+ for batch in self.batch_data:
173
+ if variable in batch['values']:
174
+ batch_values.append(batch['values'][variable])
175
+ batch_weights.append(batch['weights'][variable])
176
+ batch_sizes.append(batch['batch_size'])
177
+
178
+ if not batch_values:
179
+ return 0.0, float('inf')
180
+
181
+ batch_values = np.array(batch_values)
182
+ batch_weights = np.array(batch_weights)
183
+ batch_sizes = np.array(batch_sizes)
184
+
185
+ # For weighted variables (asymmetry, albedo), use weighted statistics
186
+ if variable in ['asymmetry', 'albedo']:
187
+ # Calculate weighted mean across batches
188
+ # Each batch contributes: weight * batch_size * value
189
+ total_weighted_sum = np.sum(batch_weights * batch_sizes * batch_values)
190
+ total_weight = np.sum(batch_weights * batch_sizes)
191
+ weighted_mean = total_weighted_sum / total_weight
192
+
193
+ # Calculate weighted variance between batches
194
+ if len(batch_values) < 2:
195
+ return weighted_mean, float('inf') # Cannot estimate variance with < 2 batches
196
+
197
+ # For batch means, we need to account for the effective weight of each batch
198
+ effective_weights = batch_weights * batch_sizes
199
+ weighted_variance_batch_means = np.sum(effective_weights * (batch_values - weighted_mean)**2) / np.sum(effective_weights)
200
+
201
+ # Scale up to estimate population variance
202
+ # Batch means have variance = population_variance / average_batch_size
203
+ # So population_variance ≈ batch_means_variance * average_batch_size
204
+ avg_batch_size = np.average(batch_sizes, weights=effective_weights)
205
+ estimated_population_variance = weighted_variance_batch_means * avg_batch_size
206
+
207
+ # Calculate SEM for the total sample (using n-1 for sample standard error)
208
+ total_n = np.sum(batch_sizes)
209
+ sem = np.sqrt(estimated_population_variance / (total_n - 1))
210
+
211
+ return weighted_mean, sem
212
+
213
+ else:
214
+ # For unweighted variables (scatt, ext), use simple batch statistics
215
+ # Calculate mean of batch means, weighted by batch size
216
+ total_sum = np.sum(batch_sizes * batch_values)
217
+ total_n = np.sum(batch_sizes)
218
+ mean = total_sum / total_n
219
+
220
+ # Calculate variance between batch means
221
+ if len(batch_values) < 2:
222
+ return mean, float('inf')
223
+
224
+ batch_means_variance = np.var(batch_values, ddof=1)
225
+
226
+ # Scale up to estimate population variance
227
+ # Batch means have variance = population_variance / average_batch_size
228
+ # So population_variance ≈ batch_means_variance * average_batch_size
229
+ avg_batch_size = np.mean(batch_sizes)
230
+ estimated_population_variance = batch_means_variance * avg_batch_size
231
+
232
+ # Calculate SEM for the total sample (using n-1 for sample standard error)
233
+ sem = np.sqrt(estimated_population_variance / (total_n - 1))
234
+
235
+ return mean, sem
236
+
237
+ def _check_convergence(self) -> Dict[str, bool]:
238
+ """Check if all convergence criteria are met.
239
+
240
+ Returns:
241
+ Dict mapping variable names to convergence status
242
+ """
243
+ converged = {}
244
+
245
+ for conv in self.convergables:
246
+ mean, sem = self._calculate_mean_and_sem(conv.variable)
247
+
248
+ # Calculate tolerance based on type
249
+ if conv.tolerance_type == 'relative':
250
+ # Relative tolerance: SEM / |mean| < tolerance
251
+ if mean != 0:
252
+ relative_sem = sem / abs(mean)
253
+ converged[conv.variable] = relative_sem < conv.tolerance
254
+ else:
255
+ # If mean is zero, use absolute comparison
256
+ converged[conv.variable] = sem < conv.tolerance
257
+ else:
258
+ # Absolute tolerance: SEM < tolerance
259
+ converged[conv.variable] = sem < conv.tolerance
260
+
261
+ return converged
262
+
263
+ def _all_converged(self) -> bool:
264
+ """Check if all variables have converged.
265
+
266
+ Returns:
267
+ True if all variables meet their convergence criteria and minimum batches completed
268
+ """
269
+ # Check minimum batches requirement first
270
+ if len(self.batch_data) < self.min_batches:
271
+ return False
272
+
273
+ converged_status = self._check_convergence()
274
+ return all(converged_status.values())
275
+
276
+ def _print_progress(self, iteration: int):
277
+ """Print convergence progress.
278
+
279
+ Args:
280
+ iteration: Current iteration number
281
+ """
282
+ print(f"\nIteration {iteration} ({self.n_orientations} orientations):")
283
+
284
+ converged_status = self._check_convergence()
285
+
286
+ for conv in self.convergables:
287
+ mean, sem = self._calculate_mean_and_sem(conv.variable)
288
+
289
+ # Calculate 95% CI
290
+ ci_lower = mean - 1.96 * sem
291
+ ci_upper = mean + 1.96 * sem
292
+
293
+ # Format based on tolerance type
294
+ if conv.tolerance_type == 'relative':
295
+ if mean != 0:
296
+ relative_sem = sem / abs(mean)
297
+ target_str = f"{conv.tolerance*100:.1f}%"
298
+ current_str = f"{relative_sem*100:.2f}%"
299
+ else:
300
+ target_str = f"{conv.tolerance} (abs, mean=0)"
301
+ current_str = f"{sem:.4g}"
302
+ else:
303
+ target_str = f"{conv.tolerance}"
304
+ current_str = f"{sem:.4g}"
305
+
306
+ # Status indicator
307
+ status = "✓" if converged_status[conv.variable] else "❌"
308
+
309
+ # Print line with mean, SEM, CI, and convergence status
310
+ print(f" {conv.variable:<10}: {mean:.6f} ± {sem:.6f} [{ci_lower:.6f}, {ci_upper:.6f}] | SEM: {current_str} (target: {target_str}) {status}")
311
+
312
+ # Add to convergence history
313
+ self.convergence_history.append((self.n_orientations, conv.variable, sem))
314
+
315
+ def run(self) -> ConvergenceResults:
316
+ """Run the convergence study.
317
+
318
+ Returns:
319
+ ConvergenceResults containing final values and convergence status
320
+ """
321
+ iteration = 0
322
+ converged = False
323
+ warning = None
324
+
325
+ while not converged and self.n_orientations < self.max_orientations:
326
+ iteration += 1
327
+
328
+ # Determine batch size for this iteration
329
+ remaining = self.max_orientations - self.n_orientations
330
+ batch_size = min(self.batch_size, remaining)
331
+
332
+ # Set batch size
333
+ orientations = goad.create_uniform_orientation(batch_size)
334
+
335
+ # Set the orientations for the settings
336
+ self.settings.orientation = orientations
337
+
338
+ mp = goad.MultiProblem(self.settings)
339
+ mp.py_solve()
340
+
341
+ # Update statistics
342
+ self._update_statistics(mp.results, batch_size)
343
+
344
+ # Print progress
345
+ self._print_progress(iteration)
346
+
347
+ # Check convergence
348
+ converged = self._all_converged()
349
+
350
+ # Prepare final results
351
+ if converged:
352
+ print(f"\nConverged after {self.n_orientations} orientations.")
353
+ else:
354
+ warning = f"Maximum orientations ({self.max_orientations}) reached without convergence"
355
+ print(f"\nWarning: {warning}")
356
+
357
+ # Calculate final values and SEMs
358
+ final_values = {}
359
+ final_sems = {}
360
+ for conv in self.convergables:
361
+ mean, sem = self._calculate_mean_and_sem(conv.variable)
362
+ final_values[conv.variable] = mean
363
+ final_sems[conv.variable] = sem
364
+
365
+ # Prepare Mueller matrices
366
+ mueller_1d = None
367
+ mueller_2d = None
368
+ if self.mueller_1d and self.mueller_1d_sum is not None:
369
+ mueller_1d = self.mueller_1d_sum / self.n_orientations
370
+ if self.mueller_2d and self.mueller_2d_sum is not None:
371
+ mueller_2d = self.mueller_2d_sum / self.n_orientations
372
+
373
+ return ConvergenceResults(
374
+ converged=converged,
375
+ n_orientations=self.n_orientations,
376
+ values=final_values,
377
+ sem_values=final_sems,
378
+ mueller_1d=mueller_1d,
379
+ mueller_2d=mueller_2d,
380
+ convergence_history=self.convergence_history,
381
+ warning=warning
382
+ )
@@ -20,27 +20,18 @@ Default behavior (minimal setup):
20
20
  Example (minimal setup):
21
21
  import goad_py as goad
22
22
 
23
- # Ultra-simple single orientation
24
23
  settings = goad.Settings("particle.obj")
25
- problem = goad.Problem(settings)
26
- problem.py_solve()
27
- print(f"Extinction: {problem.results.ext_cross}")
28
-
29
- # Multi-orientation averaging (100 random orientations)
30
- orientations = goad.create_uniform_orientation(100)
31
- settings = goad.Settings("particle.obj", orientation=orientations)
32
24
  mp = goad.MultiProblem(settings)
33
25
  mp.py_solve()
34
- print(f"Average extinction: {mp.results.ext_cross}")
35
26
 
36
- # Truly minimal (just geometry path)
37
- settings = goad.Settings("particle.obj") # Everything else uses defaults!
38
- mp = goad.MultiProblem(settings)
39
- mp.py_solve()
40
- print(f"Results: {mp.results.scat_cross}")
27
+ results = mp.results
28
+ print(f"Scattering cross-section: {results.scat_cross}")
29
+ print(f"Extinction cross-section: {results.ext_cross}")
30
+ print(f"Asymmetry parameter: {results.asymmetry}")
41
31
  """
42
32
 
43
- from typing import Optional, List, Dict, Any, Union
33
+ from typing import Optional, List, Dict, Any, Union, Tuple
34
+ import numpy as np
44
35
 
45
36
  class Euler:
46
37
  """Euler angles for rotations."""
@@ -342,4 +333,121 @@ def create_discrete_orientation(eulers: List[Euler], euler_convention: Optional[
342
333
 
343
334
  def sum_as_string(a: int, b: int) -> str: ...
344
335
 
345
- def goad_py_add() -> None: ...
336
+ def goad_py_add() -> None: ...
337
+
338
+ # Convergence Analysis Classes
339
+
340
+ class Convergable:
341
+ """Represents a variable to monitor for convergence.
342
+
343
+ Defines convergence criteria for integrated scattering parameters
344
+ including asymmetry parameter, scattering cross-section, extinction
345
+ cross-section, and single-scattering albedo.
346
+ """
347
+
348
+ variable: str
349
+ tolerance_type: str
350
+ tolerance: float
351
+
352
+ def __init__(
353
+ self,
354
+ variable: str,
355
+ tolerance_type: str = 'relative',
356
+ tolerance: float = 0.01
357
+ ) -> None:
358
+ """Initialize convergence criterion.
359
+
360
+ Args:
361
+ variable: Variable to monitor ('asymmetry', 'scatt', 'ext', 'albedo')
362
+ tolerance_type: 'relative' or 'absolute' tolerance
363
+ tolerance: Tolerance value (relative as fraction, absolute as value)
364
+
365
+ Raises:
366
+ ValueError: If variable name or tolerance_type is invalid
367
+ """
368
+ ...
369
+
370
+ class ConvergenceResults:
371
+ """Results from a convergence study.
372
+
373
+ Contains final convergence status, parameter values with uncertainties,
374
+ and complete convergence history for analysis.
375
+ """
376
+
377
+ converged: bool
378
+ n_orientations: int
379
+ values: Dict[str, float]
380
+ sem_values: Dict[str, float]
381
+ mueller_1d: Optional[np.ndarray]
382
+ mueller_2d: Optional[np.ndarray]
383
+ convergence_history: List[Tuple[int, str, float]]
384
+ warning: Optional[str]
385
+
386
+ def __init__(
387
+ self,
388
+ converged: bool,
389
+ n_orientations: int,
390
+ values: Dict[str, float],
391
+ sem_values: Dict[str, float],
392
+ mueller_1d: Optional[np.ndarray] = None,
393
+ mueller_2d: Optional[np.ndarray] = None,
394
+ convergence_history: List[Tuple[int, str, float]] = None,
395
+ warning: Optional[str] = None
396
+ ) -> None: ...
397
+
398
+ class Convergence:
399
+ """Runs multiple MultiProblems until convergence criteria are met.
400
+
401
+ Implements statistical convergence analysis for scattering parameters
402
+ using batch-based standard error estimation. Monitors multiple variables
403
+ simultaneously and stops when all meet their convergence criteria.
404
+
405
+ Example:
406
+ convergence = Convergence(
407
+ settings=goad.Settings("particle.obj"),
408
+ convergables=[
409
+ Convergable('asymmetry', 'absolute', 0.005),
410
+ Convergable('scatt', 'relative', 0.01),
411
+ ],
412
+ batch_size=100
413
+ )
414
+ results = convergence.run()
415
+ """
416
+
417
+ def __init__(
418
+ self,
419
+ settings: Settings,
420
+ convergables: List[Convergable],
421
+ batch_size: int = 24,
422
+ max_orientations: int = 100_000,
423
+ min_batches: int = 10,
424
+ mueller_1d: bool = True,
425
+ mueller_2d: bool = False
426
+ ) -> None:
427
+ """Initialize convergence study.
428
+
429
+ Args:
430
+ settings: GOAD settings for the simulation
431
+ convergables: List of variables to monitor for convergence
432
+ batch_size: Number of orientations per iteration
433
+ max_orientations: Maximum total orientations before stopping
434
+ min_batches: Minimum number of batches before allowing convergence
435
+ mueller_1d: Whether to collect 1D Mueller matrices
436
+ mueller_2d: Whether to collect 2D Mueller matrices
437
+
438
+ Raises:
439
+ ValueError: If parameters are invalid or no convergables specified
440
+ """
441
+ ...
442
+
443
+ def run(self) -> ConvergenceResults:
444
+ """Run the convergence study.
445
+
446
+ Executes batches of orientations until all convergence criteria
447
+ are met or maximum orientations reached. Provides progress updates
448
+ and rigorous statistical analysis.
449
+
450
+ Returns:
451
+ ConvergenceResults containing final values and convergence status
452
+ """
453
+ ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: goad-py
3
- Version: 0.3.0
3
+ Version: 0.4.2
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: Topic :: Scientific/Engineering :: Physics
@@ -43,14 +43,38 @@ pip install goad-py
43
43
  import goad_py
44
44
 
45
45
  # Create a problem with minimal setup
46
- problem = goad_py.Problem("path/to/geometry.obj")
47
-
48
- # Solve and get results
49
- results = problem.py_solve()
46
+ settings = goad_py.Settings("path/to/geometry.obj")
47
+ mp = goad_py.MultiProblem(settings)
48
+ mp.py_solve()
50
49
 
51
50
  # Access scattering data
52
- print(f"Number of angles: {results.num_angles}")
53
- print(f"Scattering cross section: {results.sca_cross_section}")
51
+ results = mp.results
52
+ print(f"Scattering cross-section: {results.scat_cross}")
53
+ print(f"Extinction cross-section: {results.ext_cross}")
54
+ print(f"Asymmetry parameter: {results.asymmetry}")
55
+ ```
56
+
57
+ ### Convergence Analysis
58
+
59
+ For statistical error estimation, use the convergence analysis functionality:
60
+
61
+ ```python
62
+ from goad_py import Convergence, Convergable
63
+
64
+ # Set up convergence analysis
65
+ convergence = Convergence(
66
+ settings=goad_py.Settings(geom_path="path/to/geometry.obj"),
67
+ convergables=[
68
+ Convergable('asymmetry', 'absolute', 0.005), # absolute SEM < 0.005
69
+ Convergable('scatt', 'relative', 0.01), # relative SEM < 1%
70
+ ],
71
+ batch_size=100
72
+ )
73
+
74
+ # Run until convergence
75
+ results = convergence.run()
76
+ print(f"Converged: {results.converged}")
77
+ print(f"Final values: {results.values}")
54
78
  ```
55
79
 
56
80
  ## Features
@@ -59,6 +83,7 @@ print(f"Scattering cross section: {results.sca_cross_section}")
59
83
  - Support for various 3D geometry formats
60
84
  - Configurable wavelength, refractive index, and orientations
61
85
  - Multi-orientation averaging capabilities
86
+ - Convergence analysis for statistical error estimation
62
87
  - Efficient parallel computation with GIL release
63
88
 
64
89
  ## Documentation
@@ -0,0 +1,9 @@
1
+ goad_py-0.4.2.dist-info/METADATA,sha256=JWxD4wctGOJzIWAWzjEpHPrdKbEgabqBjqGbgAptSR4,3181
2
+ goad_py-0.4.2.dist-info/WHEEL,sha256=dOnalb29euhUK3FRsG9PGb9HBYXnNGRGVeKIPHUwibU,106
3
+ goad_py.libs/libgcc_s-e52197c3.so.1,sha256=vkPW1Auw6CH9Bjk7frmX3hry_1H9c0tRI0Ncyg71WUI,724137
4
+ goad_py.libs/libstdc++-405035b3.so.6,sha256=dhdlt148awG0mZDLGM8wZy1R4PeU5HXvi8l9pgv4DiY,22443689
5
+ goad_py/__init__.py,sha256=vZn5zZZdTgm1qTQFYCqgNKBKDAoheMo5OvwdLIIl3Dk,242
6
+ goad_py/_goad_py.abi3.so,sha256=Kl6jqv2uEB2RiXY-SlvUlpLzBtelJTIYW-DdA60aeys,2166617
7
+ goad_py/convergence.py,sha256=8HTlrpv3RLD8FfmZuT_2mySVtnpHaPLKx6Rcw-jDgB0,14930
8
+ goad_py/goad_py.pyi,sha256=Ue33wS-DLeI2JTwpKyPXNk4D-Trt9S5MBQSO8qW5XGc,14922
9
+ goad_py-0.4.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: maturin (1.9.0)
2
+ Generator: maturin (1.9.1)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp38-abi3-musllinux_1_2_aarch64
goad_py/goad_py.abi3.so DELETED
Binary file
goad_py/py.typed DELETED
File without changes
@@ -1,9 +0,0 @@
1
- goad_py-0.3.0.dist-info/METADATA,sha256=_QAoI_pML6HmYtVhYwEzjAjrZ1ieYWmib0Hk0QRvDGI,2434
2
- goad_py-0.3.0.dist-info/WHEEL,sha256=XrXtO6TC5d8ini6lhMZhY6K70cqp9-og79F-C64Ik-M,106
3
- goad_py.libs/libgcc_s-e52197c3.so.1,sha256=vkPW1Auw6CH9Bjk7frmX3hry_1H9c0tRI0Ncyg71WUI,724137
4
- goad_py.libs/libstdc++-405035b3.so.6,sha256=dhdlt148awG0mZDLGM8wZy1R4PeU5HXvi8l9pgv4DiY,22443689
5
- goad_py/__init__.py,sha256=YW_7ejLyMUb8grQQmBo-vpbgTYF2xRruw6x7UxAerIg,111
6
- goad_py/__init__.pyi,sha256=Fc4JBBbKMYZ0MA_DzycbC2v19YARzGKNg0bfmTkNhPQ,11489
7
- goad_py/goad_py.abi3.so,sha256=4bAY6AE8Uxh-g_sgtHEZG5-JsUu5P0lDb47rk0PnKd4,2035593
8
- goad_py/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- goad_py-0.3.0.dist-info/RECORD,,