pytdgl3d 0.3.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.
Files changed (59) hide show
  1. pytdgl3d-0.3.0.dist-info/METADATA +1268 -0
  2. pytdgl3d-0.3.0.dist-info/RECORD +59 -0
  3. pytdgl3d-0.3.0.dist-info/WHEEL +5 -0
  4. pytdgl3d-0.3.0.dist-info/entry_points.txt +2 -0
  5. pytdgl3d-0.3.0.dist-info/licenses/LICENSE +21 -0
  6. pytdgl3d-0.3.0.dist-info/top_level.txt +1 -0
  7. tdgl3d/__init__.py +51 -0
  8. tdgl3d/about.py +81 -0
  9. tdgl3d/device/__init__.py +4 -0
  10. tdgl3d/device/device.py +544 -0
  11. tdgl3d/device/layer.py +83 -0
  12. tdgl3d/device/meshing.py +285 -0
  13. tdgl3d/device/volume.py +188 -0
  14. tdgl3d/distance.py +60 -0
  15. tdgl3d/em.py +180 -0
  16. tdgl3d/finite_volume/__init__.py +3 -0
  17. tdgl3d/finite_volume/edge_mesh.py +112 -0
  18. tdgl3d/finite_volume/mesh.py +271 -0
  19. tdgl3d/finite_volume/operators.py +337 -0
  20. tdgl3d/finite_volume/util.py +243 -0
  21. tdgl3d/fluxoid.py +215 -0
  22. tdgl3d/geometry.py +492 -0
  23. tdgl3d/parameter.py +258 -0
  24. tdgl3d/solution/__init__.py +20 -0
  25. tdgl3d/solution/data.py +288 -0
  26. tdgl3d/solution/plot_solution.py +595 -0
  27. tdgl3d/solution/solution.py +982 -0
  28. tdgl3d/solver/__init__.py +3 -0
  29. tdgl3d/solver/options.py +77 -0
  30. tdgl3d/solver/runner.py +265 -0
  31. tdgl3d/solver/screening.py +175 -0
  32. tdgl3d/solver/solve.py +105 -0
  33. tdgl3d/solver/solver.py +905 -0
  34. tdgl3d/sources/__init__.py +3 -0
  35. tdgl3d/sources/constant.py +32 -0
  36. tdgl3d/sources/loop.py +61 -0
  37. tdgl3d/sources/scaling.py +52 -0
  38. tdgl3d/test/__init__.py +0 -0
  39. tdgl3d/test/test_completeness.py +782 -0
  40. tdgl3d/test/test_cone.py +316 -0
  41. tdgl3d/test/test_fast.py +210 -0
  42. tdgl3d/test/test_features.py +384 -0
  43. tdgl3d/test/test_upgrades.py +499 -0
  44. tdgl3d/testing.py +19 -0
  45. tdgl3d/version.py +2 -0
  46. tdgl3d/visualization/__init__.py +53 -0
  47. tdgl3d/visualization/analysis.py +205 -0
  48. tdgl3d/visualization/animate.py +222 -0
  49. tdgl3d/visualization/common.py +219 -0
  50. tdgl3d/visualization/convert.py +73 -0
  51. tdgl3d/visualization/interactive.py +349 -0
  52. tdgl3d/visualization/io.py +103 -0
  53. tdgl3d/visualization/monitor.py +177 -0
  54. tdgl3d/visualization/physics.py +481 -0
  55. tdgl3d/visualization/plots3d.py +420 -0
  56. tdgl3d/visualization/publication.py +735 -0
  57. tdgl3d/visualization/snapshot.py +143 -0
  58. tdgl3d/visualization/vortex.py +679 -0
  59. tdgl3d/visualize.py +138 -0
