nmag-python-3 0.0.2__tar.gz → 0.0.4__tar.gz

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 (161) hide show
  1. {nmag_python_3-0.0.2/src/nmag_python_3.egg-info → nmag_python_3-0.0.4}/PKG-INFO +20 -2
  2. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/README.md +19 -1
  3. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/pyproject.toml +5 -1
  4. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/__init__.py +16 -0
  5. nmag_python_3-0.0.4/src/nmag/cli/__init__.py +1 -0
  6. nmag_python_3-0.0.4/src/nmag/cli/nmagpp.py +43 -0
  7. nmag_python_3-0.0.4/src/nmag/vtk_export.py +124 -0
  8. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4/src/nmag_python_3.egg-info}/PKG-INFO +20 -2
  9. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag_python_3.egg-info/SOURCES.txt +7 -0
  10. nmag_python_3-0.0.4/src/nmag_python_3.egg-info/entry_points.txt +3 -0
  11. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/__init__.py +8 -0
  12. nmag_python_3-0.0.4/src/nmesh/cli/__init__.py +1 -0
  13. nmag_python_3-0.0.4/src/nmesh/cli/nmeshimport.py +39 -0
  14. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/io/__init__.py +9 -0
  15. nmag_python_3-0.0.4/src/nmesh/io/netgen.py +122 -0
  16. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/LICENSE +0 -0
  17. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/setup.cfg +0 -0
  18. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/anisotropy/__init__.py +0 -0
  19. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/anisotropy/anisotropy.py +0 -0
  20. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/anisotropy/evaluation.py +0 -0
  21. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/anisotropy/model.py +0 -0
  22. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/anisotropy/predefined.py +0 -0
  23. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/anisotropy/py.typed +0 -0
  24. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/anisotropy/values.py +0 -0
  25. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/mag_material/__init__.py +0 -0
  26. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/mag_material/mag_material.py +0 -0
  27. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/mag_material/parameters.py +0 -0
  28. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/mag_material/py.typed +0 -0
  29. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/backends.py +0 -0
  30. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/checkpoint.py +0 -0
  31. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/config.py +0 -0
  32. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/demag/__init__.py +0 -0
  33. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/demag/bem_operator.py +0 -0
  34. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/demag/geometry.py +0 -0
  35. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/demag/lindholm.py +0 -0
  36. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/demag/lindholm_fast.py +0 -0
  37. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/demag/linear.py +0 -0
  38. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/dynamics/__init__.py +0 -0
  39. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/output.py +0 -0
  40. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/parallel.py +0 -0
  41. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/py.typed +0 -0
  42. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/resources.py +0 -0
  43. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/__init__.py +0 -0
  44. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/anisotropy/__init__.py +0 -0
  45. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/anisotropy/fields.py +0 -0
  46. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/anisotropy/materials.py +0 -0
  47. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/__init__.py +0 -0
  48. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/bem/__init__.py +0 -0
  49. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/bem/diagnostics.py +0 -0
  50. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/bem/dirichlet.py +0 -0
  51. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/bem/hierarchical.py +0 -0
  52. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/bem/operator.py +0 -0
  53. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/fem/__init__.py +0 -0
  54. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/fem/assembly.py +0 -0
  55. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/fem/charges.py +0 -0
  56. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/fem/geometry.py +0 -0
  57. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/fields/__init__.py +0 -0
  58. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/fields/auxiliary.py +0 -0
  59. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/fields/probe.py +0 -0
  60. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/fields/recovery.py +0 -0
  61. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/demag/solver.py +0 -0
  62. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/dynamics/__init__.py +0 -0
  63. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/dynamics/advance.py +0 -0
  64. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/dynamics/integrator.py +0 -0
  65. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/exchange/__init__.py +0 -0
  66. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/exchange/coefficients.py +0 -0
  67. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/exchange/fields.py +0 -0
  68. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/exchange/llg_rhs.py +0 -0
  69. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/fields/__init__.py +0 -0
  70. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/fields/arrays.py +0 -0
  71. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/fields/availability.py +0 -0
  72. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/fields/averages.py +0 -0
  73. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/fields/derived.py +0 -0
  74. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/fields/maxangle.py +0 -0
  75. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/fields/probes.py +0 -0
  76. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/implicit_dynamics.py +0 -0
  77. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/mesh/__init__.py +0 -0
  78. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/mesh/geometry.py +0 -0
  79. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/mesh/materials.py +0 -0
  80. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/mesh/probe.py +0 -0
  81. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/restart.py +0 -0
  82. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag/simulation/support.py +0 -0
  83. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag_python_3.egg-info/dependency_links.txt +0 -0
  84. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag_python_3.egg-info/requires.txt +0 -0
  85. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmag_python_3.egg-info/top_level.txt +0 -0
  86. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/backend.py +0 -0
  87. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/geometry/__init__.py +0 -0
  88. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/geometry/boolean_operations.py +0 -0
  89. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/geometry/primitives.py +0 -0
  90. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/geometry/transform.py +0 -0
  91. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/io/ascii.py +0 -0
  92. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/io/legacy_nmesh_hdf5.py +0 -0
  93. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/io/meshio_support.py +0 -0
  94. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesh_generation.py +0 -0
  95. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesh_io.py +0 -0
  96. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesh_model.py +0 -0
  97. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesh_utilities.py +0 -0
  98. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/__init__.py +0 -0
  99. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/driver.py +0 -0
  100. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/meshing_defaults.py +0 -0
  101. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/meshing_parameters.py +0 -0
  102. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/parity.py +0 -0
  103. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/parity_canonical.py +0 -0
  104. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/parity_comparison.py +0 -0
  105. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/parity_metrics.py +0 -0
  106. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/periodic.py +0 -0
  107. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/__init__.py +0 -0
  108. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/_constants.py +0 -0
  109. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/_types.py +0 -0
  110. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/density.py +0 -0
  111. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/engine/__init__.py +0 -0
  112. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/engine/state.py +0 -0
  113. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/engine/steps.py +0 -0
  114. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/engine/topology.py +0 -0
  115. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/forces/__init__.py +0 -0
  116. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/forces/jit.py +0 -0
  117. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/forces/neighbors.py +0 -0
  118. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/forces/simplex.py +0 -0
  119. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/forces/summary.py +0 -0
  120. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/forces/types.py +0 -0
  121. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/geometry/__init__.py +0 -0
  122. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/geometry/builder.py +0 -0
  123. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/geometry/model.py +0 -0
  124. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/seeding/__init__.py +0 -0
  125. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/seeding/periodic.py +0 -0
  126. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/seeding/points.py +0 -0
  127. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/seeding/sampling.py +0 -0
  128. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/topology/__init__.py +0 -0
  129. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/topology/finalize.py +0 -0
  130. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/relaxation/topology/recovery.py +0 -0
  131. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/mesher/sectioned_config.py +0 -0
  132. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/nmesh.py +0 -0
  133. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/py.typed +0 -0
  134. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/utils/__init__.py +0 -0
  135. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/utils/array_list_utils.py +0 -0
  136. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/utils/constants.py +0 -0
  137. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/utils/timing_memory_utils.py +0 -0
  138. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/nmesh/utils/types.py +0 -0
  139. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/si/constants.py +0 -0
  140. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/si/physical.py +0 -0
  141. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/si/py.typed +0 -0
  142. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/__init__.py +0 -0
  143. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/clock.py +0 -0
  144. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/data_writer.py +0 -0
  145. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/data_writer_collection.py +0 -0
  146. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/hysteresis.py +0 -0
  147. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/hysteresis_runner.py +0 -0
  148. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/hysteresis_schedule.py +0 -0
  149. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/inference/__init__.py +0 -0
  150. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/inference/inference.py +0 -0
  151. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/py.typed +0 -0
  152. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/quantity.py +0 -0
  153. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/simulation/simulation_core.py +0 -0
  154. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/throttler/__init__.py +0 -0
  155. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/throttler/py.typed +0 -0
  156. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/throttler/throttler.py +0 -0
  157. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/when/__init__.py +0 -0
  158. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/when/py.typed +0 -0
  159. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/src/when/when.py +0 -0
  160. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/tests/test_docs_examples.py +0 -0
  161. {nmag_python_3-0.0.2 → nmag_python_3-0.0.4}/tests/test_packaging_hygiene.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nmag-python-3
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Standalone Python 3 implementation of the Nmag micromagnetic simulation interface
5
5
  Author-email: TriMagnetix <info@trimagnetix.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -58,9 +58,27 @@ and [quickstart](https://trimagnetix.github.io/nmag-python-3/getting-started/qui
58
58
 
59
59
  ## Installation
60
60
 
61
- From a clone of this repository:
61
+ If you only want to run Nmag and do not need the source code, install the
62
+ published package in a virtual environment:
62
63
 
63
64
  ```bash
65
+ python3 -m venv .venv
66
+ .venv/bin/python -m pip install --upgrade pip
67
+ .venv/bin/python -m pip install nmag-python-3
68
+ ```
69
+
70
+ You can then run a simulation with:
71
+
72
+ ```bash
73
+ .venv/bin/python simulation.py
74
+ ```
75
+
76
+ To work from the source repository or contribute to Nmag, clone the repository
77
+ and use its setup script instead:
78
+
79
+ ```bash
80
+ git clone https://github.com/TriMagnetix/nmag-python-3.git
81
+ cd nmag-python-3
64
82
  ./scripts/setup.sh
65
83
  ```
66
84
 
@@ -20,9 +20,27 @@ and [quickstart](https://trimagnetix.github.io/nmag-python-3/getting-started/qui
20
20
 
21
21
  ## Installation
22
22
 
23
- From a clone of this repository:
23
+ If you only want to run Nmag and do not need the source code, install the
24
+ published package in a virtual environment:
24
25
 
25
26
  ```bash
27
+ python3 -m venv .venv
28
+ .venv/bin/python -m pip install --upgrade pip
29
+ .venv/bin/python -m pip install nmag-python-3
30
+ ```
31
+
32
+ You can then run a simulation with:
33
+
34
+ ```bash
35
+ .venv/bin/python simulation.py
36
+ ```
37
+
38
+ To work from the source repository or contribute to Nmag, clone the repository
39
+ and use its setup script instead:
40
+
41
+ ```bash
42
+ git clone https://github.com/TriMagnetix/nmag-python-3.git
43
+ cd nmag-python-3
26
44
  ./scripts/setup.sh
27
45
  ```
28
46
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "nmag-python-3"
7
- version = "0.0.2"
7
+ version = "0.0.4"
8
8
  authors = [{ name = "TriMagnetix", email = "info@trimagnetix.com" }]
9
9
  description = "Standalone Python 3 implementation of the Nmag micromagnetic simulation interface"
10
10
  readme = "README.md"
@@ -14,6 +14,10 @@ classifiers = [
14
14
  "Operating System :: OS Independent" ]
15
15
  dependencies = ["pint", "numpy", "scipy", "numba", "tabulate", "meshio", "h5py"]
16
16
 
17
+ [project.scripts]
18
+ nmeshimport = "nmesh.cli.nmeshimport:main"
19
+ nmagpp = "nmag.cli.nmagpp:main"
20
+
17
21
  [project.optional-dependencies]
18
22
  test = ["pytest", "pytest-cov", "pytest-watch"]
19
23
  rust = ["maturin>=1.14,<2"]
@@ -1,5 +1,7 @@
1
1
  """Public Python 3 entrypoint for the nmag rewrite."""
2
2
 
3
+ from typing import Any
4
+
3
5
  from anisotropy import (
4
6
  PredefinedAnisotropy,
5
7
  cubic_anisotropy,
@@ -15,6 +17,8 @@ from .dynamics import IntegratorConfig, IntegratorStats
15
17
  from .parallel import ParallelRuntimeInfo, parallel_runtime_info
16
18
  from .simulation import Simulation
17
19
 
20
+ _OUTPUT_EXPORTS = {"export_vtk", "resolve_snapshot"}
21
+
18
22
  __all__ = [
19
23
  "MagMaterial",
20
24
  "NmagConfig",
@@ -33,4 +37,16 @@ __all__ = [
33
37
  "parallel_runtime_info",
34
38
  "uniaxial_anisotropy",
35
39
  "want_anisotropy",
40
+ "export_vtk",
41
+ "resolve_snapshot",
36
42
  ]
43
+
44
+
45
+ def __getattr__(name: str) -> Any:
46
+ if name in _OUTPUT_EXPORTS:
47
+ from . import vtk_export
48
+
49
+ value = getattr(vtk_export, name)
50
+ globals()[name] = value
51
+ return value
52
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1 @@
1
+ """Command-line entry points for Nmag utilities."""
@@ -0,0 +1,43 @@
1
+ """Export modern Nmag snapshots to VTK-compatible files."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ from collections.abc import Sequence
7
+ from pathlib import Path
8
+
9
+ import h5py
10
+
11
+ from ..vtk_export import export_vtk, resolve_snapshot
12
+
13
+
14
+ def _parser() -> argparse.ArgumentParser:
15
+ parser = argparse.ArgumentParser(
16
+ prog="nmagpp",
17
+ description="Export a modern Nmag HDF5 snapshot to VTK.",
18
+ )
19
+ parser.add_argument("--vtk", dest="output", required=True, type=Path)
20
+ parser.add_argument("input", type=Path, help="snapshot path or simulation base name")
21
+ parser.add_argument("--mesh", type=Path, help="mesh file supplying cell topology")
22
+ parser.add_argument("--field", action="append", dest="fields", metavar="NAME")
23
+ parser.add_argument("--all-fields", action="store_true")
24
+ return parser
25
+
26
+
27
+ def main(argv: Sequence[str] | None = None) -> int:
28
+ args = _parser().parse_args(argv)
29
+ snapshot = resolve_snapshot(args.input)
30
+ if args.all_fields:
31
+ with h5py.File(str(snapshot), "r") as handle:
32
+ group = handle.get("fields")
33
+ if not isinstance(group, h5py.Group):
34
+ raise ValueError("Snapshot is missing the /fields group.")
35
+ fields = tuple(str(name) for name in group.keys())
36
+ else:
37
+ fields = tuple(args.fields or ("m",))
38
+ export_vtk(snapshot, args.output, mesh_path=args.mesh, fields=fields)
39
+ return 0
40
+
41
+
42
+ if __name__ == "__main__":
43
+ raise SystemExit(main())
@@ -0,0 +1,124 @@
1
+ """Export modern Nmag spatial snapshots to VTK-compatible mesh files."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+ from pathlib import Path
7
+
8
+ import h5py
9
+ import meshio
10
+ import numpy as np
11
+
12
+ import nmesh
13
+
14
+
15
+ def _dataset_names(handle: h5py.File) -> list[str]:
16
+ fields = handle.get("fields")
17
+ if not isinstance(fields, h5py.Group):
18
+ raise ValueError("Snapshot is missing the /fields group.")
19
+ return sorted(str(name) for name in fields.keys())
20
+
21
+
22
+ def _read_points(handle: h5py.File) -> np.ndarray:
23
+ try:
24
+ points = np.asarray(handle["mesh/points"], dtype=float)
25
+ except KeyError as exc:
26
+ raise ValueError("Snapshot is missing /mesh/points.") from exc
27
+ if points.ndim != 2 or points.shape[1] != 3:
28
+ raise ValueError(f"Snapshot points must have shape (N, 3), got {points.shape}.")
29
+ return points
30
+
31
+
32
+ def _read_topology(
33
+ handle: h5py.File,
34
+ mesh_path: str | Path | None,
35
+ ) -> tuple[np.ndarray, np.ndarray | None, np.ndarray]:
36
+ if "mesh/simplices" in handle:
37
+ simplices = np.asarray(handle["mesh/simplices"], dtype=np.int64)
38
+ regions = (
39
+ np.asarray(handle["mesh/simplicesregions"], dtype=np.int64)
40
+ if "mesh/simplicesregions" in handle
41
+ else None
42
+ )
43
+ elif mesh_path is not None:
44
+ source_mesh = nmesh.load(mesh_path)
45
+ simplices = np.asarray(source_mesh.simplices, dtype=np.int64)
46
+ regions = np.asarray(source_mesh.regions, dtype=np.int64)
47
+ else:
48
+ raise ValueError(
49
+ "Snapshot contains point coordinates but no cell topology; provide --mesh."
50
+ )
51
+
52
+ if simplices.ndim != 2 or simplices.shape[1] != 4:
53
+ raise ValueError(f"VTK export requires tetrahedral cells, got {simplices.shape}.")
54
+ if regions is not None and len(regions) != len(simplices):
55
+ raise ValueError("Mesh region data does not match the number of cells.")
56
+ return simplices, regions, _read_points(handle)
57
+
58
+
59
+ def export_vtk(
60
+ snapshot_path: str | Path,
61
+ output_path: str | Path,
62
+ *,
63
+ mesh_path: str | Path | None = None,
64
+ fields: Iterable[str] = ("m",),
65
+ ) -> Path:
66
+ """Export selected point fields from a modern Nmag HDF5 snapshot."""
67
+
68
+ snapshot = Path(snapshot_path)
69
+ output = Path(output_path)
70
+ selected_fields = tuple(dict.fromkeys(fields))
71
+ if not selected_fields:
72
+ raise ValueError("At least one point field must be selected.")
73
+
74
+ with h5py.File(str(snapshot), "r") as handle:
75
+ points = _read_points(handle)
76
+ simplices, regions, _ = _read_topology(handle, mesh_path)
77
+ if np.any(simplices < 0) or np.any(simplices >= len(points)):
78
+ raise ValueError("Mesh cell indices are outside the snapshot point range.")
79
+
80
+ point_data: dict[str, np.ndarray] = {}
81
+ field_group = handle.get("fields")
82
+ if not isinstance(field_group, h5py.Group):
83
+ raise ValueError("Snapshot is missing the /fields group.")
84
+ for field_name in selected_fields:
85
+ if field_name not in field_group:
86
+ available = ", ".join(_dataset_names(handle))
87
+ raise KeyError(f"Field {field_name!r} is not present; available fields: {available}")
88
+ values = np.asarray(field_group[field_name])
89
+ if values.ndim not in (1, 2) or values.shape[0] != len(points):
90
+ raise ValueError(
91
+ f"Field {field_name!r} must have one value per point, got {values.shape}."
92
+ )
93
+ if values.ndim == 2 and values.shape[1] not in (1, 3):
94
+ raise ValueError(
95
+ f"Field {field_name!r} must be scalar or three-component vector, "
96
+ f"got {values.shape}."
97
+ )
98
+ point_data[field_name] = np.asarray(values, dtype=float)
99
+
100
+ cell_data: dict[str, list[np.ndarray]] = {}
101
+ if regions is not None:
102
+ cell_data["region"] = [regions]
103
+ mesh = meshio.Mesh(
104
+ points=points,
105
+ cells=[("tetra", simplices)],
106
+ point_data=point_data,
107
+ cell_data=cell_data or None,
108
+ )
109
+ output.parent.mkdir(parents=True, exist_ok=True)
110
+ meshio.write(output, mesh)
111
+ return output
112
+
113
+
114
+ def resolve_snapshot(path: str | Path) -> Path:
115
+ """Resolve a snapshot path or a simulation base name."""
116
+
117
+ candidate = Path(path)
118
+ if candidate.is_file():
119
+ return candidate
120
+ if candidate.suffix == "":
121
+ suffixed = candidate.with_name(f"{candidate.name}_dat.h5")
122
+ if suffixed.is_file():
123
+ return suffixed
124
+ raise FileNotFoundError(f"Nmag snapshot does not exist: {candidate}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nmag-python-3
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Standalone Python 3 implementation of the Nmag micromagnetic simulation interface
5
5
  Author-email: TriMagnetix <info@trimagnetix.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -58,9 +58,27 @@ and [quickstart](https://trimagnetix.github.io/nmag-python-3/getting-started/qui
58
58
 
59
59
  ## Installation
60
60
 
61
- From a clone of this repository:
61
+ If you only want to run Nmag and do not need the source code, install the
62
+ published package in a virtual environment:
62
63
 
63
64
  ```bash
65
+ python3 -m venv .venv
66
+ .venv/bin/python -m pip install --upgrade pip
67
+ .venv/bin/python -m pip install nmag-python-3
68
+ ```
69
+
70
+ You can then run a simulation with:
71
+
72
+ ```bash
73
+ .venv/bin/python simulation.py
74
+ ```
75
+
76
+ To work from the source repository or contribute to Nmag, clone the repository
77
+ and use its setup script instead:
78
+
79
+ ```bash
80
+ git clone https://github.com/TriMagnetix/nmag-python-3.git
81
+ cd nmag-python-3
64
82
  ./scripts/setup.sh
65
83
  ```
66
84
 
@@ -20,6 +20,9 @@ src/nmag/output.py
20
20
  src/nmag/parallel.py
21
21
  src/nmag/py.typed
22
22
  src/nmag/resources.py
23
+ src/nmag/vtk_export.py
24
+ src/nmag/cli/__init__.py
25
+ src/nmag/cli/nmagpp.py
23
26
  src/nmag/demag/__init__.py
24
27
  src/nmag/demag/bem_operator.py
25
28
  src/nmag/demag/geometry.py
@@ -70,6 +73,7 @@ src/nmag/simulation/mesh/probe.py
70
73
  src/nmag_python_3.egg-info/PKG-INFO
71
74
  src/nmag_python_3.egg-info/SOURCES.txt
72
75
  src/nmag_python_3.egg-info/dependency_links.txt
76
+ src/nmag_python_3.egg-info/entry_points.txt
73
77
  src/nmag_python_3.egg-info/requires.txt
74
78
  src/nmag_python_3.egg-info/top_level.txt
75
79
  src/nmesh/__init__.py
@@ -80,6 +84,8 @@ src/nmesh/mesh_model.py
80
84
  src/nmesh/mesh_utilities.py
81
85
  src/nmesh/nmesh.py
82
86
  src/nmesh/py.typed
87
+ src/nmesh/cli/__init__.py
88
+ src/nmesh/cli/nmeshimport.py
83
89
  src/nmesh/geometry/__init__.py
84
90
  src/nmesh/geometry/boolean_operations.py
85
91
  src/nmesh/geometry/primitives.py
@@ -88,6 +94,7 @@ src/nmesh/io/__init__.py
88
94
  src/nmesh/io/ascii.py
89
95
  src/nmesh/io/legacy_nmesh_hdf5.py
90
96
  src/nmesh/io/meshio_support.py
97
+ src/nmesh/io/netgen.py
91
98
  src/nmesh/mesher/__init__.py
92
99
  src/nmesh/mesher/driver.py
93
100
  src/nmesh/mesher/meshing_defaults.py
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ nmagpp = nmag.cli.nmagpp:main
3
+ nmeshimport = nmesh.cli.nmeshimport:main
@@ -52,6 +52,7 @@ _MESHER_EXPORTS = {
52
52
  "do_every_n_steps_driver",
53
53
  "make_mg_gendriver",
54
54
  }
55
+ _NETGEN_EXPORTS = {"read_netgen_neutral"}
55
56
 
56
57
  __all__ = [
57
58
  "Mesh",
@@ -96,10 +97,17 @@ __all__ = [
96
97
  "inverse_shift",
97
98
  "make_mg_gendriver",
98
99
  "union",
100
+ "read_netgen_neutral",
99
101
  ]
100
102
 
101
103
 
102
104
  def __getattr__(name: str) -> Any:
105
+ if name in _NETGEN_EXPORTS:
106
+ from .io.netgen import read_netgen_neutral
107
+
108
+ globals()[name] = read_netgen_neutral
109
+ return read_netgen_neutral
110
+
103
111
  if name in _GEOMETRY_EXPORTS:
104
112
  from . import geometry
105
113
 
@@ -0,0 +1 @@
1
+ """Command-line entry points for mesh utilities."""
@@ -0,0 +1,39 @@
1
+ """Convert Netgen Neutral meshes to legacy Nmesh HDF5."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ from collections.abc import Sequence
7
+ from pathlib import Path
8
+
9
+ from ..io import save_raw_mesh_as_legacy_nmesh_hdf5
10
+ from ..io.netgen import read_netgen_neutral
11
+
12
+
13
+ def _parser() -> argparse.ArgumentParser:
14
+ parser = argparse.ArgumentParser(
15
+ prog="nmeshimport",
16
+ description="Convert a Netgen Neutral tetrahedral mesh to Nmesh HDF5.",
17
+ )
18
+ parser.add_argument(
19
+ "--netgen",
20
+ action="store_true",
21
+ help="read Netgen Neutral input (the supported conversion mode)",
22
+ )
23
+ parser.add_argument("input", type=Path)
24
+ parser.add_argument("output", type=Path)
25
+ return parser
26
+
27
+
28
+ def main(argv: Sequence[str] | None = None) -> int:
29
+ args = _parser().parse_args(argv)
30
+ if not args.netgen:
31
+ raise SystemExit("nmeshimport currently requires --netgen.")
32
+ mesh = read_netgen_neutral(args.input)
33
+ args.output.parent.mkdir(parents=True, exist_ok=True)
34
+ save_raw_mesh_as_legacy_nmesh_hdf5(args.output, mesh)
35
+ return 0
36
+
37
+
38
+ if __name__ == "__main__":
39
+ raise SystemExit(main())
@@ -23,12 +23,15 @@ _MESHIO_EXPORTS = {
23
23
  "save_raw_mesh_with_meshio",
24
24
  }
25
25
 
26
+ _NETGEN_EXPORTS = {"read_netgen_neutral"}
27
+
26
28
  __all__ = [
27
29
  "is_legacy_nmesh_hdf5",
28
30
  "load_raw_mesh_from_legacy_nmesh_hdf5",
29
31
  "load_raw_mesh_with_meshio",
30
32
  "save_raw_mesh_as_legacy_nmesh_hdf5",
31
33
  "save_raw_mesh_with_meshio",
34
+ "read_netgen_neutral",
32
35
  ]
33
36
 
34
37
 
@@ -47,4 +50,10 @@ def __getattr__(name: str) -> Any:
47
50
  globals()[name] = value
48
51
  return value
49
52
 
53
+ if name in _NETGEN_EXPORTS:
54
+ from .netgen import read_netgen_neutral
55
+
56
+ globals()[name] = read_netgen_neutral
57
+ return read_netgen_neutral
58
+
50
59
  raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,122 @@
1
+ """Readers for Netgen Neutral tetrahedral meshes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import gzip
6
+ from pathlib import Path
7
+ from typing import TextIO
8
+
9
+ from ..backend import RawMesh
10
+
11
+
12
+ def _open_text(path: Path) -> TextIO:
13
+ if path.suffix == ".gz":
14
+ return gzip.open(path, "rt", encoding="utf-8")
15
+ return path.open("r", encoding="utf-8")
16
+
17
+
18
+ class _LineReader:
19
+ def __init__(self, stream: TextIO, path: Path) -> None:
20
+ self.stream = stream
21
+ self.path = path
22
+ self.line_number = 0
23
+
24
+ def next(self, description: str) -> tuple[int, str]:
25
+ for line in self.stream:
26
+ self.line_number += 1
27
+ stripped = line.strip()
28
+ if stripped:
29
+ return self.line_number, stripped
30
+ raise ValueError(f"{self.path} ended while reading {description}.")
31
+
32
+
33
+ def _parse_count(line: str, path: Path, line_number: int, description: str) -> int:
34
+ try:
35
+ count = int(line)
36
+ except ValueError as exc:
37
+ raise ValueError(
38
+ f"{path}:{line_number} has an invalid {description} count: {line!r}."
39
+ ) from exc
40
+ if count < 0:
41
+ raise ValueError(f"{path}:{line_number} has a negative {description} count.")
42
+ return count
43
+
44
+
45
+ def read_netgen_neutral(path: str | Path) -> RawMesh:
46
+ """Read a Netgen Neutral tetrahedral mesh into a :class:`RawMesh`.
47
+
48
+ Netgen Neutral element indices are one-based. They are converted to the
49
+ zero-based indexing used by ``nmesh`` while region IDs are preserved.
50
+ Gzip-compressed files are accepted when the filename ends in ``.gz``.
51
+ """
52
+
53
+ mesh_path = Path(path)
54
+ if not mesh_path.is_file():
55
+ raise FileNotFoundError(f"Netgen mesh does not exist: {mesh_path}")
56
+
57
+ try:
58
+ with _open_text(mesh_path) as stream:
59
+ reader = _LineReader(stream, mesh_path)
60
+ point_count_line, point_count_text = reader.next("point")
61
+ point_count = _parse_count(
62
+ point_count_text, mesh_path, point_count_line, "point"
63
+ )
64
+ if point_count == 0:
65
+ raise ValueError(f"{mesh_path} contains no points.")
66
+
67
+ points: list[list[float]] = []
68
+ for index in range(point_count):
69
+ line_number, line = reader.next(f"point {index + 1}")
70
+ values = line.split()
71
+ if len(values) != 3:
72
+ raise ValueError(
73
+ f"{mesh_path}:{line_number} point {index + 1} must have three coordinates."
74
+ )
75
+ try:
76
+ points.append([float(value) for value in values])
77
+ except ValueError as exc:
78
+ raise ValueError(
79
+ f"{mesh_path}:{line_number} contains a non-numeric point coordinate."
80
+ ) from exc
81
+
82
+ simplex_count_line, simplex_count_text = reader.next("tetrahedron")
83
+ simplex_count = _parse_count(
84
+ simplex_count_text,
85
+ mesh_path,
86
+ simplex_count_line,
87
+ "tetrahedron",
88
+ )
89
+ if simplex_count == 0:
90
+ raise ValueError(f"{mesh_path} contains no tetrahedra.")
91
+
92
+ simplices: list[list[int]] = []
93
+ regions: list[int] = []
94
+ for index in range(simplex_count):
95
+ line_number, line = reader.next(f"tetrahedron {index + 1}")
96
+ values = line.split()
97
+ if len(values) != 5:
98
+ raise ValueError(
99
+ f"{mesh_path}:{line_number} tetrahedron {index + 1} must contain "
100
+ "one region ID and four point indices."
101
+ )
102
+ try:
103
+ region = int(values[0])
104
+ indices = [int(value) - 1 for value in values[1:]]
105
+ except ValueError as exc:
106
+ raise ValueError(
107
+ f"{mesh_path}:{line_number} contains a non-integer tetrahedron value."
108
+ ) from exc
109
+ if region <= 0:
110
+ raise ValueError(
111
+ f"{mesh_path}:{line_number} has invalid region ID {region}; expected > 0."
112
+ )
113
+ if any(point < 0 or point >= point_count for point in indices):
114
+ raise ValueError(
115
+ f"{mesh_path}:{line_number} contains a point index outside 1..{point_count}."
116
+ )
117
+ simplices.append(indices)
118
+ regions.append(region)
119
+ except (OSError, UnicodeError) as exc:
120
+ raise ValueError(f"Unable to read Netgen mesh {mesh_path}: {exc}") from exc
121
+
122
+ return RawMesh(points=points, simplices=simplices, regions=regions, dim=3)
File without changes
File without changes