radia 1.2.0__tar.gz → 1.3.2__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 (187) hide show
  1. {radia-1.2.0/src/radia.egg-info → radia-1.3.2}/PKG-INFO +1 -1
  2. {radia-1.2.0 → radia-1.3.2}/docs/README.md +5 -0
  3. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/benchmark_gridfunction_set.py +3 -2
  4. radia-1.3.2/examples/NGSolve_Integration/demo_batch_evaluation.py +183 -0
  5. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/demo_field_types.py +197 -193
  6. radia-1.3.2/examples/NGSolve_Integration/example_hmatrix_cache_usage.py +249 -0
  7. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/export_radia_geometry.py +10 -7
  8. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/test_batch_evaluation.py +3 -2
  9. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/test_batch_fld.py +12 -11
  10. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/test_coordinate_transform.py +15 -16
  11. radia-1.3.2/examples/NGSolve_Integration/test_gridfunction_simple.py +72 -0
  12. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/test_mesh_convergence.py +2 -1
  13. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/test_set_vs_interpolate.py +3 -2
  14. radia-1.3.2/examples/NGSolve_Integration/verify_curl_A_equals_B.py +352 -0
  15. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/visualize_field.py +267 -263
  16. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_solver.py +6 -2
  17. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_solver_methods.py +1 -1
  18. {radia-1.2.0 → radia-1.3.2}/pyproject.toml +1 -1
  19. radia-1.3.2/src/python/rad_ngsolve.pyd +0 -0
  20. radia-1.3.2/src/python/rad_ngsolve_fast.py +166 -0
  21. radia-1.3.2/src/python/radia_field_cached.py +274 -0
  22. {radia-1.2.0 → radia-1.3.2/src/radia.egg-info}/PKG-INFO +1 -1
  23. {radia-1.2.0 → radia-1.3.2}/src/radia.egg-info/SOURCES.txt +31 -1
  24. radia-1.3.2/tests/profile_batch_performance.py +222 -0
  25. radia-1.3.2/tests/test_all_spaces.py +151 -0
  26. radia-1.3.2/tests/test_batch_evaluation.py +176 -0
  27. radia-1.3.2/tests/test_cf_direct.py +69 -0
  28. radia-1.3.2/tests/test_convergence_hdiv.py +152 -0
  29. radia-1.3.2/tests/test_curlA_equals_B.py +294 -0
  30. radia-1.3.2/tests/test_curl_A_detailed.py +142 -0
  31. radia-1.3.2/tests/test_far_field_accuracy.py +133 -0
  32. radia-1.3.2/tests/test_fast_preparecache.py +167 -0
  33. radia-1.3.2/tests/test_fast_simple.py +79 -0
  34. radia-1.3.2/tests/test_hcurl_vs_hdiv.py +103 -0
  35. radia-1.3.2/tests/test_hmatrix_cache.py +256 -0
  36. radia-1.3.2/tests/test_hmatrix_cache_simple.py +188 -0
  37. radia-1.3.2/tests/test_l2_norm_debug.py +139 -0
  38. radia-1.3.2/tests/test_minimal_cached.py +57 -0
  39. radia-1.3.2/tests/test_order1.py +54 -0
  40. radia-1.3.2/tests/test_preparecache_performance.py +111 -0
  41. radia-1.3.2/tests/test_python_cached_field.py +200 -0
  42. radia-1.3.2/tests/test_python_cached_simple.py +141 -0
  43. {radia-1.2.0 → radia-1.3.2}/tests/test_rad_ngsolve.py +8 -2
  44. radia-1.3.2/tests/test_rad_ngsolve_diagnostic.py +78 -0
  45. radia-1.3.2/tests/test_rad_ngsolve_function.py +70 -0
  46. radia-1.3.2/tests/test_rad_ngsolve_hmatrix.py +226 -0
  47. radia-1.3.2/tests/test_set_vs_interpolate.py +125 -0
  48. {radia-1.2.0 → radia-1.3.2}/tests/test_vector_potential.py +9 -5
  49. radia-1.3.2/tests/test_without_B_projection.py +127 -0
  50. radia-1.3.2/tests/test_without_gridfunction.py +63 -0
  51. {radia-1.2.0/examples/NGSolve_Integration → radia-1.3.2/tests}/verify_curl_A_equals_B.py +351 -351
  52. radia-1.2.0/README_BUILD.md +0 -445
  53. radia-1.2.0/src/python/rad_ngsolve.pyd +0 -0
  54. {radia-1.2.0 → radia-1.3.2}/COPYRIGHT.txt +0 -0
  55. {radia-1.2.0 → radia-1.3.2}/LICENSE +0 -0
  56. {radia-1.2.0 → radia-1.3.2}/MANIFEST.in +0 -0
  57. {radia-1.2.0 → radia-1.3.2}/README.md +0 -0
  58. {radia-1.2.0 → radia-1.3.2}/docs/API_EXTENSIONS.md +0 -0
  59. {radia-1.2.0 → radia-1.3.2}/docs/API_REFERENCE.md +0 -0
  60. {radia-1.2.0 → radia-1.3.2}/docs/CF_BACKGROUND_FIELD_IMPLEMENTATION.md +0 -0
  61. {radia-1.2.0 → radia-1.3.2}/docs/HMATRIX_BENCHMARKS_RESULTS.md +0 -0
  62. {radia-1.2.0 → radia-1.3.2}/docs/HMATRIX_ENHANCEMENT_PROPOSAL_2025.md +0 -0
  63. {radia-1.2.0 → radia-1.3.2}/docs/HMATRIX_IMPLEMENTATION_HISTORY.md +0 -0
  64. {radia-1.2.0 → radia-1.3.2}/docs/HMATRIX_SERIALIZATION.md +0 -0
  65. {radia-1.2.0 → radia-1.3.2}/docs/HMATRIX_USER_GUIDE.md +0 -0
  66. {radia-1.2.0 → radia-1.3.2}/docs/MATERIAL_API_IMPLEMENTATION.md +0 -0
  67. {radia-1.2.0 → radia-1.3.2}/docs/ML_PARAMETER_TUNING.md +0 -0
  68. {radia-1.2.0 → radia-1.3.2}/docs/NGSOLVE_CF_BACKGROUND_FIELD_DESIGN.md +0 -0
  69. {radia-1.2.0 → radia-1.3.2}/docs/NGSOLVE_INTEGRATION.md +0 -0
  70. {radia-1.2.0 → radia-1.3.2}/docs/NGSOLVE_USAGE_GUIDE.md +0 -0
  71. {radia-1.2.0 → radia-1.3.2}/docs/hmatrix_field_design.md +0 -0
  72. {radia-1.2.0 → radia-1.3.2}/docs/scripts/README.md +0 -0
  73. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/HMATRIX_ANALYSIS.md +0 -0
  74. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/HMATRIX_FIELD_EVALUATION_ISSUE.md +0 -0
  75. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/H_MATRIX_PARALLEL_OPTIMIZATION.md +0 -0
  76. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/NGBEM_ANALYSIS.md +0 -0
  77. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/NGSOLVE_SET_VS_INTERPOLATE.md +0 -0
  78. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/PROPOSAL_VECTORIZED_API.md +0 -0
  79. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/README.md +0 -0
  80. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/SET_VS_INTERPOLATE_SIMPLE.md +0 -0
  81. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/SOLVER_OPTIMIZATION_PROPOSAL.md +0 -0
  82. {radia-1.2.0 → radia-1.3.2}/examples/NGSolve_Integration/radia_field.pvsm +0 -0
  83. {radia-1.2.0 → radia-1.3.2}/examples/README.md +0 -0
  84. {radia-1.2.0 → radia-1.3.2}/examples/background_fields/Cubit2Nastran.py +0 -0
  85. {radia-1.2.0 → radia-1.3.2}/examples/background_fields/README.md +0 -0
  86. {radia-1.2.0 → radia-1.3.2}/examples/background_fields/permeability_comparison.py +0 -0
  87. {radia-1.2.0 → radia-1.3.2}/examples/background_fields/quadrupole_analytical.py +0 -0
  88. {radia-1.2.0 → radia-1.3.2}/examples/background_fields/sphere_in_quadrupole.py +0 -0
  89. {radia-1.2.0 → radia-1.3.2}/examples/background_fields/sphere_nastran_analysis.py +0 -0
  90. {radia-1.2.0 → radia-1.3.2}/examples/background_fields/sphere_nastran_field_mu.pvsm +0 -0
  91. {radia-1.2.0 → radia-1.3.2}/examples/background_fields/sphere_nastran_geometry.vtk +0 -0
  92. {radia-1.2.0 → radia-1.3.2}/examples/complex_coil_geometry/README.md +0 -0
  93. {radia-1.2.0 → radia-1.3.2}/examples/complex_coil_geometry/coil_geometry.vtk +0 -0
  94. {radia-1.2.0 → radia-1.3.2}/examples/complex_coil_geometry/coil_model.py +0 -0
  95. {radia-1.2.0 → radia-1.3.2}/examples/complex_coil_geometry/complex_coil.pvsm +0 -0
  96. {radia-1.2.0 → radia-1.3.2}/examples/complex_coil_geometry/field_map.py +0 -0
  97. {radia-1.2.0 → radia-1.3.2}/examples/complex_coil_geometry/field_map.vtk +0 -0
  98. {radia-1.2.0 → radia-1.3.2}/examples/complex_coil_geometry/visualize_coils.py +0 -0
  99. {radia-1.2.0 → radia-1.3.2}/examples/electromagnet/README.md +0 -0
  100. {radia-1.2.0 → radia-1.3.2}/examples/electromagnet/electromagnet.pvsm +0 -0
  101. {radia-1.2.0 → radia-1.3.2}/examples/electromagnet/electromagnet.vtk +0 -0
  102. {radia-1.2.0 → radia-1.3.2}/examples/electromagnet/field_distribution.vtk +0 -0
  103. {radia-1.2.0 → radia-1.3.2}/examples/electromagnet/magnet.py +0 -0
  104. {radia-1.2.0 → radia-1.3.2}/examples/electromagnet/racetrack_coil_model.py +0 -0
  105. {radia-1.2.0 → radia-1.3.2}/examples/electromagnet/yoke_model.py +0 -0
  106. {radia-1.2.0 → radia-1.3.2}/examples/simple_problems/CONVERSION_NOTES.md +0 -0
  107. {radia-1.2.0 → radia-1.3.2}/examples/simple_problems/README.md +0 -0
  108. {radia-1.2.0 → radia-1.3.2}/examples/simple_problems/arc_current_dual_magnets.py +0 -0
  109. {radia-1.2.0 → radia-1.3.2}/examples/simple_problems/arc_current_with_magnet.py +0 -0
  110. {radia-1.2.0 → radia-1.3.2}/examples/simple_problems/chamfered_pole_piece.py +0 -0
  111. {radia-1.2.0 → radia-1.3.2}/examples/simple_problems/compare_magpylib.py +0 -0
  112. {radia-1.2.0 → radia-1.3.2}/examples/simple_problems/cubic_polyhedron_magnet.py +0 -0
  113. {radia-1.2.0 → radia-1.3.2}/examples/simple_problems/hmatrix_update_magnetization.py +0 -0
  114. {radia-1.2.0 → radia-1.3.2}/examples/smco_magnet_array/README.md +0 -0
  115. {radia-1.2.0 → radia-1.3.2}/examples/smco_magnet_array/smbo.pvsm +0 -0
  116. {radia-1.2.0 → radia-1.3.2}/examples/smco_magnet_array/smco_array.py +0 -0
  117. {radia-1.2.0 → radia-1.3.2}/examples/smco_magnet_array/smco_array.vtk +0 -0
  118. {radia-1.2.0 → radia-1.3.2}/examples/smco_magnet_array/smco_field_distribution.vtk +0 -0
  119. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/BENCHMARK_RESULTS.md +0 -0
  120. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/HMATRIX_FIELD_DESIGN.md +0 -0
  121. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/HMATRIX_FIELD_DESIGN_SIMPLIFIED.md +0 -0
  122. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/PHASE2B_REEVALUATION.md +0 -0
  123. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/README.md +0 -0
  124. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/SCALING_RESULTS.md +0 -0
  125. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_field_evaluation.py +0 -0
  126. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_hmatrix_field.py +0 -0
  127. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_hmatrix_scaling_exact.py +0 -0
  128. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_large_scale_comparison.py +0 -0
  129. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_linear_material.py +0 -0
  130. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_matrix_construction.py +0 -0
  131. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_parallel_construction.py +0 -0
  132. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_solver_comparison.py +0 -0
  133. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_solver_scaling.py +0 -0
  134. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/benchmark_solver_scaling_extended.py +0 -0
  135. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/plot_benchmark_results.py +0 -0
  136. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/run_all_benchmarks.py +0 -0
  137. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/run_all_hmatrix_benchmarks.py +0 -0
  138. {radia-1.2.0 → radia-1.3.2}/examples/solver_benchmarks/verify_field_accuracy.py +0 -0
  139. {radia-1.2.0 → radia-1.3.2}/setup.cfg +0 -0
  140. {radia-1.2.0 → radia-1.3.2}/setup.py +0 -0
  141. {radia-1.2.0 → radia-1.3.2}/src/python/__init__.py +0 -0
  142. {radia-1.2.0 → radia-1.3.2}/src/python/nastran_reader.py +0 -0
  143. {radia-1.2.0 → radia-1.3.2}/src/python/radia.pyd +0 -0
  144. {radia-1.2.0 → radia-1.3.2}/src/python/radia_coil_builder.py +0 -0
  145. {radia-1.2.0 → radia-1.3.2}/src/python/radia_ngsolve_field.py +0 -0
  146. {radia-1.2.0 → radia-1.3.2}/src/python/radia_pyvista_viewer.py +0 -0
  147. {radia-1.2.0 → radia-1.3.2}/src/python/radia_vtk_export.py +0 -0
  148. {radia-1.2.0 → radia-1.3.2}/src/radia.egg-info/dependency_links.txt +0 -0
  149. {radia-1.2.0 → radia-1.3.2}/src/radia.egg-info/not-zip-safe +0 -0
  150. {radia-1.2.0 → radia-1.3.2}/src/radia.egg-info/requires.txt +0 -0
  151. {radia-1.2.0 → radia-1.3.2}/src/radia.egg-info/top_level.txt +0 -0
  152. {radia-1.2.0 → radia-1.3.2}/tests/README.md +0 -0
  153. {radia-1.2.0 → radia-1.3.2}/tests/__init__.py +0 -0
  154. {radia-1.2.0 → radia-1.3.2}/tests/benchmark_hmatrix.py +0 -0
  155. {radia-1.2.0 → radia-1.3.2}/tests/benchmarks/benchmark_correct.py +0 -0
  156. {radia-1.2.0 → radia-1.3.2}/tests/benchmarks/benchmark_heavy.py +0 -0
  157. {radia-1.2.0 → radia-1.3.2}/tests/benchmarks/benchmark_openmp.py +0 -0
  158. {radia-1.2.0 → radia-1.3.2}/tests/benchmarks/benchmark_threads.py +0 -0
  159. {radia-1.2.0 → radia-1.3.2}/tests/conftest.py +0 -0
  160. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_phase2a_final.py +0 -0
  161. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_phase2a_hmatrix_reuse.py +0 -0
  162. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_phase2a_with_field.py +0 -0
  163. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_phase2b_geometry_detection.py +0 -0
  164. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_phase3_magnetization_update.py +0 -0
  165. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_phase3b_large_problem.py +0 -0
  166. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_phase3b_serialization.py +0 -0
  167. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_phase3b_solver_cache.py +0 -0
  168. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_serialize_step1_build.py +0 -0
  169. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_serialize_step2_load.py +0 -0
  170. {radia-1.2.0 → radia-1.3.2}/tests/hmatrix/test_verify_field_simple.py +0 -0
  171. {radia-1.2.0 → radia-1.3.2}/tests/test_advanced.py +0 -0
  172. {radia-1.2.0 → radia-1.3.2}/tests/test_group_operations.py +0 -0
  173. {radia-1.2.0 → radia-1.3.2}/tests/test_magpylib_comparison.py +0 -0
  174. {radia-1.2.0 → radia-1.3.2}/tests/test_materials.py +0 -0
  175. {radia-1.2.0 → radia-1.3.2}/tests/test_new_material_api.py +0 -0
  176. {radia-1.2.0 → radia-1.3.2}/tests/test_objbckg_simple.py +0 -0
  177. {radia-1.2.0 → radia-1.3.2}/tests/test_objbckgcf_alone.py +0 -0
  178. {radia-1.2.0 → radia-1.3.2}/tests/test_parallel_performance.py +0 -0
  179. {radia-1.2.0 → radia-1.3.2}/tests/test_radhmat.py +0 -0
  180. {radia-1.2.0 → radia-1.3.2}/tests/test_radia.py +0 -0
  181. {radia-1.2.0 → radia-1.3.2}/tests/test_serialization.py +0 -0
  182. {radia-1.2.0 → radia-1.3.2}/tests/test_simple.py +0 -0
  183. {radia-1.2.0 → radia-1.3.2}/tests/test_square_coil_analytical.py +0 -0
  184. {radia-1.2.0 → radia-1.3.2}/tests/test_transformations.py +0 -0
  185. {radia-1.2.0 → radia-1.3.2}/tests/test_type_cast.py +0 -0
  186. {radia-1.2.0 → radia-1.3.2}/tests/test_update_hmatrix_magnetization.py +0 -0
  187. {radia-1.2.0 → radia-1.3.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: radia
3
- Version: 1.2.0
3
+ Version: 1.3.2
4
4
  Summary: Radia 3D Magnetostatics with NGSolve Integration and OpenMP Parallelization
5
5
  Home-page: https://github.com/ksugahar/Radia_NGSolve
6
6
  Author: Pascal Elleaume
@@ -34,6 +34,11 @@ This folder contains the official documentation for Radia.
34
34
 
35
35
  ## Additional Resources
36
36
 
37
+ ### Internal Documentation (For Maintainers)
38
+ Design documents and implementation analysis are in [../internal/](../internal/):
39
+ - [design/](../internal/design/) - Architecture decisions, implementation proposals
40
+ - [analysis/](../internal/analysis/) - Performance analysis, bottleneck investigations
41
+
37
42
  ### Development Notes
38
43
  Implementation notes, performance analysis, and troubleshooting are in [../dev/notes/](../dev/notes/):
39
44
  - Implementation details (directory structure, conversion reports)
@@ -81,8 +81,9 @@ for radia_cfg in radia_configs:
81
81
 
82
82
  # Create Radia magnet geometry
83
83
  rad.UtiDelAll()
84
+ rad.FldUnits('m') # Set units to meters
84
85
 
85
- cube_size = 100.0 # mm
86
+ cube_size = 0.100 # meters
86
87
  elem_size = cube_size / n
87
88
  mag_value = 1.2 # T
88
89
 
@@ -109,7 +110,7 @@ for radia_cfg in radia_configs:
109
110
  print(f" {'-'*76}")
110
111
 
111
112
  # Create NGSolve mesh
112
- box_size_m = cube_size * 2.0 / 1000 # mm to m
113
+ box_size_m = cube_size * 2.0 # meters
113
114
  geo = Box(
114
115
  Pnt(-box_size_m/2, -box_size_m/2, -box_size_m/2),
115
116
  Pnt( box_size_m/2, box_size_m/2, box_size_m/2)
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Demonstration: Batch evaluation for H-matrix acceleration
4
+
5
+ Shows the benefit of batching all evaluation points together
6
+ versus element-by-element evaluation.
7
+
8
+ Current limitation:
9
+ - NGSolve's GridFunction.Set() calls CoefficientFunction element-by-element
10
+ - Each call has only ~10-20 points (one element's integration points)
11
+ - H-matrix overhead >> computation time for such small batches
12
+ - No speedup observed
13
+
14
+ Proposed solution:
15
+ - Collect ALL integration points from ALL elements
16
+ - Evaluate in ONE batch call (1000s of points)
17
+ - H-matrix speedup is significant for large batches
18
+ - Expected: 10-100x speedup for N>1000
19
+
20
+ This script demonstrates the concept and measures potential speedup.
21
+ """
22
+
23
+ import sys
24
+ import os
25
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../build/Release'))
26
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../src/python'))
27
+
28
+ import radia as rad
29
+ import numpy as np
30
+ import time
31
+
32
+ try:
33
+ from ngsolve import *
34
+ from netgen.occ import *
35
+ import rad_ngsolve
36
+ except ImportError:
37
+ print("NGSolve not available")
38
+ sys.exit(0)
39
+
40
+ print("="*70)
41
+ print("Batch Evaluation Demo for H-Matrix Acceleration")
42
+ print("="*70)
43
+
44
+ # Set Radia units to meters
45
+ rad.FldUnits('m')
46
+
47
+ # Create Radia magnet
48
+ rad.UtiDelAll()
49
+ n = 5 # 5x5x5 = 125 elements
50
+ cube_size = 0.100
51
+ elem_size = cube_size / n
52
+
53
+ print(f"\n[1] Creating magnet: {n}x{n}x{n} = {n**3} elements")
54
+ elements = []
55
+ for i in range(n):
56
+ for j in range(n):
57
+ for k in range(n):
58
+ x = (i - n/2 + 0.5) * elem_size
59
+ y = (j - n/2 + 0.5) * elem_size
60
+ z = (k - n/2 + 0.5) * elem_size
61
+ elem = rad.ObjRecMag([x, y, z], [elem_size, elem_size, elem_size],
62
+ [0, 0, 1.2])
63
+ elements.append(elem)
64
+
65
+ magnet = rad.ObjCnt(elements)
66
+
67
+ # Create mesh
68
+ print(f"\n[2] Creating NGSolve mesh")
69
+ box = Box((0.015, 0.015, 0.015), (0.063, 0.063, 0.063))
70
+ mesh = Mesh(OCCGeometry(box).GenerateMesh(maxh=0.010))
71
+ print(f" Mesh: {mesh.nv} vertices, {mesh.ne} elements")
72
+
73
+ # Create finite element space
74
+ fes = HCurl(mesh, order=2)
75
+ gf = GridFunction(fes)
76
+ print(f" FE space: {fes.ndof} DOFs")
77
+
78
+ # Estimate number of integration points
79
+ # For HCurl order=2, typically 10-15 points per element
80
+ points_per_elem = 15 # Estimate
81
+ total_points = mesh.ne * points_per_elem
82
+ print(f" Estimated integration points: ~{total_points}")
83
+
84
+ print("\n" + "="*70)
85
+ print("MEASUREMENT 1: Element-by-element evaluation (current method)")
86
+ print("="*70)
87
+
88
+ # Standard GridFunction.Set() with H-matrix
89
+ rad.SetHMatrixFieldEval(1, 1e-6)
90
+ cf_standard = rad_ngsolve.RadiaField(magnet, 'b')
91
+
92
+ print(f"\n[3a] Measuring GridFunction.Set() with H-matrix...")
93
+ print(f" (Element-by-element: {mesh.ne} calls, ~{points_per_elem} points/call)")
94
+
95
+ t0 = time.time()
96
+ gf.Set(cf_standard)
97
+ t_standard = time.time() - t0
98
+
99
+ print(f" Time: {t_standard*1000:.1f} ms")
100
+ print(f" Average per element: {t_standard*1000/mesh.ne:.2f} ms")
101
+
102
+ print("\n" + "="*70)
103
+ print("MEASUREMENT 2: Single batch evaluation (proposed method)")
104
+ print("="*70)
105
+
106
+ # Simulate batch evaluation: collect all vertices and evaluate once
107
+ print(f"\n[3b] Simulating batch evaluation...")
108
+ print(f" (Single batch: 1 call, {mesh.nv} points)")
109
+
110
+ # Collect all vertex positions
111
+ points = []
112
+ for v in mesh.vertices:
113
+ pt = v.point
114
+ points.append([pt[0], pt[1], pt[2]])
115
+
116
+ # Single batch evaluation
117
+ t0 = time.time()
118
+ field_values = rad.FldBatch(magnet, 'b', points, 1) # use_hmatrix=1
119
+ t_batch = time.time() - t0
120
+
121
+ print(f" Time: {t_batch*1000:.1f} ms")
122
+ print(f" Average per point: {t_batch*1e6/len(points):.2f} us")
123
+
124
+ print("\n" + "="*70)
125
+ print("ANALYSIS")
126
+ print("="*70)
127
+
128
+ # Calculate actual points evaluated in standard method
129
+ # Each element's integration rule has multiple points
130
+ actual_eval_points = total_points
131
+
132
+ print(f"\nEstimated evaluation points:")
133
+ print(f" Standard method: ~{actual_eval_points} points")
134
+ print(f" Batch method: {len(points)} points (vertices only)")
135
+
136
+ print(f"\nTime comparison:")
137
+ print(f" Standard (element-by-element): {t_standard*1000:8.1f} ms")
138
+ print(f" Batch (single call): {t_batch*1000:8.1f} ms")
139
+
140
+ speedup = t_standard / t_batch
141
+ print(f"\nObserved speedup: {speedup:.2f}x")
142
+
143
+ print(f"\nWhy the speedup is limited:")
144
+ print(f" - Standard method evaluates ~{actual_eval_points} integration points")
145
+ print(f" - Batch method evaluates only {len(points)} vertices")
146
+ print(f" - Not a fair comparison!")
147
+
148
+ print(f"\nTrue batch optimization requires:")
149
+ print(f" 1. Collect ALL integration points (~{actual_eval_points})")
150
+ print(f" 2. Evaluate in ONE batch call")
151
+ print(f" 3. Map results back to GridFunction DOFs")
152
+ print(f" 4. This would give true {speedup:.1f}-{speedup*2:.1f}x speedup")
153
+
154
+ print("\n" + "="*70)
155
+ print("CONCLUSION")
156
+ print("="*70)
157
+
158
+ print(f"""
159
+ Current situation:
160
+ - GridFunction.Set() calls Evaluate() {mesh.ne} times
161
+ - Each call evaluates ~{points_per_elem} points
162
+ - H-matrix overhead dominates for small batches
163
+ - Total time: {t_standard*1000:.1f} ms
164
+
165
+ Optimized approach (requires C++ implementation):
166
+ - Collect all ~{actual_eval_points} integration points
167
+ - Single FldBatch() call
168
+ - Full H-matrix acceleration
169
+ - Expected time: ~{t_batch*actual_eval_points/len(points):.1f} ms
170
+ - Expected speedup: ~{t_standard/(t_batch*actual_eval_points/len(points)):.1f}x
171
+
172
+ Implementation path:
173
+ 1. Add PrepareCache() method to RadiaFieldCF (C++)
174
+ 2. PrepareCache() collects all mesh integration points
175
+ 3. PrepareCache() calls FldBatch() once
176
+ 4. Evaluate() returns cached values
177
+ 5. User calls PrepareCache(mesh) before gf.Set(cf)
178
+ """)
179
+
180
+ print("="*70)
181
+
182
+ rad.UtiDelAll()
183
+
@@ -1,193 +1,197 @@
1
- """
2
- Radia Field Types Demo - NGSolve Integration
3
-
4
- This script demonstrates how to use the new unified RadiaField interface
5
- to access different physical field quantities:
6
- - 'b': Magnetic flux density (Tesla)
7
- - 'h': Magnetic field (A/m)
8
- - 'a': Vector potential (T*m)
9
- - 'm': Magnetization (A/m)
10
-
11
- Usage:
12
- python demo_field_types.py
13
-
14
-
15
- Date: 2025-11-01
16
- """
17
-
18
- import sys
19
- sys.path.insert(0, r"S:\radia\01_GitHub\build\Release")
20
- sys.path.insert(0, r"S:\radia\01_GitHub\dist")
21
-
22
- from ngsolve import *
23
- from netgen.csg import CSGeometry, OrthoBrick, Pnt
24
- import numpy as np
25
- import radia as rad
26
- import rad_ngsolve
27
-
28
- print("=" * 70)
29
- print("Radia Field Types Demo")
30
- print("=" * 70)
31
-
32
- # ============================================================================
33
- # Step 1: Create Radia Magnet Geometry
34
- # ============================================================================
35
-
36
- print("\n[Step 1] Creating Radia Magnet")
37
- print("-" * 70)
38
-
39
- magnet_center = [0, 0, 0]
40
- magnet_size = [20, 20, 30]
41
-
42
- magnet = rad.ObjRecMag(magnet_center, magnet_size, [0, 0, 1.2])
43
- rad.MatApl(magnet, rad.MatPM(1.2, 900000, [0, 0, 1])) # NdFeB
44
- rad.Solve(magnet, 0.0001, 10000)
45
-
46
- print(f"Magnet created: object #{magnet}")
47
- print(f" Center: {magnet_center} mm")
48
- print(f" Size: {magnet_size} mm")
49
- print(f" Material: NdFeB, Br = 1.2 T")
50
-
51
- # ============================================================================
52
- # Step 2: Create CoefficientFunctions for Different Field Types
53
- # ============================================================================
54
-
55
- print("\n[Step 2] Creating CoefficientFunctions for All Field Types")
56
- print("-" * 70)
57
-
58
- # Method 1: New unified interface (recommended)
59
- B_cf = rad_ngsolve.RadiaField(magnet, 'b') # Magnetic flux density
60
- H_cf = rad_ngsolve.RadiaField(magnet, 'h') # Magnetic field
61
- A_cf = rad_ngsolve.RadiaField(magnet, 'a') # Vector potential
62
- M_cf = rad_ngsolve.RadiaField(magnet, 'm') # Magnetization
63
-
64
- print(f"Created CoefficientFunctions:")
65
- print(f" B (flux density): {type(B_cf).__name__}, field_type='{B_cf.field_type}'")
66
- print(f" H (magnetic field): {type(H_cf).__name__}, field_type='{H_cf.field_type}'")
67
- print(f" A (vector potential): {type(A_cf).__name__}, field_type='{A_cf.field_type}'")
68
- print(f" M (magnetization): {type(M_cf).__name__}, field_type='{M_cf.field_type}'")
69
-
70
- # ============================================================================
71
- # Step 3: Create 3D Mesh
72
- # ============================================================================
73
-
74
- print("\n[Step 3] Creating 3D Mesh")
75
- print("-" * 70)
76
-
77
- geo = CSGeometry()
78
- geo.Add(OrthoBrick(Pnt(-0.05, -0.05, -0.05), Pnt(0.05, 0.05, 0.05)))
79
- mesh = Mesh(geo.GenerateMesh(maxh=0.01))
80
-
81
- print(f"3D Mesh generated:")
82
- print(f" Elements: {mesh.ne}")
83
- print(f" Vertices: {mesh.nv}")
84
- print(f" Domain: [-0.05, 0.05] m = [-50, 50] mm")
85
-
86
- # ============================================================================
87
- # Step 4: Evaluate Fields at Test Points
88
- # ============================================================================
89
-
90
- print("\n[Step 4] Field Evaluation at Test Points")
91
- print("-" * 70)
92
-
93
- test_points = [
94
- (0.000, 0.000, 0.000), # 0mm (center)
95
- (0.000, 0.000, 0.020), # 20mm (above magnet)
96
- (0.000, 0.000, 0.040), # 40mm (far from magnet)
97
- ]
98
-
99
- print("\n" + "=" * 70)
100
- print("Field Values at Different Points")
101
- print("=" * 70)
102
-
103
- for pt in test_points:
104
- pt_mm = [pt[0]*1000, pt[1]*1000, pt[2]*1000]
105
- mesh_pt = mesh(*pt)
106
-
107
- print(f"\nPoint: {pt} m = {pt_mm} mm")
108
-
109
- # B field (Tesla)
110
- B_val = B_cf(mesh_pt)
111
- print(f" B (flux density): Bx={B_val[0]:8.6f}, By={B_val[1]:8.6f}, Bz={B_val[2]:8.6f} T")
112
-
113
- # H field (A/m)
114
- H_val = H_cf(mesh_pt)
115
- print(f" H (magnetic field): Hx={H_val[0]:8.2f}, Hy={H_val[1]:8.2f}, Hz={H_val[2]:8.2f} A/m")
116
-
117
- # A field (T*m)
118
- A_val = A_cf(mesh_pt)
119
- print(f" A (vector potential): Ax={A_val[0]:8.6f}, Ay={A_val[1]:8.6f}, Az={A_val[2]:8.6f} T*m")
120
-
121
- # M field (A/m)
122
- M_val = M_cf(mesh_pt)
123
- print(f" M (magnetization): Mx={M_val[0]:8.2f}, My={M_val[1]:8.2f}, Mz={M_val[2]:8.2f} A/m")
124
-
125
- # ============================================================================
126
- # Step 5: Compare with Radia Direct Evaluation
127
- # ============================================================================
128
-
129
- print("\n" + "=" * 70)
130
- print("Comparison with Radia Direct Evaluation")
131
- print("=" * 70)
132
-
133
- pt_mm = [0, 0, 0] # Center point in mm
134
- mesh_pt = mesh(0, 0, 0)
135
-
136
- print(f"\nAt center ({pt_mm} mm):")
137
-
138
- # Radia direct
139
- B_radia = rad.Fld(magnet, 'b', pt_mm)
140
- H_radia = rad.Fld(magnet, 'h', pt_mm)
141
- A_radia = rad.Fld(magnet, 'a', pt_mm)
142
- M_radia = rad.Fld(magnet, 'm', pt_mm)
143
-
144
- # NGSolve CoefficientFunction
145
- B_ngsolve = B_cf(mesh_pt)
146
- H_ngsolve = H_cf(mesh_pt)
147
- A_ngsolve = A_cf(mesh_pt)
148
- M_ngsolve = M_cf(mesh_pt)
149
-
150
- # Compare
151
- print(f"\nB field:")
152
- print(f" Radia: Bz = {B_radia[2]:.6f} T")
153
- print(f" NGSolve: Bz = {B_ngsolve[2]:.6f} T")
154
- print(f" Error: {abs(B_radia[2] - B_ngsolve[2]):.2e} T")
155
-
156
- print(f"\nH field:")
157
- print(f" Radia: Hz = {H_radia[2]:.2f} A/m")
158
- print(f" NGSolve: Hz = {H_ngsolve[2]:.2f} A/m")
159
- print(f" Error: {abs(H_radia[2] - H_ngsolve[2]):.2e} A/m")
160
-
161
- print(f"\nA field:")
162
- print(f" Radia: |A| = {np.linalg.norm(A_radia):.6e} T*m")
163
- print(f" NGSolve: |A| = {np.linalg.norm(A_ngsolve):.6e} T*m")
164
-
165
- print(f"\nM field (Magnetization):")
166
- print(f" Radia: Mz = {M_radia[2]:.2f} A/m")
167
- print(f" NGSolve: Mz = {M_ngsolve[2]:.2f} A/m")
168
- print(f" Error: {abs(M_radia[2] - M_ngsolve[2]):.2e} A/m")
169
-
170
- # ============================================================================
171
- # Summary
172
- # ============================================================================
173
-
174
- print("\n" + "=" * 70)
175
- print("Summary")
176
- print("=" * 70)
177
-
178
- print("\nNew Unified Interface:")
179
- print(" rad_ngsolve.RadiaField(radia_obj, field_type)")
180
- print("\nField types:")
181
- print(" 'b' - Magnetic flux density B (Tesla)")
182
- print(" 'h' - Magnetic field H (A/m)")
183
- print(" 'a' - Vector potential A (T*m)")
184
- print(" 'm' - Magnetization M (A/m)")
185
-
186
- print("\nRecommendation:")
187
- print(" Use the new RadiaField interface for all new code.")
188
- print(" Legacy interfaces (RadBfield, RadHfield, etc.) remain")
189
- print(" supported for backward compatibility.")
190
-
191
- print("\n" + "=" * 70)
192
- print("Complete")
193
- print("=" * 70)
1
+ """
2
+ Radia Field Types Demo - NGSolve Integration
3
+
4
+ This script demonstrates how to use the new unified RadiaField interface
5
+ to access different physical field quantities:
6
+ - 'b': Magnetic flux density (Tesla)
7
+ - 'h': Magnetic field (A/m)
8
+ - 'a': Vector potential (T*m)
9
+ - 'm': Magnetization (A/m)
10
+
11
+ Usage:
12
+ python demo_field_types.py
13
+
14
+
15
+ Date: 2025-11-01
16
+ """
17
+
18
+ import sys
19
+ import os
20
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../build/Release'))
21
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../src/python'))
22
+
23
+ from ngsolve import *
24
+ from netgen.csg import CSGeometry, OrthoBrick, Pnt
25
+ import numpy as np
26
+ import radia as rad
27
+ import rad_ngsolve
28
+
29
+ print("=" * 70)
30
+ print("Radia Field Types Demo")
31
+ print("=" * 70)
32
+
33
+ # Set Radia to use meters (required for NGSolve integration)
34
+ rad.FldUnits('m')
35
+
36
+ # ============================================================================
37
+ # Step 1: Create Radia Magnet Geometry
38
+ # ============================================================================
39
+
40
+ print("\n[Step 1] Creating Radia Magnet")
41
+ print("-" * 70)
42
+
43
+ magnet_center = [0, 0, 0] # meters
44
+ magnet_size = [0.020, 0.020, 0.030] # meters (20mm x 20mm x 30mm)
45
+
46
+ magnet = rad.ObjRecMag(magnet_center, magnet_size, [0, 0, 1.2])
47
+ rad.MatApl(magnet, rad.MatPM(1.2, 900000, [0, 0, 1])) # NdFeB
48
+ rad.Solve(magnet, 0.0001, 10000)
49
+
50
+ print(f"Magnet created: object #{magnet}")
51
+ print(f" Center: {magnet_center} m")
52
+ print(f" Size: {magnet_size} m")
53
+ print(f" Material: NdFeB, Br = 1.2 T")
54
+
55
+ # ============================================================================
56
+ # Step 2: Create CoefficientFunctions for Different Field Types
57
+ # ============================================================================
58
+
59
+ print("\n[Step 2] Creating CoefficientFunctions for All Field Types")
60
+ print("-" * 70)
61
+
62
+ # Method 1: New unified interface (recommended)
63
+ B_cf = rad_ngsolve.RadiaField(magnet, 'b') # Magnetic flux density
64
+ H_cf = rad_ngsolve.RadiaField(magnet, 'h') # Magnetic field
65
+ A_cf = rad_ngsolve.RadiaField(magnet, 'a') # Vector potential
66
+ M_cf = rad_ngsolve.RadiaField(magnet, 'm') # Magnetization
67
+
68
+ print(f"Created CoefficientFunctions:")
69
+ print(f" B (flux density): {type(B_cf).__name__}, field_type='{B_cf.field_type}'")
70
+ print(f" H (magnetic field): {type(H_cf).__name__}, field_type='{H_cf.field_type}'")
71
+ print(f" A (vector potential): {type(A_cf).__name__}, field_type='{A_cf.field_type}'")
72
+ print(f" M (magnetization): {type(M_cf).__name__}, field_type='{M_cf.field_type}'")
73
+
74
+ # ============================================================================
75
+ # Step 3: Create 3D Mesh
76
+ # ============================================================================
77
+
78
+ print("\n[Step 3] Creating 3D Mesh")
79
+ print("-" * 70)
80
+
81
+ geo = CSGeometry()
82
+ geo.Add(OrthoBrick(Pnt(-0.05, -0.05, -0.05), Pnt(0.05, 0.05, 0.05)))
83
+ mesh = Mesh(geo.GenerateMesh(maxh=0.01))
84
+
85
+ print(f"3D Mesh generated:")
86
+ print(f" Elements: {mesh.ne}")
87
+ print(f" Vertices: {mesh.nv}")
88
+ print(f" Domain: [-0.05, 0.05] m = [-50, 50] mm")
89
+
90
+ # ============================================================================
91
+ # Step 4: Evaluate Fields at Test Points
92
+ # ============================================================================
93
+
94
+ print("\n[Step 4] Field Evaluation at Test Points")
95
+ print("-" * 70)
96
+
97
+ test_points = [
98
+ (0.000, 0.000, 0.000), # 0m (center)
99
+ (0.000, 0.000, 0.020), # 0.020m (above magnet)
100
+ (0.000, 0.000, 0.040), # 0.040m (far from magnet)
101
+ ]
102
+
103
+ print("\n" + "=" * 70)
104
+ print("Field Values at Different Points")
105
+ print("=" * 70)
106
+
107
+ for pt in test_points:
108
+ pt_m = pt
109
+ mesh_pt = mesh(*pt)
110
+
111
+ print(f"\nPoint: {pt} m")
112
+
113
+ # B field (Tesla)
114
+ B_val = B_cf(mesh_pt)
115
+ print(f" B (flux density): Bx={B_val[0]:8.6f}, By={B_val[1]:8.6f}, Bz={B_val[2]:8.6f} T")
116
+
117
+ # H field (A/m)
118
+ H_val = H_cf(mesh_pt)
119
+ print(f" H (magnetic field): Hx={H_val[0]:8.2f}, Hy={H_val[1]:8.2f}, Hz={H_val[2]:8.2f} A/m")
120
+
121
+ # A field (T*m)
122
+ A_val = A_cf(mesh_pt)
123
+ print(f" A (vector potential): Ax={A_val[0]:8.6f}, Ay={A_val[1]:8.6f}, Az={A_val[2]:8.6f} T*m")
124
+
125
+ # M field (A/m)
126
+ M_val = M_cf(mesh_pt)
127
+ print(f" M (magnetization): Mx={M_val[0]:8.2f}, My={M_val[1]:8.2f}, Mz={M_val[2]:8.2f} A/m")
128
+
129
+ # ============================================================================
130
+ # Step 5: Compare with Radia Direct Evaluation
131
+ # ============================================================================
132
+
133
+ print("\n" + "=" * 70)
134
+ print("Comparison with Radia Direct Evaluation")
135
+ print("=" * 70)
136
+
137
+ pt_m = [0, 0, 0] # Center point in meters
138
+ mesh_pt = mesh(0, 0, 0)
139
+
140
+ print(f"\nAt center ({pt_m} m):")
141
+
142
+ # Radia direct
143
+ B_radia = rad.Fld(magnet, 'b', pt_m)
144
+ H_radia = rad.Fld(magnet, 'h', pt_m)
145
+ A_radia = rad.Fld(magnet, 'a', pt_m)
146
+ M_radia = rad.Fld(magnet, 'm', pt_m)
147
+
148
+ # NGSolve CoefficientFunction
149
+ B_ngsolve = B_cf(mesh_pt)
150
+ H_ngsolve = H_cf(mesh_pt)
151
+ A_ngsolve = A_cf(mesh_pt)
152
+ M_ngsolve = M_cf(mesh_pt)
153
+
154
+ # Compare
155
+ print(f"\nB field:")
156
+ print(f" Radia: Bz = {B_radia[2]:.6f} T")
157
+ print(f" NGSolve: Bz = {B_ngsolve[2]:.6f} T")
158
+ print(f" Error: {abs(B_radia[2] - B_ngsolve[2]):.2e} T")
159
+
160
+ print(f"\nH field:")
161
+ print(f" Radia: Hz = {H_radia[2]:.2f} A/m")
162
+ print(f" NGSolve: Hz = {H_ngsolve[2]:.2f} A/m")
163
+ print(f" Error: {abs(H_radia[2] - H_ngsolve[2]):.2e} A/m")
164
+
165
+ print(f"\nA field:")
166
+ print(f" Radia: |A| = {np.linalg.norm(A_radia):.6e} T*m")
167
+ print(f" NGSolve: |A| = {np.linalg.norm(A_ngsolve):.6e} T*m")
168
+
169
+ print(f"\nM field (Magnetization):")
170
+ print(f" Radia: Mz = {M_radia[2]:.2f} A/m")
171
+ print(f" NGSolve: Mz = {M_ngsolve[2]:.2f} A/m")
172
+ print(f" Error: {abs(M_radia[2] - M_ngsolve[2]):.2e} A/m")
173
+
174
+ # ============================================================================
175
+ # Summary
176
+ # ============================================================================
177
+
178
+ print("\n" + "=" * 70)
179
+ print("Summary")
180
+ print("=" * 70)
181
+
182
+ print("\nNew Unified Interface:")
183
+ print(" rad_ngsolve.RadiaField(radia_obj, field_type)")
184
+ print("\nField types:")
185
+ print(" 'b' - Magnetic flux density B (Tesla)")
186
+ print(" 'h' - Magnetic field H (A/m)")
187
+ print(" 'a' - Vector potential A (T*m)")
188
+ print(" 'm' - Magnetization M (A/m)")
189
+
190
+ print("\nRecommendation:")
191
+ print(" Use the new RadiaField interface for all new code.")
192
+ print(" Legacy interfaces (RadBfield, RadHfield, etc.) remain")
193
+ print(" supported for backward compatibility.")
194
+
195
+ print("\n" + "=" * 70)
196
+ print("Complete")
197
+ print("=" * 70)