@@ -0,0 +1,1268 @@
1
+ Metadata-Version: 2.4
2
+ Name: pytdgl3d
3
+ Version: 0.3.0
4
+ Summary: 3D Time-Dependent Ginzburg-Landau solver
5
+ Author-email: Tanvir Hassan <tanvir6307@gmail.com>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.14
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: numpy>=2.4.2
11
+ Requires-Dist: scipy>=1.17.0
12
+ Requires-Dist: h5py>=3.15.1
13
+ Requires-Dist: numba>=0.64.0
14
+ Requires-Dist: pint>=0.25.2
15
+ Requires-Dist: cloudpickle>=3.1.2
16
+ Requires-Dist: matplotlib>=3.10.8
17
+ Requires-Dist: Pillow>=12.1.1
18
+ Provides-Extra: visualization
19
+ Requires-Dist: pyvista>=0.35; extra == "visualization"
20
+ Requires-Dist: meshio>=5.0; extra == "visualization"
21
+ Provides-Extra: gpu
22
+ Requires-Dist: cupy-cuda12x>=14.0.1; extra == "gpu"
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=7.0; extra == "dev"
25
+ Dynamic: license-file
26
+
27
+ # tdgl3d
28
+
29
+ `tdgl3d` is an open-source Python package for solving three-dimensional
30
+ time-dependent Ginzburg-Landau (TDGL) problems in superconductors. It represents
31
+ the superconducting domain by a closed triangular surface mesh, generates a
32
+ tetrahedral volume mesh, assembles finite-volume operators on mesh vertices and
33
+ edges, and evolves the complex superconducting order parameter using
34
+ gauge-invariant link variables.
35
+
36
+ The package is designed for computational studies of vortex nucleation, vortex
37
+ motion, magnetic screening, fluxoid quantization, and transport-like boundary
38
+ conditions in finite three-dimensional geometries. Built-in geometry generators
39
+ cover common shapes such as cones, cylinders, cuboids, cubes, pyramids, spheres,
40
+ and ellipsoids, while user-defined closed surface meshes can also be supplied.
41
+
42
+ ## Contents
43
+
44
+ - [Scientific Scope](#scientific-scope)
45
+ - [Main Features](#main-features)
46
+ - [Numerical Method](#numerical-method)
47
+ - [Package Architecture](#package-architecture)
48
+ - [Installation](#installation)
49
+ - [Quick Start](#quick-start)
50
+ - [Geometry and Device Construction](#geometry-and-device-construction)
51
+ - [Solver Usage](#solver-usage)
52
+ - [Magnetic Sources](#magnetic-sources)
53
+ - [Screening and GPU Acceleration](#screening-and-gpu-acceleration)
54
+ - [Terminal Currents and Probe Points](#terminal-currents-and-probe-points)
55
+ - [Solution Analysis](#solution-analysis)
56
+ - [Visualization](#visualization)
57
+ - [HDF5 Output Format](#hdf5-output-format)
58
+ - [Testing and Validation](#testing-and-validation)
59
+ - [Reproducibility Checklist](#reproducibility-checklist)
60
+ - [Known Limitations](#known-limitations)
61
+ - [License](#license)
62
+ - [Citation](#citation)
63
+
64
+ ## Scientific Scope
65
+
66
+ `tdgl3d` solves a generalized TDGL model for a superconducting volume
67
+ `Omega`. The primary fields are:
68
+
69
+ - `psi(r, t)`: complex superconducting order parameter.
70
+ - `mu(r, t)`: scalar electric potential.
71
+ - `A(r, t)`: vector potential.
72
+ - `J_s`: superconducting current on mesh edges.
73
+ - `J_n`: normal current on mesh edges.
74
+
75
+ The code uses dimensionless TDGL units internally. Lengths are scaled by the
76
+ coherence length `xi`, magnetic fields by `Bc2`, vector potentials by
77
+ `xi * Bc2`, and currents by the corresponding GL current scale exposed through
78
+ the `Device` physical-scale helpers.
79
+
80
+ The intended use cases include:
81
+
82
+ - 3D Abrikosov vortex nucleation and relaxation.
83
+ - Vortex line deformation in non-planar geometries.
84
+ - Surface and geometry effects in cones, tips, spheres, and finite-thickness
85
+ mesoscopic superconductors.
86
+ - Fluxoid and winding-number analysis along arbitrary 3D contours.
87
+ - Transport-style simulations using terminal volumes and scalar-potential
88
+ boundary feedback.
89
+ - Post-processing of HDF5 TDGL trajectories for visualization and physical
90
+ observables.
91
+
92
+ ## Main Features
93
+
94
+ - 3D tetrahedral finite-volume mesh support.
95
+ - Gauge-invariant edge link variables for vector-potential coupling.
96
+ - Adaptive semi-implicit Euler time stepping for TDGL evolution.
97
+ - Built-in geometry generators:
98
+ `cone`, `cylinder`, `cuboid`, `box`, `cube`, `pyramid`, `sphere`,
99
+ `ellipsoid`.
100
+ - User-supplied closed triangular surface meshes through `Volume`.
101
+ - Material model through `Layer`, including `xi`, London penetration depth,
102
+ conductivity, `u`, and `gamma`.
103
+ - `Device` abstraction for geometry, materials, mesh generation, terminal
104
+ volumes, probe points, transformations, HDF5 I/O, and physical scales.
105
+ - Sparse finite-volume gradient, divergence, and Laplacian operators.
106
+ - Optional magnetic self-field screening using a 3D Biot-Savart summation.
107
+ - Numba-accelerated CPU screening kernel.
108
+ - Optional CuPy CUDA screening kernel.
109
+ - Uniform magnetic field and circular current-loop source helpers.
110
+ - Spatially and time-dependent parameters using Python callables.
111
+ - Seed-solution support for continuation studies.
112
+ - HDF5 output containing device, mesh, options, snapshots, and dynamics.
113
+ - Solution analysis for order parameter, phase, current density, magnetic
114
+ moment, magnetic field, vorticity, superfluid velocity, London penetration
115
+ depth, and fluxoid quantization.
116
+ - Matplotlib slice plots, 3D plotting helpers, snapshots, GIF/MP4 animation,
117
+ live monitoring, vortex detection, and XDMF export.
118
+ - Test suite covering geometry, meshing, finite-volume operators, short solver
119
+ runs, serialization, visualization, screening, and post-processing.
120
+
121
+ ## Numerical Method
122
+
123
+ ### Mesh and Control Volumes
124
+
125
+ The computational domain is a closed triangular surface mesh. `tdgl3d` fills
126
+ the interior with points and uses SciPy Delaunay tetrahedralization to create a
127
+ tetrahedral mesh. Tetrahedra with centroids outside the surface are discarded,
128
+ and boundary vertices are projected back to the original surface.
129
+
130
+ For each mesh vertex, a barycentric control volume is approximated by
131
+ distributing each tetrahedron volume equally among its four vertices. The mesh
132
+ stores:
133
+
134
+ - `sites`: vertex coordinates in dimensionless units.
135
+ - `elements`: tetrahedral connectivity.
136
+ - `boundary_indices`: mesh sites on the boundary.
137
+ - `volumes`: per-site control volumes.
138
+ - `edge_mesh`: unique edges, edge centers, edge directions, edge lengths,
139
+ approximate dual-face areas, and boundary-edge indices.
140
+
141
+ ### Finite-Volume Operators
142
+
143
+ The finite-volume operators are assembled on the edge mesh:
144
+
145
+ - `build_gradient`: edge gradient from site values to edge values.
146
+ - `build_divergence`: site divergence from edge values.
147
+ - `build_laplacian`: finite-volume Laplacian assembled from edge weights.
148
+ - `MeshOperators`: cached divergence, scalar Laplacian, covariant gradient,
149
+ and covariant Laplacian.
150
+
151
+ The edge weights use edge lengths, site control volumes, and approximate
152
+ dual-face areas. This gives a practical Delaunay-Voronoi-style discretization
153
+ for 3D exploratory calculations.
154
+
155
+ ### Gauge-Invariant Link Variables
156
+
157
+ The vector potential is evaluated at edge midpoints. For each oriented edge
158
+ `i -> j`, the code computes a link variable
159
+
160
+ ```text
161
+ U_ij = exp(-i A_ij . (r_j - r_i))
162
+ ```
163
+
164
+ The covariant gradient uses the link variable:
165
+
166
+ ```text
167
+ grad_A(psi)_ij = (U_ij psi_j - psi_i) / L_ij
168
+ ```
169
+
170
+ This preserves gauge-invariant phase coupling on the mesh edges.
171
+
172
+ ### Time Stepping
173
+
174
+ The TDGL update uses a semi-implicit Euler step. The nonlinear term in
175
+ `|psi|^2` is handled through a quadratic solve for the next order-parameter
176
+ magnitude. Adaptive stepping reduces the time step on failed updates and uses a
177
+ sliding-window estimate of recent `|psi|^2` changes to adjust the next step.
178
+
179
+ At each successful step, the solver:
180
+
181
+ 1. Updates time-dependent disorder or pair-breaking fields.
182
+ 2. Advances `psi`.
183
+ 3. Solves for scalar potential `mu`.
184
+ 4. Computes supercurrent and normal current.
185
+ 5. Applies terminal-current feedback when terminals are configured.
186
+ 6. Updates the induced vector potential if screening is enabled.
187
+ 7. Periodically applies a Coulomb-gauge projection to the induced field.
188
+ 8. Saves snapshots according to `save_every`.
189
+
190
+ ### Screening
191
+
192
+ When `include_screening=True`, the induced vector potential is updated from the
193
+ site current density using a Biot-Savart-type volume summation:
194
+
195
+ ```text
196
+ A_induced(r_e) ~ sum_j J(r_j) V_j / |r_e - r_j|
197
+ ```
198
+
199
+ The screening update uses a Polyak heavy-ball iteration controlled in the
200
+ current implementation by `screening_step_size` and `screening_drag`.
201
+ `screening_tolerance` is stored in the solver options as a screening
202
+ convergence parameter. The CPU implementation uses Numba. The optional GPU path
203
+ uses a CuPy raw CUDA kernel.
204
+
205
+ ## Package Architecture
206
+
207
+ ```text
208
+ tdgl3d/
209
+ __init__.py Public API exports
210
+ about.py Version and dependency table helpers
211
+ em.py Unit registry, vector potentials, Biot-Savart tools
212
+ fluxoid.py 3D fluxoid contours and fluxoid integration
213
+ geometry.py Surface mesh generators
214
+ parameter.py Callable spatial/time-dependent parameters
215
+ testing.py Test runner helper
216
+
217
+ device/
218
+ layer.py Material parameters
219
+ volume.py Closed triangular surface mesh container
220
+ meshing.py Interior fill and tetrahedral mesh generation
221
+ device.py Device abstraction and HDF5 I/O
222
+
223
+ finite_volume/
224
+ mesh.py Tetrahedral mesh and mesh quality metrics
225
+ edge_mesh.py Edge topology and edge geometry
226
+ operators.py Gradient, divergence, Laplacian, link variables
227
+ util.py Mesh topology and geometry utilities
228
+
229
+ solver/
230
+ options.py SolverOptions dataclass
231
+ solve.py Public solve() function and terminal validation
232
+ solver.py TDGLSolver implementation
233
+ runner.py Simulation loop and HDF5 writer
234
+ screening.py Numba/CuPy induced-vector-potential kernels
235
+
236
+ solution/
237
+ data.py TDGLData, DynamicsData, HDF5 data helpers
238
+ solution.py Solution object and analysis methods
239
+ plot_solution.py Solution-bound Matplotlib plotting helpers
240
+
241
+ sources/
242
+ constant.py Uniform-field source
243
+ loop.py Circular current-loop vector potential
244
+ scaling.py LinearRamp and Scale parameters
245
+
246
+ visualization/
247
+ common.py Quantity enum, plot defaults, utility helpers
248
+ io.py HDF5 plotting data extraction
249
+ snapshot.py Snapshot generation
250
+ animate.py Animation generation
251
+ interactive.py Interactive plotting helpers
252
+ convert.py XDMF export
253
+ monitor.py Live monitoring
254
+ plots3d.py 3D plotting helpers
255
+ vortex.py Vortex detection and vortex-tube rendering
256
+ analysis.py Supercurrent and multi-slice analysis panels
257
+ physics.py Voltage, V-I, free-energy, and Lorentz plots
258
+ ```
259
+
260
+ ## Installation
261
+
262
+ ### Requirements
263
+
264
+ The package metadata targets:
265
+
266
+ ```text
267
+ Python >= 3.14
268
+ ```
269
+
270
+ Core Python dependencies:
271
+
272
+ - NumPy
273
+ - SciPy
274
+ - h5py
275
+ - Numba
276
+ - Pint
277
+ - cloudpickle
278
+ - Matplotlib
279
+ - Pillow
280
+
281
+ Optional dependencies:
282
+
283
+ - CuPy for CUDA GPU screening.
284
+ - PyVista for 3D visualization.
285
+ - meshio for XDMF export.
286
+ - pytest for development and testing.
287
+
288
+ ### Install From a Local Checkout
289
+
290
+ ```bash
291
+ pip install .
292
+ ```
293
+
294
+ ### Editable Development Install
295
+
296
+ ```bash
297
+ pip install -e ".[dev,visualization]"
298
+ ```
299
+
300
+ ### Install From requirements.txt
301
+
302
+ `requirements.txt` includes the optional packages listed in this repository:
303
+
304
+ ```bash
305
+ pip install -r requirements.txt
306
+ ```
307
+
308
+ ### Optional GPU Package
309
+
310
+ Install a CuPy package matching your CUDA version. For CUDA 12.x:
311
+
312
+ ```bash
313
+ pip install cupy-cuda12x
314
+ ```
315
+
316
+ For CUDA 11.x:
317
+
318
+ ```bash
319
+ pip install cupy-cuda11x
320
+ ```
321
+
322
+ ## Quick Start
323
+
324
+ This example builds a cone-shaped superconductor, generates a tetrahedral
325
+ mesh, solves a short TDGL run with a uniform dimensionless `Bz` field, and
326
+ plots the final order-parameter magnitude on a cross-section.
327
+
328
+ ```python
329
+ import matplotlib.pyplot as plt
330
+ import tdgl3d
331
+
332
+ layer = tdgl3d.Layer(
333
+ coherence_length=1.0,
334
+ london_lambda=2.0,
335
+ )
336
+
337
+ vertices, facets = tdgl3d.cone(
338
+ radius_bottom=2.0,
339
+ radius_top=0.3,
340
+ height=3.0,
341
+ n_radial=24,
342
+ n_height=8,
343
+ )
344
+
345
+ volume = tdgl3d.Volume("cone", vertices, facets)
346
+
347
+ device = tdgl3d.Device(
348
+ name="cone_device",
349
+ layer=layer,
350
+ volume=volume,
351
+ length_units="um",
352
+ )
353
+
354
+ device.make_mesh(max_edge_length=0.9, min_points=150)
355
+ print(device.mesh_stats())
356
+
357
+ options = tdgl3d.SolverOptions(
358
+ solve_time=2.0,
359
+ dt_init=1e-3,
360
+ dt_max=5e-2,
361
+ adaptive=True,
362
+ save_every=50,
363
+ output_file="cone_solution.h5",
364
+ )
365
+
366
+ solution = tdgl3d.solve(
367
+ device=device,
368
+ options=options,
369
+ applied_vector_potential=0.3,
370
+ seed_noise=0.01,
371
+ )
372
+
373
+ fig, ax = solution.plot_order_parameter(slice_axis="z")
374
+ plt.show()
375
+ ```
376
+
377
+ ## Geometry and Device Construction
378
+
379
+ ### Built-In Geometry Generators
380
+
381
+ Each geometry function returns:
382
+
383
+ ```python
384
+ vertices, facets = tdgl3d.geometry_function(...)
385
+ ```
386
+
387
+ where `vertices` has shape `(N, 3)` and `facets` has shape `(M, 3)`.
388
+
389
+ | Function | Purpose |
390
+ | --- | --- |
391
+ | `cone(radius_bottom, radius_top, height)` | Cone or truncated cone aligned with `z` |
392
+ | `cylinder(radius, height)` | Cylinder, implemented as a cone special case |
393
+ | `cuboid(lx, ly, lz)` | Rectangular box |
394
+ | `box(lx, ly, lz)` | Alias-style box generator |
395
+ | `cube(side)` | Cube |
396
+ | `pyramid(...)` | Pyramid with polygonal or rectangular base |
397
+ | `sphere(radius)` | Spherical surface mesh |
398
+ | `ellipsoid(a, b, c)` | Axis-aligned ellipsoid |
399
+
400
+ Example:
401
+
402
+ ```python
403
+ vertices, facets = tdgl3d.sphere(radius=2.0, n_phi=30, n_theta=60)
404
+ tdgl3d.close_surface(vertices, facets)
405
+ volume = tdgl3d.Volume("sphere", vertices, facets)
406
+ ```
407
+
408
+ ### Custom Closed Surface Meshes
409
+
410
+ You may construct a `Volume` from your own closed triangular surface mesh:
411
+
412
+ ```python
413
+ volume = tdgl3d.Volume(
414
+ name="custom",
415
+ vertices=vertices_array,
416
+ facets=triangles_array,
417
+ )
418
+ ```
419
+
420
+ The surface must be watertight. A closed triangular mesh should have each
421
+ surface edge shared by exactly two triangles. Use `close_surface()` to check
422
+ simple watertightness before meshing.
423
+
424
+ ### Device Transformations
425
+
426
+ `Volume` and `Device` support basic transformations:
427
+
428
+ ```python
429
+ device_shifted = device.translate(dx=1.0, dy=0.0, dz=0.5)
430
+ device_scaled = device.scale(sx=1.0, sy=1.0, sz=2.0)
431
+ device_rotated = device.rotate(angle=45.0, axis="z")
432
+ ```
433
+
434
+ Transformed devices do not keep the old mesh; regenerate the mesh after
435
+ changing geometry.
436
+
437
+ ### Mesh Generation
438
+
439
+ ```python
440
+ device.make_mesh(max_edge_length=1.0, min_points=300)
441
+ ```
442
+
443
+ Parameters:
444
+
445
+ - `max_edge_length`: target mesh spacing in the device length units.
446
+ - `min_points`: minimum interior point target used during point filling.
447
+
448
+ Inspect the generated mesh:
449
+
450
+ ```python
451
+ stats = device.mesh_stats()
452
+ quality = device.mesh.quality_metrics()
453
+ print(stats)
454
+ print(quality["summary"])
455
+ ```
456
+
457
+ Plot the surface projection or filled surface projection:
458
+
459
+ ```python
460
+ device.plot(mesh=True)
461
+ device.draw(alpha=0.5)
462
+ ```
463
+
464
+ ### Physical Scales
465
+
466
+ `Device` exposes useful dimensional scales through Pint:
467
+
468
+ ```python
469
+ print(device.coherence_length)
470
+ print(device.Bc2)
471
+ print(device.A0)
472
+ print(device.K0)
473
+ print(device.tau0(conductivity=1e7))
474
+ print(device.V0(conductivity=1e7))
475
+ ```
476
+
477
+ ## Solver Usage
478
+
479
+ ### SolverOptions
480
+
481
+ `SolverOptions` controls integration, output, screening, sparse solver choice,
482
+ GPU use, and monitoring.
483
+
484
+ | Option | Default | Meaning |
485
+ | --- | --- | --- |
486
+ | `solve_time` | `100.0` | Simulation time after optional skip period |
487
+ | `skip_time` | `0.0` | Initial time not saved to snapshots |
488
+ | `dt_init` | `1e-4` | Initial time step |
489
+ | `dt_max` | `1e-2` | Maximum adaptive time step |
490
+ | `adaptive` | `True` | Enable adaptive time stepping |
491
+ | `adaptive_window` | `10` | Window for time-step adaptation |
492
+ | `adaptive_time_step_multiplier` | `0.25` | Retry multiplier after failed step |
493
+ | `max_solve_retries` | `10` | Maximum retries per step |
494
+ | `output_file` | `None` | HDF5 output path; temporary file if unset |
495
+ | `field_units` | `"mT"` | Metadata field units |
496
+ | `current_units` | `"uA"` | Metadata current units |
497
+ | `save_every` | `100` | Save every N solver steps |
498
+ | `include_screening` | `False` | Enable magnetic self-field iteration |
499
+ | `screening_step_size` | `0.1` | Polyak screening step size |
500
+ | `screening_tolerance` | `1e-3` | Stored screening convergence parameter |
501
+ | `screening_drag` | `0.5` | Polyak heavy-ball drag |
502
+ | `terminal_psi` | `0.0` | `|psi|` imposed at terminal sites |
503
+ | `sparse_solver` | `"superlu"` | Sparse backend name |
504
+ | `gpu` | `False` | Use CuPy screening kernel |
505
+ | `monitor` | `False` | Enable SWMR-compatible live monitoring |
506
+ | `monitor_update_interval` | `2.0` | Monitor refresh interval |
507
+ | `pause_on_interrupt` | `True` | Save current state on keyboard interrupt |
508
+
509
+ Example:
510
+
511
+ ```python
512
+ options = tdgl3d.SolverOptions(
513
+ solve_time=10.0,
514
+ skip_time=1.0,
515
+ dt_init=1e-3,
516
+ dt_max=5e-2,
517
+ adaptive=True,
518
+ save_every=100,
519
+ output_file="run.h5",
520
+ )
521
+ ```
522
+
523
+ ### Applied Vector Potential
524
+
525
+ `applied_vector_potential` may be:
526
+
527
+ - `None` or `0`: no applied vector potential.
528
+ - `float`: interpreted as a uniform `Bz` field.
529
+ - `numpy.ndarray` with shape `(num_edges, 3)`: value at edge midpoints.
530
+ - Callable or `Parameter`: evaluated as `A(x, y, z)`.
531
+
532
+ Uniform field:
533
+
534
+ ```python
535
+ solution = tdgl3d.solve(device, options, applied_vector_potential=0.3)
536
+ ```
537
+
538
+ Callable field:
539
+
540
+ ```python
541
+ def A_custom(x, y, z):
542
+ import numpy as np
543
+ A = np.zeros((len(x), 3))
544
+ A[:, 0] = -0.5 * y
545
+ A[:, 1] = 0.5 * x
546
+ return A
547
+
548
+ solution = tdgl3d.solve(device, options, applied_vector_potential=A_custom)
549
+ ```
550
+
551
+ ### Disorder or Pair-Breaking Parameter
552
+
553
+ `disorder_epsilon` can be a scalar, array, spatial callable, or time-dependent
554
+ callable. Time-dependent functions must accept keyword-only `t`.
555
+
556
+ ```python
557
+ def epsilon(x, y, z, *, t):
558
+ import numpy as np
559
+ value = max(1.0 - 0.1 * t, 0.5)
560
+ return value * np.ones_like(x)
561
+
562
+ solution = tdgl3d.solve(
563
+ device,
564
+ options,
565
+ disorder_epsilon=epsilon,
566
+ )
567
+ ```
568
+
569
+ ### Initial Conditions
570
+
571
+ Initial-condition controls:
572
+
573
+ - `seed_noise`: small complex noise added to the initial state.
574
+ - `field_cooling=True`: initialize a moderate-amplitude random-phase state to
575
+ help vortex nucleation.
576
+ - `seed_solution`: initialize from a previous `Solution`; different meshes are
577
+ handled by interpolation.
578
+
579
+ ```python
580
+ solution2 = tdgl3d.solve(
581
+ device,
582
+ options,
583
+ applied_vector_potential=0.4,
584
+ seed_solution=solution1,
585
+ )
586
+ ```
587
+
588
+ ### Manual Solver Access
589
+
590
+ For advanced workflows:
591
+
592
+ ```python
593
+ from tdgl3d.solver import TDGLSolver
594
+
595
+ solver = TDGLSolver(
596
+ device=device,
597
+ options=options,
598
+ applied_vector_potential=0.3,
599
+ )
600
+
601
+ for _ in range(100):
602
+ dt, converged = solver.update()
603
+ ```
604
+
605
+ Most users should prefer `tdgl3d.solve()`.
606
+
607
+ ## Magnetic Sources
608
+
609
+ ### Uniform Field Source
610
+
611
+ ```python
612
+ A = tdgl3d.sources.ConstantField(Bz=0.5)
613
+ solution = tdgl3d.solve(device, options, applied_vector_potential=A)
614
+ ```
615
+
616
+ The source uses the symmetric gauge:
617
+
618
+ ```text
619
+ A = (Bz / 2) (-y, x, 0)
620
+ ```
621
+
622
+ ### Circular Current Loop
623
+
624
+ ```python
625
+ loop = tdgl3d.sources.CurrentLoop(
626
+ current=1.0,
627
+ radius=5.0,
628
+ center=(0.0, 0.0, 0.0),
629
+ )
630
+
631
+ solution = tdgl3d.solve(device, options, applied_vector_potential=loop)
632
+ ```
633
+
634
+ ### Time-Dependent Scaling
635
+
636
+ ```python
637
+ ramp = tdgl3d.sources.LinearRamp(
638
+ tmin=0.0,
639
+ tmax=10.0,
640
+ vmin=0.0,
641
+ vmax=1.0,
642
+ )
643
+ ```
644
+
645
+ Custom `Parameter` objects can be combined arithmetically:
646
+
647
+ ```python
648
+ param = 0.5 * tdgl3d.sources.Scale(2.0)
649
+ ```
650
+
651
+ ## Screening and GPU Acceleration
652
+
653
+ Enable magnetic self-field screening:
654
+
655
+ ```python
656
+ options = tdgl3d.SolverOptions(
657
+ solve_time=5.0,
658
+ include_screening=True,
659
+ screening_step_size=0.1,
660
+ screening_drag=0.5,
661
+ gpu=False,
662
+ )
663
+ ```
664
+
665
+ Use the GPU kernel when CuPy is installed:
666
+
667
+ ```python
668
+ options.gpu = True
669
+ ```
670
+
671
+ Notes:
672
+
673
+ - The screening calculation is typically the most expensive part of a run.
674
+ - The CPU path is Numba-accelerated and may compile on first use.
675
+ - The GPU path requires a compatible CUDA runtime and a matching CuPy package.
676
+ - Very large meshes can exceed GPU memory because the kernel evaluates many
677
+ source-site and target-edge interactions.
678
+
679
+ ## Terminal Currents and Probe Points
680
+
681
+ ### Terminal Volumes
682
+
683
+ Terminals are represented as `Volume` objects associated with a `Device`.
684
+ The solver identifies mesh sites belonging to those terminal regions and uses
685
+ them for scalar-potential boundary feedback and optional `psi` suppression.
686
+
687
+ ```python
688
+ terminal_left = tdgl3d.Volume("left", left_vertices, left_facets)
689
+ terminal_right = tdgl3d.Volume("right", right_vertices, right_facets)
690
+
691
+ device = tdgl3d.Device(
692
+ "wire",
693
+ layer=layer,
694
+ volume=body,
695
+ terminals=[terminal_left, terminal_right],
696
+ )
697
+ ```
698
+
699
+ Inspect terminal metadata:
700
+
701
+ ```python
702
+ print(device.terminal_info())
703
+ ```
704
+
705
+ ### Terminal Driving
706
+
707
+ The solver accepts `terminal_currents` in `tdgl3d.solve()` as either a
708
+ dictionary or a callable returning a dictionary. The implemented terminal
709
+ update distinguishes two value forms:
710
+
711
+ - Scalar value: direct scalar-potential bias at that terminal.
712
+ - `{"current": I}`: current-bias feedback that adjusts terminal `mu` to drive
713
+ the measured normal current toward `I`.
714
+
715
+ Voltage-bias style input:
716
+
717
+ ```python
718
+ solution = tdgl3d.solve(
719
+ device,
720
+ options,
721
+ terminal_currents={"left": 0.5, "right": -0.5},
722
+ )
723
+ ```
724
+
725
+ Current-bias feedback:
726
+
727
+ ```python
728
+ solution = tdgl3d.solve(
729
+ device,
730
+ options,
731
+ terminal_currents={
732
+ "left": {"current": 1.0},
733
+ "right": {"current": -1.0},
734
+ },
735
+ )
736
+ ```
737
+
738
+ Time-dependent driving:
739
+
740
+ ```python
741
+ def drive(t):
742
+ return {
743
+ "left": {"current": 1.0},
744
+ "right": {"current": -1.0},
745
+ }
746
+
747
+ solution = tdgl3d.solve(
748
+ device,
749
+ options,
750
+ terminal_currents=drive,
751
+ )
752
+ ```
753
+
754
+ ### Current Conservation Check
755
+
756
+ Static currents:
757
+
758
+ ```python
759
+ tdgl3d.validate_terminal_currents(
760
+ {"left": 1.0, "right": -1.0},
761
+ terminal_names=["left", "right"],
762
+ )
763
+ ```
764
+
765
+ Time-dependent currents:
766
+
767
+ ```python
768
+ def currents(t):
769
+ return {"left": 1.0, "right": -1.0}
770
+
771
+ tdgl3d.validate_terminal_currents(
772
+ currents,
773
+ terminal_names=["left", "right"],
774
+ options=options,
775
+ )
776
+ ```
777
+
778
+ `validate_terminal_currents()` currently validates flat scalar dictionaries or
779
+ callables returning flat scalar dictionaries. It checks that terminal names are
780
+ known and that the scalar values sum to zero. For nested current-bias
781
+ dictionaries such as `{"left": {"current": 1.0}}`, check conservation manually
782
+ before passing them to `solve()`.
783
+
784
+ The sum over all terminal currents must be zero.
785
+
786
+ ### Probe Points
787
+
788
+ Probe points are physical coordinates used to record scalar potential during
789
+ the run:
790
+
791
+ ```python
792
+ device = tdgl3d.Device(
793
+ "device_with_probes",
794
+ layer=layer,
795
+ volume=volume,
796
+ probe_points=[
797
+ [-1.0, 0.0, 0.5],
798
+ [1.0, 0.0, 0.5],
799
+ ],
800
+ )
801
+ ```
802
+
803
+ After solving:
804
+
805
+ ```python
806
+ voltage = solution.dynamics.voltage(i=0, j=1)
807
+ mean_v = solution.dynamics.mean_voltage(i=0, j=1, tmin=1.0)
808
+ ```
809
+
810
+ ## Solution Analysis
811
+
812
+ Load a solution:
813
+
814
+ ```python
815
+ solution = tdgl3d.Solution.from_hdf5("run.h5")
816
+ ```
817
+
818
+ Common properties:
819
+
820
+ ```python
821
+ psi = solution.order_parameter
822
+ abs_psi = solution.order_parameter_magnitude
823
+ phase = solution.phase
824
+ mu = solution.scalar_potential
825
+ Js = solution.supercurrent
826
+ Jn = solution.normal_current
827
+ times = solution.times
828
+ ```
829
+
830
+ Select data by saved frame:
831
+
832
+ ```python
833
+ data_range = solution.data_range
834
+ data0 = solution.get_data_at_step(data_range[0])
835
+ last = solution.get_data_at_step(data_range[1])
836
+ ```
837
+
838
+ Find the closest saved frame to a target simulation time:
839
+
840
+ ```python
841
+ frame = solution.closest_solve_step(target_time=5.0)
842
+ ```
843
+
844
+ ### Derived Quantities
845
+
846
+ ```python
847
+ magnetic_moment = solution.magnetic_moment()
848
+ magnetic_field = solution.magnetic_field()
849
+ free_energy = solution.free_energy()
850
+ superfluid_velocity = solution.superfluid_velocity()
851
+ lambda_eff = solution.london_penetration_depth()
852
+ vorticity = solution.vorticity
853
+ ```
854
+
855
+ ### Interpolation
856
+
857
+ Order parameter:
858
+
859
+ ```python
860
+ positions = solution.mesh.sites[:10]
861
+ psi_at_positions = solution.interp_order_parameter(positions)
862
+ ```
863
+
864
+ Current density:
865
+
866
+ ```python
867
+ J = solution.interp_current_density(
868
+ positions,
869
+ dataset=None, # None = supercurrent + normal current
870
+ method="nearest",
871
+ )
872
+ ```
873
+
874
+ Regular 3D grid:
875
+
876
+ ```python
877
+ xg, yg, zg, Jgrid = solution.grid_current_density(
878
+ grid_shape=(40, 40, 40),
879
+ method="nearest",
880
+ )
881
+ ```
882
+
883
+ ### Fluxoid Quantization
884
+
885
+ Circular contour:
886
+
887
+ ```python
888
+ contour = tdgl3d.make_fluxoid_contour_circle(
889
+ center=(0.0, 0.0, 1.0),
890
+ radius=0.5,
891
+ normal=(0.0, 0.0, 1.0),
892
+ n_points=64,
893
+ )
894
+
895
+ fluxoid = solution.fluxoid(contour, kappa=solution.device.kappa)
896
+ print(fluxoid.flux_part, fluxoid.supercurrent_part)
897
+ ```
898
+
899
+ Validation helper:
900
+
901
+ ```python
902
+ result = solution.validate_flux_quantization(
903
+ contour,
904
+ kappa=solution.device.kappa,
905
+ tolerance=0.1,
906
+ )
907
+ print(result)
908
+ ```
909
+
910
+ Rectangular contour:
911
+
912
+ ```python
913
+ contour = tdgl3d.make_fluxoid_contour_rectangular(
914
+ center=(0.0, 0.0, 1.0),
915
+ width=1.0,
916
+ height=1.0,
917
+ normal=(0.0, 0.0, 1.0),
918
+ n_points_per_side=16,
919
+ )
920
+ ```
921
+
922
+ ### Current Through a Surface
923
+
924
+ For a sampled planar surface:
925
+
926
+ ```python
927
+ current = solution.current_through_surface(
928
+ surface_points=points_on_surface,
929
+ surface_normal=[1.0, 0.0, 0.0],
930
+ )
931
+ ```
932
+
933
+ For time series through named paths:
934
+
935
+ ```python
936
+ from tdgl3d.solution.data import get_current_through_paths
937
+
938
+ paths = {"center": points_on_surface}
939
+ currents = get_current_through_paths("run.h5", paths)
940
+ ```
941
+
942
+ ## Visualization
943
+
944
+ ### Solution Plot Shortcuts
945
+
946
+ Each plotting method returns `(fig, ax)`:
947
+
948
+ ```python
949
+ solution.plot_order_parameter(slice_axis="z")
950
+ solution.plot_phase(slice_axis="z")
951
+ solution.plot_scalar_potential(slice_axis="z")
952
+ solution.plot_supercurrent(slice_axis="z")
953
+ solution.plot_currents(slice_axis="z")
954
+ solution.plot_vorticity(slice_axis="z")
955
+ solution.plot_vector_potential(slice_axis="z")
956
+ ```
957
+
958
+ Slice options:
959
+
960
+ - `slice_axis`: `"x"`, `"y"`, or `"z"`.
961
+ - `slice_value`: coordinate of the slice. If omitted, the midpoint is used.
962
+
963
+ ### Snapshot Generation
964
+
965
+ ```python
966
+ from tdgl3d.visualization import generate_snapshots
967
+
968
+ figures = generate_snapshots(
969
+ input_path="run.h5",
970
+ steps=[0, 5, 10],
971
+ quantities=["order_parameter", "phase", "supercurrent"],
972
+ slice_axis="z",
973
+ )
974
+ ```
975
+
976
+ ### Animation
977
+
978
+ ```python
979
+ from tdgl3d.visualization import create_animation
980
+
981
+ create_animation(
982
+ input_file="run.h5",
983
+ output_file="order_parameter.gif",
984
+ quantity="order_parameter",
985
+ fps=10,
986
+ ngrid=80,
987
+ )
988
+ ```
989
+
990
+ For MP4 output, Matplotlib needs a working `ffmpeg` writer.
991
+
992
+ ### Command-Line Interface
993
+
994
+ The package defines the console script:
995
+
996
+ ```bash
997
+ tdgl3d-visualize
998
+ ```
999
+
1000
+ Examples:
1001
+
1002
+ ```bash
1003
+ tdgl3d-visualize -i run.h5 snapshot --steps 0 5 10
1004
+ tdgl3d-visualize -i run.h5 interactive
1005
+ tdgl3d-visualize -i run.h5 -o solution.xdmf convert
1006
+ tdgl3d-visualize -i run.h5 monitor
1007
+ ```
1008
+
1009
+ ### 3D and Vortex Utilities
1010
+
1011
+ The visualization package also includes:
1012
+
1013
+ - `plot_3d_order_parameter`
1014
+ - `plot_3d_scalar_potential`
1015
+ - `plot_3d_vortex_cores`
1016
+ - `plot_3d_volume`
1017
+ - `plot_3d_isosurface`
1018
+ - `detect_vortex_positions`
1019
+ - `build_core_tubes`
1020
+ - `make_vortex_slice_gif`
1021
+ - `make_vortex_3d_gif`
1022
+ - `plot_supercurrent_analysis`
1023
+ - `plot_multi_z_slices`
1024
+ - `plot_voltage_vs_time`
1025
+ - `plot_vi_curve`
1026
+ - `plot_free_energy_density`
1027
+ - `plot_total_free_energy_vs_time`
1028
+
1029
+ ## HDF5 Output Format
1030
+
1031
+ The solver writes an HDF5 file containing the full state required for
1032
+ post-processing.
1033
+
1034
+ ```text
1035
+ /
1036
+ attrs:
1037
+ solver
1038
+ version
1039
+ field_units
1040
+ current_units
1041
+ total_steps
1042
+ total_saves
1043
+
1044
+ device/
1045
+ attrs:
1046
+ name
1047
+ length_units
1048
+ layer/
1049
+ attrs:
1050
+ coherence_length
1051
+ london_lambda
1052
+ thickness
1053
+ conductivity
1054
+ u
1055
+ gamma
1056
+ volume/
1057
+ attrs:
1058
+ name
1059
+ vertices
1060
+ facets
1061
+ holes/
1062
+ terminals/
1063
+ probe_points
1064
+
1065
+ mesh/
1066
+ sites
1067
+ elements
1068
+ boundary_indices
1069
+ volumes
1070
+ edge_mesh/
1071
+ edges
1072
+ edge_centers
1073
+ directions
1074
+ edge_lengths
1075
+ dual_face_areas
1076
+ boundary_edge_indices
1077
+
1078
+ options/
1079
+ attrs:
1080
+ solve_time
1081
+ skip_time
1082
+ dt_init
1083
+ dt_max
1084
+ adaptive
1085
+ save_every
1086
+ include_screening
1087
+ gpu
1088
+
1089
+ data/
1090
+ 0/
1091
+ attrs:
1092
+ dt
1093
+ time
1094
+ step
1095
+ psi
1096
+ mu
1097
+ supercurrent
1098
+ normal_current
1099
+ A_applied
1100
+ A_induced
1101
+ 1/
1102
+ ...
1103
+
1104
+ dynamics/
1105
+ time
1106
+ dt
1107
+ step
1108
+ free_energy
1109
+ mu
1110
+ ```
1111
+
1112
+ `psi` is stored as two columns: real and imaginary parts. The `Solution` and
1113
+ `TDGLData` loaders reconstruct it as a complex array.
1114
+
1115
+ Because the device and mesh are embedded in the solution file, most analysis
1116
+ and visualization functions do not require the original Python script that
1117
+ created the simulation.
1118
+
1119
+ ## Testing and Validation
1120
+
1121
+ Run the test suite:
1122
+
1123
+ ```bash
1124
+ pytest tdgl3d/test
1125
+ ```
1126
+
1127
+ Or use the package helper:
1128
+
1129
+ ```python
1130
+ import tdgl3d
1131
+ tdgl3d.testing.run()
1132
+ ```
1133
+
1134
+ The tests exercise:
1135
+
1136
+ - Geometry generation and closed-volume containment checks.
1137
+ - Tetrahedral mesh generation and finite-volume topology.
1138
+ - Mesh quality metrics.
1139
+ - Gradient, divergence, Laplacian, and link-variable construction.
1140
+ - Short TDGL solves on cone and box geometries.
1141
+ - Seed-solution continuation and interpolation across meshes.
1142
+ - Time-dependent pair-breaking/disorder functions.
1143
+ - Fluxoid contour generation and fluxoid computation.
1144
+ - Numba screening kernels and optional CPU/GPU consistency.
1145
+ - HDF5 device and solution round trips.
1146
+ - Solver option storage.
1147
+ - Terminal current validation.
1148
+ - Solution analysis methods.
1149
+ - Snapshot, animation, monitor, and CLI import paths.
1150
+ - Plotting helpers and visualization utilities.
1151
+
1152
+ For a quick smoke test, run:
1153
+
1154
+ ```bash
1155
+ pytest tdgl3d/test/test_fast.py
1156
+ ```
1157
+
1158
+ For simulation-level tests, run:
1159
+
1160
+ ```bash
1161
+ pytest tdgl3d/test/test_cone.py
1162
+ pytest tdgl3d/test/test_features.py
1163
+ ```
1164
+
1165
+ ## Reproducibility Checklist
1166
+
1167
+ For reproducible simulation studies, record:
1168
+
1169
+ - Package version and dependency versions:
1170
+
1171
+ ```python
1172
+ import tdgl3d
1173
+ print(tdgl3d.version_table(verbose=True))
1174
+ ```
1175
+
1176
+ - Python version and operating system.
1177
+ - Geometry generator parameters or the exact custom surface mesh.
1178
+ - Material parameters in `Layer`.
1179
+ - Device length units.
1180
+ - Mesh generation parameters: `max_edge_length`, `min_points`.
1181
+ - Solver options.
1182
+ - Applied vector potential definition.
1183
+ - Disorder or pair-breaking function.
1184
+ - Random-noise amplitude and random seed behavior where relevant.
1185
+ - Whether screening and GPU acceleration were enabled.
1186
+ - Output HDF5 file.
1187
+
1188
+ The HDF5 solution stores most simulation metadata, including the embedded
1189
+ device, mesh, options, saved TDGL snapshots, and dynamics.
1190
+
1191
+ ## Troubleshooting
1192
+
1193
+ ### Mesh Generation Is Slow
1194
+
1195
+ Reduce `min_points`, increase `max_edge_length`, or start with a simpler
1196
+ surface mesh. Very fine surface meshes and small edge-length targets can create
1197
+ large Delaunay problems.
1198
+
1199
+ ### Solver Diverges or Reports NaN Values
1200
+
1201
+ Try:
1202
+
1203
+ - Decrease `dt_init`.
1204
+ - Decrease `dt_max`.
1205
+ - Increase mesh resolution.
1206
+ - Reduce abrupt changes in time-dependent fields.
1207
+ - Use `seed_noise=0.0` for stable Meissner-like initialization.
1208
+ - Use a seed solution for continuation in field/current sweeps.
1209
+
1210
+ ### No Data Appears in the Output File
1211
+
1212
+ Check `save_every`, `solve_time`, and `skip_time`. Snapshots are saved when
1213
+ simulation time has passed `skip_time` and the solver step is divisible by
1214
+ `save_every`.
1215
+
1216
+ ### GPU Screening Fails
1217
+
1218
+ Check that:
1219
+
1220
+ - CuPy is installed.
1221
+ - The CuPy package matches the CUDA runtime.
1222
+ - A CUDA-capable GPU is visible.
1223
+ - The mesh is small enough for available GPU memory.
1224
+
1225
+ Set `gpu=False` to use the Numba CPU path.
1226
+
1227
+ ### Interactive or 3D Visualization Fails
1228
+
1229
+ Install optional visualization dependencies:
1230
+
1231
+ ```bash
1232
+ pip install pyvista meshio
1233
+ ```
1234
+
1235
+ For headless servers, use Matplotlib's non-GUI backend:
1236
+
1237
+ ```python
1238
+ with tdgl3d.non_gui_backend():
1239
+ figures = tdgl3d.generate_snapshots("run.h5")
1240
+ ```
1241
+
1242
+ ## Known Limitations
1243
+
1244
+ - The mesher is intended for accessible Python workflows and exploratory
1245
+ simulations. It is not a replacement for specialized constrained
1246
+ tetrahedral mesh generators for very complex CAD geometries.
1247
+ - Holes are represented in the `Device` data model, but robust hole-aware
1248
+ constrained meshing requires careful geometry preparation.
1249
+ - Dual-face areas are approximate and based on local tetrahedral geometry.
1250
+ - Screening uses a direct Biot-Savart summation, which can be expensive for
1251
+ large meshes.
1252
+ - Current-through-surface helpers use nearest-edge interpolation and should be
1253
+ interpreted as practical post-processing estimates.
1254
+ - The solver operates in dimensionless TDGL units internally; dimensional
1255
+ interpretation requires consistent material parameters and length units.
1256
+ - Sparse solver options currently validate several backend names, but the
1257
+ implemented solve path primarily uses SciPy sparse direct solvers.
1258
+
1259
+ ## License
1260
+
1261
+ MIT License.
1262
+
1263
+ ## Citation
1264
+
1265
+ If you use our work, please cite:
1266
+
1267
+ Tanvir Hassan and A. Hasnat, `tdgl3d: Three-Dimensional Time-Dependent
1268
+ Ginzburg-Landau Solver in Python` (manuscript submitted).