radia 1.3.15__tar.gz → 1.3.16__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.
- {radia-1.3.15/src/radia.egg-info → radia-1.3.16}/PKG-INFO +1 -1
- {radia-1.3.15 → radia-1.3.16}/docs/API_REFERENCE.md +107 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/linear/benchmark_conditions.py +3 -3
- radia-1.3.16/examples/cube_uniform_field/nonlinear/README.md +229 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/nonlinear/benchmark_conditions.py +1 -1
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/nonlinear/benchmark_hexahedron_msc.py +121 -18
- radia-1.3.16/examples/cube_uniform_field/nonlinear/benchmark_tetra_all_solvers.py +327 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/nonlinear/benchmark_tetrahedron_msc_netgen.py +93 -12
- {radia-1.3.15 → radia-1.3.16}/pyproject.toml +1 -1
- {radia-1.3.15 → radia-1.3.16}/src/radia/__init__.py +1 -1
- radia-1.3.16/src/radia/radia.pyd +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/radia_ngsolve.pyd +0 -0
- {radia-1.3.15 → radia-1.3.16/src/radia.egg-info}/PKG-INFO +1 -1
- {radia-1.3.15 → radia-1.3.16}/src/radia.egg-info/SOURCES.txt +1 -2
- radia-1.3.15/examples/cube_uniform_field/nonlinear/README.md +0 -137
- radia-1.3.15/examples/ngsolve_integration/test_batch_evaluation.py +0 -143
- radia-1.3.15/examples/ngsolve_integration/test_unit_conversion.py +0 -173
- radia-1.3.15/src/radia/radia.pyd +0 -0
- {radia-1.3.15 → radia-1.3.16}/COPYRIGHT.txt +0 -0
- {radia-1.3.15 → radia-1.3.16}/LICENSE +0 -0
- {radia-1.3.15 → radia-1.3.16}/MANIFEST.in +0 -0
- {radia-1.3.15 → radia-1.3.16}/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/docs/HMATRIX_EVALUATION.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/docs/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/docs/scripts/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/background_fields/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/background_fields/cubit_to_nastran.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/background_fields/permeability_comparison.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/background_fields/quadrupole_analytical.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/background_fields/quadrupole_analytical.vtk.vtk +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/background_fields/sphere_in_quadrupole.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/background_fields/sphere_nastran_analysis.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/background_fields/sphere_nastran_field_mu.pvsm +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/background_fields/sphere_nastran_geometry.vtk +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/complex_coil_geometry/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/complex_coil_geometry/coil_geometry.vtk +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/complex_coil_geometry/coil_model.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/complex_coil_geometry/complex_coil.pvsm +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/complex_coil_geometry/field_map.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/complex_coil_geometry/field_map.vtk +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/complex_coil_geometry/visualize_coils.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/linear/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/linear/benchmark_hexa_unified.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/linear/benchmark_tetra_unified.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/linear/compare_radia_elf.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/linear/verify_radia_vs_elf.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/nonlinear/benchmark_hexahedron_hacapk.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/electromagnet/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/electromagnet/Radia_model.vtk +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/electromagnet/York.vtk +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/electromagnet/field_distribution.vtk +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/electromagnet/main_simulation_workflow.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/electromagnet/visualize_paraview.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/electromagnet/york_cubit_mesh.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/magpylib_integration/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/magpylib_integration/cylinder_magnet_examples.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/magpylib_integration/demo_magpylib_integration.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/magpylib_integration/sphere_in_halbach_cylinder.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/RadiaField_HACApK/verify_batch_evaluation.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/benchmark_gridfunction_set.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/demo_basic_field.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/demo_batch_evaluation.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/demo_coordinate_transform.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/demo_field_types.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/demo_hdiv_projection.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/mesh_magnetization_import/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/mesh_magnetization_import/ngsolve_cube_uniform_field.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/mesh_magnetization_import/sphere_analytical_to_radia.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/mesh_magnetization_import/verified_ngsolve_to_radia.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/verify_curl_A_equals_B/verify_curl_A_equals_B.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/ngsolve_integration/visualize_field.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/simple_problems/CONVERSION_NOTES.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/simple_problems/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/simple_problems/arc_current_dual_magnets.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/simple_problems/arc_current_with_magnet.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/simple_problems/chamfered_pole_piece.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/simple_problems/compare_magpylib.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/simple_problems/cubic_polyhedron_magnet.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/smco_magnet_array/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/smco_magnet_array/smbo.pvsm +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/smco_magnet_array/smco_array.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/smco_magnet_array/smco_array.vtk +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/smco_magnet_array/smco_field_distribution.vtk +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/BENCHMARK_RESULTS.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_field_evaluation.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_large_scale_comparison.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_linear_material.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_lu_vs_hmatrix.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_matrix_construction.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_parallel_construction.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_solver.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_solver_comparison.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_solver_methods.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_solver_scaling.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/benchmark_solver_scaling_extended.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/plot_benchmark_results.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/run_all_benchmarks.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/solver_benchmarks/verify_field_accuracy.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/tetra_field_accuracy_evaluation/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/tetra_field_accuracy_evaluation/analytical_reference.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/tetra_field_accuracy_evaluation/compare_all.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/tetra_field_accuracy_evaluation/evaluate_radia_solvers.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/tetra_field_accuracy_evaluation/evaluate_tetra_field.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/examples/tetra_field_accuracy_evaluation/ngsolve_reference.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/setup.cfg +0 -0
- {radia-1.3.15 → radia-1.3.16}/setup.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/libopenblas.dll +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/nastran_mesh_import.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/netgen_mesh_import.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/rad_ngsolve_fast.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/radia_coil_builder.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/radia_field_cached.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/radia_ngsolve_field.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/radia_ngsolve_utils.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/radia_pyvista_viewer.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia/radia_vtk_export.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia.egg-info/dependency_links.txt +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia.egg-info/not-zip-safe +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia.egg-info/requires.txt +0 -0
- {radia-1.3.15 → radia-1.3.16}/src/radia.egg-info/top_level.txt +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/README.md +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/__init__.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/benchmarks/benchmark_correct.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/benchmarks/benchmark_heavy.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/benchmarks/benchmark_openmp.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/benchmarks/benchmark_threads.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/conftest.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/profile_batch_performance.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_advanced.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_all_spaces.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_background_field_debug.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_batch_evaluation.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_cf_direct.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_convergence_hdiv.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_curlA_equals_B.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_curl_A_detailed.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_far_field_accuracy.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_fast_preparecache.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_fast_simple.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_group_operations.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_hcurl_vs_hdiv.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_l2_norm_debug.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_magpylib_comparison.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_materials.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_memory_allocation_tracking.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_mesh_import.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_minimal_cached.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_moving_magnet_memory.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_moving_magnet_memory_diagnosis.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_new_material_api.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_ngsolve_integration.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_objbckg_simple.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_objbckgcf_alone.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_order1.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_parallel_performance.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_preparecache_performance.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_process_memory.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_python_cached_field.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_python_cached_simple.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_rad_ngsolve.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_rad_ngsolve_diagnostic.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_rad_ngsolve_function.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_radhmat.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_radia.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_radia_core_memory.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_radia_field_computation_memory.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_radia_ngsolve_longrun.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_radia_ngsolve_memory_leak.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_radia_ngsolve_with_cache.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_radia_only_memory.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_serialization.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_set_vs_interpolate.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_simple.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_simple_fld_leak.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_square_coil_analytical.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_tetrahedral_solver.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_transformations.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_type_cast.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_unit_conversion_verify.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_utils.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_vector_potential.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_without_B_projection.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/test_without_gridfunction.py +0 -0
- {radia-1.3.15 → radia-1.3.16}/tests/verify_curl_A_equals_B.py +0 -0
|
@@ -307,6 +307,113 @@ rel_change = |B_new - B_old| / B_sat
|
|
|
307
307
|
|
|
308
308
|
This method provides fast Newton-Raphson convergence and matches industry-standard solvers.
|
|
309
309
|
|
|
310
|
+
### Solver Tolerance Parameters
|
|
311
|
+
|
|
312
|
+
Radia provides three tolerance parameters for controlling solver behavior:
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
# 1. Nonlinear iteration tolerance (outer loop)
|
|
316
|
+
# Set via Solve() - controls when Newton-Raphson iterations stop
|
|
317
|
+
rad.Solve(obj, nonl_tol, max_iter, method) # nonl_tol = 0.001 recommended
|
|
318
|
+
|
|
319
|
+
# 2. BiCGSTAB inner loop tolerance
|
|
320
|
+
# Set via SetBiCGSTABTol() BEFORE Solve() - controls linear system accuracy
|
|
321
|
+
rad.SetBiCGSTABTol(bicg_tol) # Default: 1e-4
|
|
322
|
+
|
|
323
|
+
# 3. H-matrix ACA tolerance (Method 2 only)
|
|
324
|
+
# Set via SetHACApKParams() BEFORE Solve() - controls low-rank approximation
|
|
325
|
+
rad.SetHACApKParams(hmat_eps, leaf_size, eta) # Default: 1e-4, 10, 2.0
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
| Parameter | API | Default | Description |
|
|
329
|
+
|-----------|-----|---------|-------------|
|
|
330
|
+
| `nonl_tol` | `rad.Solve(obj, nonl_tol, ...)` | 0.001 | Nonlinear convergence threshold |
|
|
331
|
+
| `bicg_tol` | `rad.SetBiCGSTABTol(tol)` | 1e-4 | BiCGSTAB relative residual tolerance |
|
|
332
|
+
| `hmat_eps` | `rad.SetHACApKParams(eps, ...)` | 1e-4 | H-matrix ACA compression tolerance |
|
|
333
|
+
|
|
334
|
+
**Example - Full solver configuration:**
|
|
335
|
+
|
|
336
|
+
```python
|
|
337
|
+
import radia as rad
|
|
338
|
+
|
|
339
|
+
# Configure tolerances BEFORE Solve()
|
|
340
|
+
rad.SetBiCGSTABTol(1e-4) # BiCGSTAB tolerance
|
|
341
|
+
rad.SetHACApKParams(1e-4, 10, 2.0) # H-matrix: eps=1e-4, leaf=10, eta=2.0
|
|
342
|
+
|
|
343
|
+
# Solve with nonlinear tolerance
|
|
344
|
+
rad.Solve(grp, 0.001, 100, 2) # nonl_tol=0.001, max_iter=100, method=2 (HACApK)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### SetBiCGSTABTol - BiCGSTAB Inner Loop Tolerance
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
rad.SetBiCGSTABTol(tol)
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
| Parameter | Type | Default | Description |
|
|
354
|
+
|-----------|------|---------|-------------|
|
|
355
|
+
| `tol` | float | 1e-4 | Relative residual tolerance for BiCGSTAB |
|
|
356
|
+
|
|
357
|
+
**Notes:**
|
|
358
|
+
- Affects Method 1 (BiCGSTAB) and Method 2 (HACApK)
|
|
359
|
+
- Lower values = higher accuracy but more iterations
|
|
360
|
+
- Call BEFORE `rad.Solve()`
|
|
361
|
+
|
|
362
|
+
### SetHACApKParams - H-Matrix Parameters (Method 2)
|
|
363
|
+
|
|
364
|
+
```python
|
|
365
|
+
rad.SetHACApKParams(eps, leaf_size, eta)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
| Parameter | Type | Default | Description |
|
|
369
|
+
|-----------|------|---------|-------------|
|
|
370
|
+
| `eps` | float | 1e-4 | ACA+ compression tolerance |
|
|
371
|
+
| `leaf_size` | int | 10 | Minimum cluster size in elements |
|
|
372
|
+
| `eta` | float | 2.0 | Admissibility parameter |
|
|
373
|
+
|
|
374
|
+
**Notes:**
|
|
375
|
+
- Only affects Method 2 (HACApK H-matrix solver)
|
|
376
|
+
- Lower `eps` = higher accuracy, larger ranks, more memory
|
|
377
|
+
- Call BEFORE `rad.Solve()`
|
|
378
|
+
|
|
379
|
+
**Parameter Rationale:**
|
|
380
|
+
|
|
381
|
+
| Parameter | Default | Rationale |
|
|
382
|
+
|-----------|---------|-----------|
|
|
383
|
+
| `eps` | 1e-4 | Balance between accuracy and compression. Lower values (1e-6, 1e-8) for higher accuracy, higher values (1e-3) for faster computation. |
|
|
384
|
+
| `leaf_size` | 10 | Minimum cluster size. Smaller values allow deeper tree but increase H-matrix overhead. 10 provides good balance for typical element counts. ELF-compatible default. |
|
|
385
|
+
| `eta` | 2.0 | Standard admissibility criterion: clusters are "well-separated" when `dist(c1,c2) >= eta * max(diam(c1), diam(c2))`. eta=2.0 is conservative, ensuring accurate low-rank approximations. Lower values (1.0) allow more aggressive compression but may reduce accuracy. |
|
|
386
|
+
|
|
387
|
+
### SetRelaxParam - Under-Relaxation Coefficient
|
|
388
|
+
|
|
389
|
+
```python
|
|
390
|
+
rad.SetRelaxParam(relax)
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
| Parameter | Type | Default | Description |
|
|
394
|
+
|-----------|------|---------|-------------|
|
|
395
|
+
| `relax` | float | 0.0 | Under-relaxation coefficient (0.0-1.0) |
|
|
396
|
+
|
|
397
|
+
**Notes:**
|
|
398
|
+
- Affects all solver methods (0=LU, 1=BiCGSTAB, 2=HACApK)
|
|
399
|
+
- `relax=0.0`: Full Newton step (default, fastest convergence when stable)
|
|
400
|
+
- `relax>0.0`: Damped update: `chi_new = chi_new*(1-relax) + chi_old*relax`
|
|
401
|
+
- Use under-relaxation (e.g., 0.2-0.5) when:
|
|
402
|
+
- Convergence is slow or oscillating
|
|
403
|
+
- Material has steep B-H curve
|
|
404
|
+
- Problem is highly nonlinear
|
|
405
|
+
- Call BEFORE `rad.Solve()`
|
|
406
|
+
|
|
407
|
+
**Example:**
|
|
408
|
+
```python
|
|
409
|
+
# For difficult nonlinear problems, use under-relaxation
|
|
410
|
+
rad.SetRelaxParam(0.3) # 30% damping
|
|
411
|
+
rad.Solve(container, 0.001, 100, 1)
|
|
412
|
+
|
|
413
|
+
# Reset to full step for normal cases
|
|
414
|
+
rad.SetRelaxParam(0.0)
|
|
415
|
+
```
|
|
416
|
+
|
|
310
417
|
### BiCGSTAB Performance
|
|
311
418
|
|
|
312
419
|
Typical solve times (nonlinear BH curve material):
|
|
@@ -33,7 +33,7 @@ CHI = MU_R - 1 # For reference/calculations only
|
|
|
33
33
|
# =============================================================================
|
|
34
34
|
# External Field
|
|
35
35
|
# =============================================================================
|
|
36
|
-
H_EXT =
|
|
36
|
+
H_EXT = 200000.0 # External H field magnitude [A/m] (same as nonlinear benchmark)
|
|
37
37
|
B_EXT = MU_0 * H_EXT # External B field magnitude [T]
|
|
38
38
|
|
|
39
39
|
# =============================================================================
|
|
@@ -49,8 +49,8 @@ MAX_ITERATIONS = 1000 # Maximum iterations
|
|
|
49
49
|
# Tetrahedron: maxh = CUBE_SIZE / n_div (approximate correspondence)
|
|
50
50
|
|
|
51
51
|
# Standard mesh sizes for comparison
|
|
52
|
-
STANDARD_N_DIVS = [
|
|
53
|
-
STANDARD_MAXH = [0.
|
|
52
|
+
STANDARD_N_DIVS = [5, 10, 15]
|
|
53
|
+
STANDARD_MAXH = [0.35, 0.25, 0.2, 0.15, 0.1]
|
|
54
54
|
|
|
55
55
|
def n_div_to_maxh(n_div):
|
|
56
56
|
"""Convert hexahedron n_div to approximate tetrahedral maxh."""
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Nonlinear Material Benchmark
|
|
2
|
+
|
|
3
|
+
Benchmark for Radia's nonlinear solver with saturable BH curves using MSC (Magnetic Surface Charge) method.
|
|
4
|
+
|
|
5
|
+
## Problem Setup
|
|
6
|
+
|
|
7
|
+
- **Geometry**: 1.0 m x 1.0 m x 1.0 m cube centered at origin
|
|
8
|
+
- **Material**: Nonlinear BH curve (soft iron with saturation)
|
|
9
|
+
- **External Field**: Hz = 200,000 A/m (uniform field along z-axis)
|
|
10
|
+
|
|
11
|
+
## Element Types
|
|
12
|
+
|
|
13
|
+
| Element | Mesh Tool | DOF | Benchmark Script |
|
|
14
|
+
|---------|-----------|-----|------------------|
|
|
15
|
+
| Hexahedron MSC | ObjPolyhdr | 6 (sigma per face) | `benchmark_hexahedron_msc.py` |
|
|
16
|
+
| Tetrahedron MSC | Netgen | 3 (Mx, My, Mz) | `benchmark_tetrahedron_msc_netgen.py` |
|
|
17
|
+
|
|
18
|
+
## BH Curve (Soft Iron)
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
H [A/m] B [T]
|
|
22
|
+
0 0.0
|
|
23
|
+
100 0.1
|
|
24
|
+
200 0.3
|
|
25
|
+
500 0.8
|
|
26
|
+
1000 1.2
|
|
27
|
+
2000 1.5
|
|
28
|
+
5000 1.7
|
|
29
|
+
10000 1.8
|
|
30
|
+
50000 2.0
|
|
31
|
+
100000 2.1
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- Initial permeability: mu_r ~= 800
|
|
35
|
+
- Saturation onset: B ~= 1.5 T
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Hexahedron MSC Benchmarks
|
|
40
|
+
|
|
41
|
+
Results stored in `hexahedron_msc/{lu,bicgstab,hacapk}/` directories.
|
|
42
|
+
|
|
43
|
+
### Solver Methods
|
|
44
|
+
|
|
45
|
+
| Method | Description | Complexity |
|
|
46
|
+
|--------|-------------|------------|
|
|
47
|
+
| LU | Dense LU decomposition | O(N^3) |
|
|
48
|
+
| BiCGSTAB | Iterative BiCGSTAB | O(N^2) per iteration |
|
|
49
|
+
| HACApK | H-matrix accelerated BiCGSTAB | O(N log N) per iteration |
|
|
50
|
+
|
|
51
|
+
### LU Solver Results (H_ext = 200,000 A/m)
|
|
52
|
+
|
|
53
|
+
| N | Elements | DOF | Time (s) | Iter | M_avg_z (A/m) | Memory (MB) |
|
|
54
|
+
|---|----------|-----|----------|------|---------------|-------------|
|
|
55
|
+
| 5 | 125 | 750 | 0.30 | 6 | 702,132 | 49 |
|
|
56
|
+
| 10 | 1,000 | 6,000 | 46.26 | 13 | 716,281 | 1,174 |
|
|
57
|
+
|
|
58
|
+
**Note**: LU solver for N >= 15 is prohibitively slow (O(N^6) time complexity for nonlinear).
|
|
59
|
+
|
|
60
|
+
### BiCGSTAB Solver Results (H_ext = 200,000 A/m)
|
|
61
|
+
|
|
62
|
+
| N | Elements | DOF | Time (s) | Iter | M_avg_z (A/m) | Memory (MB) |
|
|
63
|
+
|---|----------|-----|----------|------|---------------|-------------|
|
|
64
|
+
| 5 | 125 | 750 | 0.24 | 3 | 702,114 | 35 |
|
|
65
|
+
| 10 | 1,000 | 6,000 | 17.95 | 5 | 716,316 | 344 |
|
|
66
|
+
|
|
67
|
+
**Note**: BiCGSTAB uses previous solution as initial guess (ELF-compatible). Iteration count matches ELF.
|
|
68
|
+
|
|
69
|
+
### HACApK Solver Results (H_ext = 200,000 A/m, eps = 1e-4)
|
|
70
|
+
|
|
71
|
+
| N | Elements | DOF | Time (s) | Iter | M_avg_z (A/m) | Memory (MB) | Compression | Leaves |
|
|
72
|
+
|---|----------|-----|----------|------|---------------|-------------|-------------|--------|
|
|
73
|
+
| 5 | 125 | 750 | 0.14 | 4 | 701,757 | 35 | 0.0219 | 184 |
|
|
74
|
+
| 10 | 1,000 | 6,000 | 6.09 | 5 | 715,885 | 208 | 0.0059 | 3,190 |
|
|
75
|
+
|
|
76
|
+
### Speedup: HACApK vs LU
|
|
77
|
+
|
|
78
|
+
| N | LU Time (s) | HACApK Time (s) | Speedup |
|
|
79
|
+
|---|-------------|-----------------|---------|
|
|
80
|
+
| 5 | 0.30 | 0.14 | 2.1x |
|
|
81
|
+
| 10 | 46.26 | 6.09 | 7.6x |
|
|
82
|
+
| 15 | (est. hours) | - | >>10x |
|
|
83
|
+
| 20 | (impractical) | - | >>100x |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Radia vs ELF/MAGIC Comparison
|
|
88
|
+
|
|
89
|
+
Comparison of Radia and ELF/MAGIC solvers on identical hexahedral mesh (1.0m cube, H_ext = 200,000 A/m).
|
|
90
|
+
|
|
91
|
+
### Magnetization Accuracy (M_avg_z)
|
|
92
|
+
|
|
93
|
+
| N | Elements | Radia LU | ELF LU | Radia HACApK | ELF HACApK | Difference (%) |
|
|
94
|
+
|---|----------|----------|--------|--------------|------------|----------------|
|
|
95
|
+
| 5 | 125 | 702,132 | 702,132 | 701,757 | 702,110 | < 0.1% |
|
|
96
|
+
| 10 | 1,000 | 716,281 | 716,281 | 715,885 | 716,360 | < 0.1% |
|
|
97
|
+
|
|
98
|
+
**Note**: LU results match exactly. Small differences in HACApK are due to H-matrix compression (eps=1e-4).
|
|
99
|
+
|
|
100
|
+
### Performance Comparison
|
|
101
|
+
|
|
102
|
+
#### LU Solver
|
|
103
|
+
|
|
104
|
+
| N | Elements | Radia Time (s) | ELF Time (s) | Radia Iter | ELF Iter |
|
|
105
|
+
|---|----------|----------------|--------------|------------|----------|
|
|
106
|
+
| 5 | 125 | 0.30 | 0.13 | 6 | 6 |
|
|
107
|
+
| 10 | 1,000 | 46.26 | 13.42 | 13 | 13 |
|
|
108
|
+
|
|
109
|
+
**Note**: ELF LU is faster due to Fortran LAPACK optimizations. Iteration counts match exactly.
|
|
110
|
+
|
|
111
|
+
#### BiCGSTAB Solver
|
|
112
|
+
|
|
113
|
+
| N | Elements | Radia Time (s) | ELF Time (s) | Radia Iter | ELF Iter |
|
|
114
|
+
|---|----------|----------------|--------------|------------|----------|
|
|
115
|
+
| 5 | 125 | 0.24 | 0.08 | 3 | 3 |
|
|
116
|
+
| 10 | 1,000 | 17.95 | 4.93 | 5 | 4 |
|
|
117
|
+
|
|
118
|
+
**Note**: Radia BiCGSTAB now uses previous solution as initial guess, matching ELF's convergence behavior.
|
|
119
|
+
|
|
120
|
+
#### HACApK Solver (eps = 1e-4)
|
|
121
|
+
|
|
122
|
+
| N | Elements | Radia Time (s) | ELF Time (s) | Radia Iter | ELF Iter |
|
|
123
|
+
|---|----------|----------------|--------------|------------|----------|
|
|
124
|
+
| 5 | 125 | 0.14 | 0.15 | 4 | 3 |
|
|
125
|
+
| 10 | 1,000 | 6.09 | 4.07 | 5 | 4 |
|
|
126
|
+
|
|
127
|
+
**Note**: HACApK performance is comparable. Both use ACA+ compression with identical parameters.
|
|
128
|
+
|
|
129
|
+
### Key Observations
|
|
130
|
+
|
|
131
|
+
1. **Accuracy**: LU results are identical between Radia and ELF (M_avg_z matches to all digits)
|
|
132
|
+
2. **Convergence**: Both use similar Newton-Raphson (mucal2) convergence with B-field criterion
|
|
133
|
+
3. **HACApK**: Performance is comparable; Radia's H-matrix overhead is similar to ELF
|
|
134
|
+
4. **BiCGSTAB**: Iteration counts now match ELF (3-5 iterations vs previous 50)
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Tetrahedron MSC Benchmarks
|
|
139
|
+
|
|
140
|
+
Results stored in `tetrahedron_msc/{lu,bicgstab,hacapk}/` directories.
|
|
141
|
+
|
|
142
|
+
### HACApK Solver Results (H_ext = 200,000 A/m, eps = 1e-4)
|
|
143
|
+
|
|
144
|
+
| maxh | Elements | DOF | Time (s) | Iter | M_avg_z (A/m) | Memory (MB) | Leaves |
|
|
145
|
+
|------|----------|-----|----------|------|---------------|-------------|--------|
|
|
146
|
+
| 0.40 | 104 | 312 | 0.29 | 2 | 588,673 | 66 | 172 |
|
|
147
|
+
| 0.20 | 627 | 1,881 | 12.50 | 2 | 568,973 | 134 | 2,098 |
|
|
148
|
+
| 0.15 | 2,211 | 6,633 | 135.86 | 2 | 587,299 | 775 | 14,386 |
|
|
149
|
+
| 0.10 | 4,994 | 14,982 | 757.65 | 2 | 570,603 | 3,298 | 36,475 |
|
|
150
|
+
|
|
151
|
+
**Note**: 3DOF tetrahedra require pre-computed dense InteractMatrix (O(N^2) memory), which is the performance bottleneck. H-matrix is used for MatVec acceleration only.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Convergence Criterion
|
|
156
|
+
|
|
157
|
+
Radia v1.3.15+ uses **B-field based convergence** (mucal2) for nonlinear materials, matching the Newton-Raphson method used in industry-standard solvers.
|
|
158
|
+
|
|
159
|
+
### Convergence Methods
|
|
160
|
+
|
|
161
|
+
| Method | Stage | Formula | Description |
|
|
162
|
+
|--------|-------|---------|-------------|
|
|
163
|
+
| **mucal0** | Initialization | `chi = B[1] / (mu_0 * H[1]) - 1` | Initial chi from 2nd BH point |
|
|
164
|
+
| mucal1 | Iteration | `rel_change = |chi_new - chi_old| / chi_old` | Legacy relaxation method |
|
|
165
|
+
| **mucal2** | Iteration | `rel_change = |B_new - B_old| / B_sat` | Newton-Raphson, fast convergence |
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Solver Methods
|
|
170
|
+
|
|
171
|
+
Radia provides three solver methods:
|
|
172
|
+
|
|
173
|
+
| Method | Name | Description | Recommendation |
|
|
174
|
+
|--------|------|-------------|----------------|
|
|
175
|
+
| 0 | LU | Direct LU decomposition | Small problems (N < 12) |
|
|
176
|
+
| 1 | BiCGSTAB | Iterative solver | Medium problems |
|
|
177
|
+
| 2 | HACApK | H-matrix accelerated BiCGSTAB | Large problems (N >= 10) |
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
# Method 0: Direct LU solver
|
|
181
|
+
res = rad.Solve(grp, 0.001, 1000, 0)
|
|
182
|
+
|
|
183
|
+
# Method 1: BiCGSTAB iterative solver
|
|
184
|
+
res = rad.Solve(grp, 0.001, 1000, 1)
|
|
185
|
+
|
|
186
|
+
# Method 2: HACApK (H-matrix + BiCGSTAB)
|
|
187
|
+
rad.SetHACApKParams(1e-4, 10, 2.0) # eps, leaf_size, eta
|
|
188
|
+
res = rad.Solve(grp, 0.001, 1000, 2)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### When to Use Each Method
|
|
192
|
+
|
|
193
|
+
| Problem Size | Recommended Solver | Rationale |
|
|
194
|
+
|--------------|-------------------|-----------|
|
|
195
|
+
| N < 10 (< 1,000 elem) | LU (Method 0) | Fast, direct solution |
|
|
196
|
+
| 10 <= N < 15 | HACApK (Method 2) | 8x faster than LU |
|
|
197
|
+
| N >= 15 | HACApK (Method 2) | Only practical option |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Usage
|
|
202
|
+
|
|
203
|
+
### Hexahedron Benchmarks
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Run specific solver
|
|
207
|
+
python benchmark_hexahedron_msc.py --lu 5 10
|
|
208
|
+
python benchmark_hexahedron_msc.py --bicgstab 5 10
|
|
209
|
+
python benchmark_hexahedron_msc.py --hacapk 5 10 15 20
|
|
210
|
+
|
|
211
|
+
# Custom ACA tolerance
|
|
212
|
+
python benchmark_hexahedron_msc.py --hacapk --eps 1e-3 5 10
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Tetrahedron Benchmarks
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
# Run specific solver
|
|
219
|
+
python benchmark_tetrahedron_msc_netgen.py --lu 0.4 0.2
|
|
220
|
+
python benchmark_tetrahedron_msc_netgen.py --hacapk 0.4 0.2 0.15 0.10
|
|
221
|
+
|
|
222
|
+
# Custom ACA tolerance
|
|
223
|
+
python benchmark_tetrahedron_msc_netgen.py --hacapk --eps 1e-3 0.15
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
**Last Updated**: 2025-12-24
|
|
229
|
+
**Author**: Claude Code
|
|
@@ -25,7 +25,7 @@ CUBE_HALF = 0.5 # Half of cube edge [m]
|
|
|
25
25
|
# =============================================================================
|
|
26
26
|
# External Field
|
|
27
27
|
# =============================================================================
|
|
28
|
-
H_EXT =
|
|
28
|
+
H_EXT = 200000.0 # External H field magnitude [A/m] (unified with linear benchmark)
|
|
29
29
|
B_EXT = MU_0 * H_EXT # External B field magnitude [T]
|
|
30
30
|
|
|
31
31
|
# =============================================================================
|
{radia-1.3.15 → radia-1.3.16}/examples/cube_uniform_field/nonlinear/benchmark_hexahedron_msc.py
RENAMED
|
@@ -17,11 +17,13 @@ Solver types:
|
|
|
17
17
|
Usage:
|
|
18
18
|
python benchmark_hexahedron_msc.py --lu 5 10 15 20
|
|
19
19
|
python benchmark_hexahedron_msc.py --bicgstab 5 10 15 20
|
|
20
|
-
python benchmark_hexahedron_msc.py 5 10 15 20
|
|
20
|
+
python benchmark_hexahedron_msc.py --hacapk 5 10 15 20
|
|
21
|
+
python benchmark_hexahedron_msc.py --hacapk --eps 1e-3 5 10 15 # custom ACA tolerance
|
|
21
22
|
|
|
22
23
|
Examples:
|
|
23
24
|
python benchmark_hexahedron_msc.py --lu 5 10 15 20
|
|
24
25
|
python benchmark_hexahedron_msc.py --bicgstab 5 10 15 20
|
|
26
|
+
python benchmark_hexahedron_msc.py --hacapk --eps 1e-4 5 10 15 # ELF-compatible default
|
|
25
27
|
"""
|
|
26
28
|
|
|
27
29
|
import sys
|
|
@@ -132,14 +134,18 @@ def create_hexahedron_msc_mesh(n_div):
|
|
|
132
134
|
return elements
|
|
133
135
|
|
|
134
136
|
|
|
135
|
-
def benchmark_hexahedron_msc(n_div, solver_method=1, use_hmatrix=False
|
|
137
|
+
def benchmark_hexahedron_msc(n_div, solver_method=1, use_hmatrix=False,
|
|
138
|
+
hmat_eps=1e-4, leaf_size=10, eta=2.0, relax=0.0):
|
|
136
139
|
"""
|
|
137
140
|
Benchmark hexahedral MSC mesh with specified solver.
|
|
138
141
|
|
|
139
142
|
Args:
|
|
140
143
|
n_div: Number of divisions per edge
|
|
141
|
-
solver_method: 0=LU, 1=BiCGSTAB
|
|
144
|
+
solver_method: 0=LU, 1=BiCGSTAB, 2=HACApK
|
|
142
145
|
use_hmatrix: Enable H-matrix acceleration (BiCGSTAB only)
|
|
146
|
+
hmat_eps: ACA tolerance for HACApK solver (default: 1e-4)
|
|
147
|
+
leaf_size: Minimum cluster size in elements (default: 10)
|
|
148
|
+
eta: Admissibility parameter (default: 2.0)
|
|
143
149
|
"""
|
|
144
150
|
rad.FldUnits('m')
|
|
145
151
|
rad.UtiDelAll()
|
|
@@ -147,6 +153,8 @@ def benchmark_hexahedron_msc(n_div, solver_method=1, use_hmatrix=False):
|
|
|
147
153
|
# Determine solver name
|
|
148
154
|
if solver_method == 0:
|
|
149
155
|
solver_name = 'lu'
|
|
156
|
+
elif solver_method == 2:
|
|
157
|
+
solver_name = 'hacapk'
|
|
150
158
|
elif use_hmatrix:
|
|
151
159
|
solver_name = 'bicgstab_hmatrix'
|
|
152
160
|
else:
|
|
@@ -175,30 +183,52 @@ def benchmark_hexahedron_msc(n_div, solver_method=1, use_hmatrix=False):
|
|
|
175
183
|
ext = rad.ObjBckg([0, 0, B_ext])
|
|
176
184
|
grp = rad.ObjCnt([container, ext])
|
|
177
185
|
|
|
178
|
-
# Configure H-matrix if
|
|
179
|
-
# Note: H-matrix API may vary - check if available
|
|
186
|
+
# Configure H-matrix if using HACApK (method=2)
|
|
180
187
|
hmatrix_enabled = False
|
|
181
|
-
|
|
188
|
+
hmatrix_stats = None
|
|
189
|
+
if solver_method == 2:
|
|
182
190
|
try:
|
|
183
|
-
|
|
191
|
+
# Set HACApK parameters
|
|
192
|
+
# eps: ACA tolerance (lower = more accurate, higher = faster)
|
|
193
|
+
# leaf_size: minimum cluster size in elements
|
|
194
|
+
# eta: admissibility parameter
|
|
195
|
+
rad.SetHACApKParams(hmat_eps, leaf_size, eta)
|
|
184
196
|
hmatrix_enabled = True
|
|
185
|
-
print('H-matrix: Enabled')
|
|
197
|
+
print(f'H-matrix: Enabled (eps={hmat_eps:.0e}, leaf_size={leaf_size}, eta={eta})')
|
|
186
198
|
except AttributeError:
|
|
187
199
|
print('H-matrix: Not available (API not found)')
|
|
188
200
|
|
|
201
|
+
# Tolerance parameters (all explicitly set for reproducibility)
|
|
202
|
+
NONL_TOL = 0.001 # Nonlinear iteration tolerance (outer loop)
|
|
203
|
+
BICG_TOL = 1e-4 # BiCGSTAB inner loop tolerance (Method 1 and 2)
|
|
204
|
+
MAX_ITER = 100 # Maximum nonlinear iterations
|
|
205
|
+
|
|
206
|
+
# Set BiCGSTAB inner loop tolerance explicitly (ELF-compatible default)
|
|
207
|
+
rad.SetBiCGSTABTol(BICG_TOL)
|
|
208
|
+
|
|
209
|
+
# Set under-relaxation coefficient (0.0 = full step, 0.0-1.0 = under-relaxation)
|
|
210
|
+
rad.SetRelaxParam(relax)
|
|
211
|
+
|
|
189
212
|
# Solve
|
|
190
|
-
|
|
213
|
+
relax_str = f', relax={relax:.1f}' if relax > 0 else ''
|
|
214
|
+
print(f'Solving... (nonl_tol={NONL_TOL:.0e}, bicg_tol={BICG_TOL:.0e}{relax_str})')
|
|
191
215
|
t_solve_start = time.time()
|
|
192
|
-
result = rad.Solve(grp,
|
|
216
|
+
result = rad.Solve(grp, NONL_TOL, MAX_ITER, solver_method)
|
|
193
217
|
t_solve = time.time() - t_solve_start
|
|
194
218
|
|
|
195
219
|
# Measure peak memory after solve
|
|
196
220
|
peak_memory_mb = get_peak_memory_mb()
|
|
197
221
|
|
|
198
|
-
#
|
|
222
|
+
# Get H-matrix statistics if HACApK was used
|
|
199
223
|
if hmatrix_enabled:
|
|
200
224
|
try:
|
|
201
|
-
rad.
|
|
225
|
+
hmatrix_stats = rad.GetHACApKStats()
|
|
226
|
+
if hmatrix_stats:
|
|
227
|
+
print(f'H-matrix stats:')
|
|
228
|
+
print(f' Leaf nodes: {hmatrix_stats["n_leaves"]} (low-rank: {hmatrix_stats["n_lowrank"]}, dense: {hmatrix_stats["n_dense"]})')
|
|
229
|
+
print(f' Max rank: {hmatrix_stats["max_rank"]}')
|
|
230
|
+
print(f' Compression: {hmatrix_stats["compression"]:.4f}')
|
|
231
|
+
print(f' Build time: {hmatrix_stats["build_time"]:.4f} s')
|
|
202
232
|
except AttributeError:
|
|
203
233
|
pass
|
|
204
234
|
|
|
@@ -208,7 +238,7 @@ def benchmark_hexahedron_msc(n_div, solver_method=1, use_hmatrix=False):
|
|
|
208
238
|
M_avg_z = np.mean([m[2] for m in M_list]) if M_list else 0.0
|
|
209
239
|
|
|
210
240
|
n_iter = int(result[3]) if result[3] else 0
|
|
211
|
-
converged = n_iter <
|
|
241
|
+
converged = n_iter < MAX_ITER
|
|
212
242
|
residual = result[0] if result[0] else 0.0
|
|
213
243
|
|
|
214
244
|
print(f'Time: {t_solve:.3f} s')
|
|
@@ -230,6 +260,13 @@ def benchmark_hexahedron_msc(n_div, solver_method=1, use_hmatrix=False):
|
|
|
230
260
|
't_solve': t_solve,
|
|
231
261
|
'solver_method': solver_method,
|
|
232
262
|
'solver_name': solver_name,
|
|
263
|
+
# Tolerance parameters (all explicitly recorded)
|
|
264
|
+
'nonl_tol': NONL_TOL, # Nonlinear iteration tolerance (outer loop)
|
|
265
|
+
'bicg_tol': BICG_TOL, # BiCGSTAB inner loop tolerance
|
|
266
|
+
# H-matrix parameters (Method 2 only)
|
|
267
|
+
'hmat_eps': hmat_eps if solver_method == 2 else None,
|
|
268
|
+
'leaf_size': leaf_size if solver_method == 2 else None,
|
|
269
|
+
'eta': eta if solver_method == 2 else None,
|
|
233
270
|
'hmatrix_enabled': hmatrix_enabled,
|
|
234
271
|
'converged': converged,
|
|
235
272
|
'residual': residual,
|
|
@@ -238,6 +275,23 @@ def benchmark_hexahedron_msc(n_div, solver_method=1, use_hmatrix=False):
|
|
|
238
275
|
}
|
|
239
276
|
if peak_memory_mb is not None:
|
|
240
277
|
result_data['peak_memory_mb'] = peak_memory_mb
|
|
278
|
+
if hmatrix_stats is not None:
|
|
279
|
+
hmatrix_data = {
|
|
280
|
+
'n_lowrank': hmatrix_stats['n_lowrank'],
|
|
281
|
+
'n_dense': hmatrix_stats['n_dense'],
|
|
282
|
+
'max_rank': hmatrix_stats['max_rank'],
|
|
283
|
+
'compression_ratio': hmatrix_stats['compression'],
|
|
284
|
+
'build_time': hmatrix_stats['build_time'],
|
|
285
|
+
'nlf': hmatrix_stats['n_leaves'],
|
|
286
|
+
}
|
|
287
|
+
# Add timing statistics if available (v1.3.16+)
|
|
288
|
+
if 't_hmatrix_build' in hmatrix_stats:
|
|
289
|
+
hmatrix_data['t_hmatrix_build'] = hmatrix_stats['t_hmatrix_build']
|
|
290
|
+
if 't_linear_solve' in hmatrix_stats:
|
|
291
|
+
hmatrix_data['t_linear_solve'] = hmatrix_stats['t_linear_solve']
|
|
292
|
+
if 'linear_iterations' in hmatrix_stats:
|
|
293
|
+
hmatrix_data['linear_iterations'] = hmatrix_stats['linear_iterations']
|
|
294
|
+
result_data['hmatrix'] = hmatrix_data
|
|
241
295
|
return result_data
|
|
242
296
|
|
|
243
297
|
|
|
@@ -245,15 +299,25 @@ def main():
|
|
|
245
299
|
parser = argparse.ArgumentParser(description='Hexahedron MSC benchmark (Radia)')
|
|
246
300
|
parser.add_argument('--lu', action='store_true', help='Run LU solver benchmark')
|
|
247
301
|
parser.add_argument('--bicgstab', action='store_true', help='Run BiCGSTAB solver benchmark')
|
|
302
|
+
parser.add_argument('--hacapk', action='store_true', help='Run HACApK (H-matrix) solver benchmark')
|
|
303
|
+
parser.add_argument('--eps', type=float, default=1e-4,
|
|
304
|
+
help='ACA tolerance for HACApK (default: 1e-4, lower=accurate, higher=fast)')
|
|
305
|
+
parser.add_argument('--leaf_size', type=int, default=10,
|
|
306
|
+
help='Minimum cluster size in elements (default: 10)')
|
|
307
|
+
parser.add_argument('--eta', type=float, default=2.0,
|
|
308
|
+
help='Admissibility parameter (default: 2.0)')
|
|
309
|
+
parser.add_argument('--relax', type=float, default=0.0,
|
|
310
|
+
help='Under-relaxation coefficient (default: 0.0 = full step, 0.0-1.0)')
|
|
248
311
|
parser.add_argument('sizes', nargs='*', type=int, default=[5, 10, 15, 20],
|
|
249
312
|
help='Mesh sizes (N values, default: 5 10 15 20)')
|
|
250
313
|
|
|
251
314
|
args = parser.parse_args()
|
|
252
315
|
|
|
253
|
-
# Default to
|
|
254
|
-
any_solver = args.lu or args.bicgstab
|
|
316
|
+
# Default to LU only if none specified
|
|
317
|
+
any_solver = args.lu or args.bicgstab or args.hacapk
|
|
255
318
|
run_lu = args.lu or not any_solver
|
|
256
|
-
run_bicgstab = args.bicgstab
|
|
319
|
+
run_bicgstab = args.bicgstab
|
|
320
|
+
run_hacapk = args.hacapk
|
|
257
321
|
|
|
258
322
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
259
323
|
|
|
@@ -263,10 +327,15 @@ def main():
|
|
|
263
327
|
print('Cube size: 1.0 m')
|
|
264
328
|
print('H_ext: %.0f A/m' % H_EXT)
|
|
265
329
|
print('N values: %s' % args.sizes)
|
|
330
|
+
if args.relax > 0:
|
|
331
|
+
print('Relaxation: %.2f (under-relaxation)' % args.relax)
|
|
332
|
+
if run_hacapk:
|
|
333
|
+
print('HACApK: eps=%.0e, leaf_size=%d, eta=%.1f' % (args.eps, args.leaf_size, args.eta))
|
|
266
334
|
print()
|
|
267
335
|
|
|
268
336
|
results_lu = []
|
|
269
337
|
results_bicgstab = []
|
|
338
|
+
results_hacapk = []
|
|
270
339
|
|
|
271
340
|
for n in args.sizes:
|
|
272
341
|
# LU Benchmark
|
|
@@ -278,7 +347,7 @@ def main():
|
|
|
278
347
|
output_dir = os.path.join(script_dir, 'hexahedron_msc', 'lu')
|
|
279
348
|
os.makedirs(output_dir, exist_ok=True)
|
|
280
349
|
|
|
281
|
-
result = benchmark_hexahedron_msc(n, solver_method=0, use_hmatrix=False)
|
|
350
|
+
result = benchmark_hexahedron_msc(n, solver_method=0, use_hmatrix=False, relax=args.relax)
|
|
282
351
|
results_lu.append(result)
|
|
283
352
|
|
|
284
353
|
filename = 'msc_N%d_results.json' % n
|
|
@@ -296,7 +365,7 @@ def main():
|
|
|
296
365
|
output_dir = os.path.join(script_dir, 'hexahedron_msc', 'bicgstab')
|
|
297
366
|
os.makedirs(output_dir, exist_ok=True)
|
|
298
367
|
|
|
299
|
-
result = benchmark_hexahedron_msc(n, solver_method=1, use_hmatrix=False)
|
|
368
|
+
result = benchmark_hexahedron_msc(n, solver_method=1, use_hmatrix=False, relax=args.relax)
|
|
300
369
|
results_bicgstab.append(result)
|
|
301
370
|
|
|
302
371
|
filename = 'msc_N%d_results.json' % n
|
|
@@ -305,6 +374,25 @@ def main():
|
|
|
305
374
|
json.dump(result, f, indent=2)
|
|
306
375
|
print('Saved: %s\n' % filepath)
|
|
307
376
|
|
|
377
|
+
# HACApK Benchmark (Method 2)
|
|
378
|
+
if run_hacapk:
|
|
379
|
+
print('\n' + '=' * 70)
|
|
380
|
+
print('HACApK SOLVER: N=%d (eps=%.0e, leaf=%d, eta=%.1f)' % (n, args.eps, args.leaf_size, args.eta))
|
|
381
|
+
print('=' * 70 + '\n')
|
|
382
|
+
|
|
383
|
+
output_dir = os.path.join(script_dir, 'hexahedron_msc', 'hacapk')
|
|
384
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
385
|
+
|
|
386
|
+
result = benchmark_hexahedron_msc(n, solver_method=2, use_hmatrix=False,
|
|
387
|
+
hmat_eps=args.eps, leaf_size=args.leaf_size, eta=args.eta, relax=args.relax)
|
|
388
|
+
results_hacapk.append(result)
|
|
389
|
+
|
|
390
|
+
filename = 'msc_N%d_results.json' % n
|
|
391
|
+
filepath = os.path.join(output_dir, filename)
|
|
392
|
+
with open(filepath, 'w') as f:
|
|
393
|
+
json.dump(result, f, indent=2)
|
|
394
|
+
print('Saved: %s\n' % filepath)
|
|
395
|
+
|
|
308
396
|
# Summary
|
|
309
397
|
print('\n' + '=' * 70)
|
|
310
398
|
print('SUMMARY')
|
|
@@ -330,6 +418,21 @@ def main():
|
|
|
330
418
|
r['nonl_iterations'], r['M_avg_z'],
|
|
331
419
|
'Yes' if r['converged'] else 'No'))
|
|
332
420
|
|
|
421
|
+
if results_hacapk:
|
|
422
|
+
print('\nHACApK Solver (hexahedron_msc/hacapk/):\n')
|
|
423
|
+
print('%-6s %8s %10s %8s %10s %10s %8s %10s' % (
|
|
424
|
+
'N', 'Elements', 'Time (s)', 'Nonl It', 'M_avg_z', 'Compress', 'Leaves', 'Conv'))
|
|
425
|
+
print('-' * 85)
|
|
426
|
+
for r in results_hacapk:
|
|
427
|
+
hm = r.get('hmatrix', {})
|
|
428
|
+
compression = hm.get('compression_ratio', 0.0)
|
|
429
|
+
n_leaves = hm.get('nlf', 0)
|
|
430
|
+
print('%-6d %8d %10.3f %8d %10.0f %10.4f %8d %10s' % (
|
|
431
|
+
r['n_div'], r['n_elements'], r['t_solve'],
|
|
432
|
+
r['nonl_iterations'], r['M_avg_z'],
|
|
433
|
+
compression, n_leaves,
|
|
434
|
+
'Yes' if r['converged'] else 'No'))
|
|
435
|
+
|
|
333
436
|
print('=' * 70)
|
|
334
437
|
|
|
335
438
|
|