radia 1.3.3__py3-none-any.whl → 1.3.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,293 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ radia_ngsolve_utils.py - Utilities for Radia-NGSolve integration
4
+
5
+ This module provides high-level utilities for working with Radia and NGSolve together,
6
+ including mesh import and VTK export functionality.
7
+
8
+ Author: Radia Development Team
9
+ Created: 2025-11-22
10
+ Version: 1.0.0
11
+
12
+ Key Features
13
+ ------------
14
+ - Import Netgen/OCC tetrahedral meshes to Radia
15
+ - Export Radia geometry to VTK for visualization
16
+ - Export NGSolve solutions to VTK
17
+ - Unified interface for both solvers
18
+
19
+ Functions
20
+ ---------
21
+ create_radia_from_mesh : Import Netgen mesh to Radia with VTK export
22
+ export_ngsolve_vtk : Export NGSolve solution to VTK
23
+ export_radia_vtk : Export Radia geometry to VTK
24
+
25
+ Example
26
+ -------
27
+ >>> import radia as rad
28
+ >>> from ngsolve import Mesh
29
+ >>> from netgen.occ import Box, OCCGeometry
30
+ >>> from radia_ngsolve_utils import create_radia_from_mesh, export_radia_vtk
31
+ >>>
32
+ >>> # Setup
33
+ >>> rad.FldUnits('m')
34
+ >>>
35
+ >>> # Create mesh
36
+ >>> geo = OCCGeometry(Box((-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)))
37
+ >>> mesh = Mesh(geo.GenerateMesh(maxh=0.2))
38
+ >>>
39
+ >>> # Import to Radia and export VTK
40
+ >>> mag = create_radia_from_mesh(
41
+ ... mesh,
42
+ ... material={'magnetization': [0, 0, 1.2]},
43
+ ... vtk_filename='magnet'
44
+ ... )
45
+ >>>
46
+ >>> # Apply material and solve
47
+ >>> rad.MatApl(mag, rad.MatStd('NdFeB', 1.2))
48
+ >>> rad.Solve(mag, 0.0001, 10000)
49
+ >>>
50
+ >>> # Export final geometry
51
+ >>> export_radia_vtk(mag, 'magnet_solved')
52
+ """
53
+
54
+ import os
55
+ import radia as rad
56
+ from netgen_mesh_import import netgen_mesh_to_radia
57
+ from radia_vtk_export import exportGeometryToVTK
58
+
59
+
60
+ def create_radia_from_mesh(mesh, material=None, units='m', combine=True,
61
+ verbose=False, material_filter=None, vtk_filename=None):
62
+ """
63
+ Import Netgen mesh to Radia and optionally export to VTK.
64
+
65
+ This is a convenience wrapper around netgen_mesh_to_radia that adds
66
+ automatic VTK export functionality.
67
+
68
+ Parameters
69
+ ----------
70
+ mesh : ngsolve.Mesh
71
+ NGSolve mesh object to import
72
+ material : dict, optional
73
+ Material properties. Should contain 'magnetization' key with [Mx, My, Mz] in Tesla.
74
+ Default: {'magnetization': [0, 0, 0]}
75
+ units : str, optional
76
+ Length units: 'm' (meters) or 'mm' (millimeters)
77
+ Default: 'm' (recommended for NGSolve integration)
78
+ combine : bool, optional
79
+ If True, combine all tetrahedra into single container
80
+ If False, return list of individual tetrahedra
81
+ Default: True
82
+ verbose : bool, optional
83
+ Print detailed import information
84
+ Default: False
85
+ material_filter : str, optional
86
+ Filter mesh by material name (e.g., 'magnetic', 'air')
87
+ If None, import all materials
88
+ Default: None
89
+ vtk_filename : str, optional
90
+ If provided, export geometry to VTK file with this name (without .vtk extension)
91
+ Default: None (no VTK export)
92
+
93
+ Returns
94
+ -------
95
+ int or list
96
+ Radia object ID (if combine=True) or list of object IDs (if combine=False)
97
+
98
+ Example
99
+ -------
100
+ >>> from netgen.occ import Box, OCCGeometry
101
+ >>> from ngsolve import Mesh
102
+ >>> import radia as rad
103
+ >>> from radia_ngsolve_utils import create_radia_from_mesh
104
+ >>>
105
+ >>> rad.FldUnits('m')
106
+ >>> geo = OCCGeometry(Box((0, 0, 0), (0.1, 0.1, 0.1)))
107
+ >>> mesh = Mesh(geo.GenerateMesh(maxh=0.03))
108
+ >>>
109
+ >>> magnet = create_radia_from_mesh(
110
+ ... mesh,
111
+ ... material={'magnetization': [0, 0, 1.2]},
112
+ ... vtk_filename='my_magnet'
113
+ ... )
114
+ >>> # Creates my_magnet.vtk in current directory
115
+ """
116
+ # Import mesh to Radia
117
+ radia_obj = netgen_mesh_to_radia(
118
+ mesh=mesh,
119
+ material=material,
120
+ units=units,
121
+ combine=combine,
122
+ verbose=verbose,
123
+ material_filter=material_filter
124
+ )
125
+
126
+ # Export to VTK if requested
127
+ if vtk_filename is not None:
128
+ export_radia_vtk(radia_obj, vtk_filename)
129
+
130
+ return radia_obj
131
+
132
+
133
+ def export_radia_vtk(radia_obj, filename):
134
+ """
135
+ Export Radia geometry to VTK file.
136
+
137
+ Parameters
138
+ ----------
139
+ radia_obj : int
140
+ Radia object ID
141
+ filename : str
142
+ Output filename without .vtk extension
143
+
144
+ Returns
145
+ -------
146
+ str
147
+ Full path to created VTK file
148
+
149
+ Example
150
+ -------
151
+ >>> import radia as rad
152
+ >>> from radia_ngsolve_utils import export_radia_vtk
153
+ >>>
154
+ >>> magnet = rad.ObjRecMag([0, 0, 0], [10, 10, 10], [0, 0, 1])
155
+ >>> vtk_path = export_radia_vtk(magnet, 'my_magnet')
156
+ >>> print(f"VTK exported to: {vtk_path}")
157
+ """
158
+ # Ensure .vtk extension
159
+ if not filename.endswith('.vtk'):
160
+ base_filename = filename
161
+ filename = filename + '.vtk'
162
+ else:
163
+ base_filename = filename[:-4]
164
+
165
+ # Export using radia_vtk_export
166
+ exportGeometryToVTK(radia_obj, base_filename)
167
+
168
+ # Get absolute path
169
+ vtk_path = os.path.abspath(filename)
170
+
171
+ return vtk_path
172
+
173
+
174
+ def export_ngsolve_vtk(mesh, gridfunction, filename, field_name='solution'):
175
+ """
176
+ Export NGSolve solution to VTK file.
177
+
178
+ Uses NGSolve's built-in VTK export functionality.
179
+
180
+ Parameters
181
+ ----------
182
+ mesh : ngsolve.Mesh
183
+ NGSolve mesh
184
+ gridfunction : ngsolve.GridFunction
185
+ Solution to export (e.g., H-field, B-field, potential)
186
+ filename : str
187
+ Output filename without .vtk extension
188
+ field_name : str, optional
189
+ Name for the field in VTK file
190
+ Default: 'solution'
191
+
192
+ Returns
193
+ -------
194
+ str
195
+ Full path to created VTK file
196
+
197
+ Example
198
+ -------
199
+ >>> from ngsolve import *
200
+ >>> from netgen.occ import Box, OCCGeometry
201
+ >>> from radia_ngsolve_utils import export_ngsolve_vtk
202
+ >>>
203
+ >>> geo = OCCGeometry(Box((0, 0, 0), (1, 1, 1)))
204
+ >>> mesh = Mesh(geo.GenerateMesh(maxh=0.2))
205
+ >>> fes = H1(mesh, order=2)
206
+ >>> gfu = GridFunction(fes)
207
+ >>> # ... solve for gfu ...
208
+ >>>
209
+ >>> vtk_path = export_ngsolve_vtk(mesh, gfu, 'solution', 'phi')
210
+ >>> print(f"NGSolve VTK exported to: {vtk_path}")
211
+ """
212
+ from ngsolve import VTKOutput
213
+
214
+ # Ensure .vtk extension
215
+ if filename.endswith('.vtk'):
216
+ filename = filename[:-4]
217
+
218
+ # Create VTK output
219
+ vtk = VTKOutput(
220
+ ma=mesh,
221
+ coefs=[gridfunction],
222
+ names=[field_name],
223
+ filename=filename,
224
+ subdivision=2
225
+ )
226
+ vtk.Do()
227
+
228
+ # Get absolute path
229
+ vtk_path = os.path.abspath(filename + '.vtk')
230
+
231
+ return vtk_path
232
+
233
+
234
+ def export_comparison_vtk(mesh_ngsolve, gfu_ngsolve, radia_obj,
235
+ prefix='comparison', ngsolve_field_name='H_ngsolve'):
236
+ """
237
+ Export both NGSolve and Radia results to VTK for comparison.
238
+
239
+ Creates two VTK files:
240
+ - {prefix}_ngsolve.vtk : NGSolve solution
241
+ - {prefix}_radia.vtk : Radia geometry
242
+
243
+ Parameters
244
+ ----------
245
+ mesh_ngsolve : ngsolve.Mesh
246
+ NGSolve mesh
247
+ gfu_ngsolve : ngsolve.GridFunction
248
+ NGSolve solution
249
+ radia_obj : int
250
+ Radia object ID
251
+ prefix : str, optional
252
+ Prefix for output filenames
253
+ Default: 'comparison'
254
+ ngsolve_field_name : str, optional
255
+ Name for NGSolve field in VTK
256
+ Default: 'H_ngsolve'
257
+
258
+ Returns
259
+ -------
260
+ tuple of str
261
+ (ngsolve_vtk_path, radia_vtk_path)
262
+
263
+ Example
264
+ -------
265
+ >>> from radia_ngsolve_utils import export_comparison_vtk
266
+ >>>
267
+ >>> # After solving both NGSolve and Radia...
268
+ >>> ngsolve_vtk, radia_vtk = export_comparison_vtk(
269
+ ... mesh, gfu, radia_system,
270
+ ... prefix='cube_benchmark',
271
+ ... ngsolve_field_name='H_field'
272
+ ... )
273
+ >>> print(f"NGSolve: {ngsolve_vtk}")
274
+ >>> print(f"Radia: {radia_vtk}")
275
+ """
276
+ ngsolve_filename = f"{prefix}_ngsolve"
277
+ radia_filename = f"{prefix}_radia"
278
+
279
+ ngsolve_vtk = export_ngsolve_vtk(mesh_ngsolve, gfu_ngsolve,
280
+ ngsolve_filename, ngsolve_field_name)
281
+ radia_vtk = export_radia_vtk(radia_obj, radia_filename)
282
+
283
+ return ngsolve_vtk, radia_vtk
284
+
285
+
286
+ # Module-level constants
287
+ __version__ = '1.0.0'
288
+ __all__ = [
289
+ 'create_radia_from_mesh',
290
+ 'export_radia_vtk',
291
+ 'export_ngsolve_vtk',
292
+ 'export_comparison_vtk'
293
+ ]
@@ -7,10 +7,32 @@ Functions for exporting Radia geometry to VTK format for visualization
7
7
  in ParaView and other VTK-compatible tools.
8
8
  """
9
9
 
10
- import radia as rad
11
10
  import csv
12
11
  from itertools import accumulate
13
12
 
13
+ def _get_radia_length_unit():
14
+ """
15
+ Get current Radia length unit by querying rad.FldUnits().
16
+
17
+ Returns:
18
+ tuple: (unit_name, scale_to_meters)
19
+ ('mm', 0.001) if Radia is using millimeters
20
+ ('m', 1.0) if Radia is using meters
21
+
22
+ Raises:
23
+ ValueError: If length unit cannot be determined
24
+ """
25
+ import radia as rad
26
+
27
+ units_str = rad.FldUnits()
28
+
29
+ if 'Length: mm' in units_str:
30
+ return ('mm', 0.001)
31
+ elif 'Length: m' in units_str:
32
+ return ('m', 1.0)
33
+ else:
34
+ raise ValueError(f"Cannot determine Radia length unit from: {units_str}")
35
+
14
36
  def chunks(lst, n):
15
37
  """
16
38
  Yield successive n-sized chunks from a list.
@@ -45,7 +67,8 @@ def exportGeometryToVTK(obj, fileName='radia_Geometry'):
45
67
  >>> mag = rad.ObjRecMag([0,0,0], [10,10,10], [0,0,1])
46
68
  >>> exportGeometryToVTK(mag, 'my_magnet')
47
69
  """
48
-
70
+ import radia as rad
71
+
49
72
  vtkData = rad.ObjDrwVTK(obj, 'Axes->False')
50
73
 
51
74
  lengths = vtkData['polygons']['lengths']
@@ -55,34 +78,41 @@ def exportGeometryToVTK(obj, fileName='radia_Geometry'):
55
78
  points = vtkData['polygons']['vertices']
56
79
  nPnts = int(len(points)/3)
57
80
 
58
- # format the points array to be floats rather than double
59
- points = [round(num/1000.0, 8) for num in points]
60
- # Note: Converted from mm (Radia units) to m
61
- # define the connectivity list
62
- conn = list(range(nPnts))
81
+ # Get Radia's current length unit and convert to meters for VTK standard
82
+ unit_name, scale_to_meters = _get_radia_length_unit()
83
+ points = [round(num * scale_to_meters, 8) for num in points]
84
+
63
85
  # define colours array
64
86
  colors = vtkData['polygons']['colors']
65
87
 
66
88
  # pre-process the output lists to have chunkLength items per line
67
- chunkLength = 9 # this writes 9 numbers per line (9 is the number used in Paraview if data is saved as the VTK Legacy format)
68
- offsets = list(chunks(offsets, chunkLength))
89
+ chunkLength = 9 # this writes 9 numbers per line
69
90
  points = list(chunks(points, chunkLength))
70
- conn = list(chunks(conn, chunkLength))
71
91
  colors = list(chunks(colors, chunkLength))
72
92
 
73
- # write the data to file
93
+ # write the data to file (VTK Legacy format - most compatible)
74
94
  with open(fileName + ".vtk", "w", newline="") as f:
75
- f.write('# vtk DataFile Version 5.1\n')
95
+ f.write('# vtk DataFile Version 3.0\n')
76
96
  f.write('vtk output\nASCII\nDATASET POLYDATA\n')
77
97
  f.write('POINTS ' + str(nPnts) + ' float\n')
78
98
  writer = csv.writer(f, delimiter=" ")
79
99
  writer.writerows(points)
80
100
  f.write('\n')
81
- f.write('POLYGONS ' + str(nPoly+1) + ' ' + str(nPnts) + '\n')
82
- f.write('OFFSETS vtktypeint64\n')
83
- writer.writerows(offsets)
84
- f.write('CONNECTIVITY vtktypeint64\n')
85
- writer.writerows(conn)
101
+
102
+ # POLYGONS in classic format (most compatible with all ParaView versions)
103
+ # Format: nPoly totalSize
104
+ # Each line: nVertices v1 v2 v3 ...
105
+ total_size = sum(lengths) + nPoly # sum of (nVertices + nVertices) for each polygon
106
+ f.write('POLYGONS ' + str(nPoly) + ' ' + str(total_size) + '\n')
107
+ for i in range(nPoly):
108
+ n_vertices = lengths[i]
109
+ start = offsets[i]
110
+ end = offsets[i+1]
111
+ f.write(str(n_vertices))
112
+ for j in range(start, end):
113
+ f.write(' ' + str(j))
114
+ f.write('\n')
115
+
86
116
  f.write('\n')
87
117
  f.write('CELL_DATA ' + str(nPoly) + '\n')
88
118
  f.write('COLOR_SCALARS Radia_colours 3\n')
@@ -93,6 +123,62 @@ def exportGeometryToVTK(obj, fileName='radia_Geometry'):
93
123
  print(f" Points: {nPnts}")
94
124
 
95
125
 
126
+ def exportFieldToVTK(points, field_data, fileName='field_distribution', field_name='B_field'):
127
+ """
128
+ Export magnetic field distribution to VTK Legacy format file.
129
+
130
+ Args:
131
+ points: List of observation points [[x, y, z], ...] in Radia's current units
132
+ field_data: List of field vectors [[Bx, By, Bz], ...] in Tesla
133
+ fileName: Output file name (without .vtk extension)
134
+ field_name: Name for the vector field in VTK file
135
+
136
+ Note:
137
+ Points are automatically converted to meters (VTK standard) based on
138
+ Radia's current unit setting (queried via rad.FldUnits()).
139
+ """
140
+ import numpy as np
141
+
142
+ points = np.array(points)
143
+ field_data = np.array(field_data)
144
+
145
+ if points.shape[0] != field_data.shape[0]:
146
+ raise ValueError(f"Points ({points.shape[0]}) and field data ({field_data.shape[0]}) must have same length")
147
+
148
+ if points.shape[1] != 3 or field_data.shape[1] != 3:
149
+ raise ValueError("Points and field data must be Nx3 arrays")
150
+
151
+ # Get Radia's current length unit
152
+ unit_name, scale_to_meters = _get_radia_length_unit()
153
+
154
+ # Ensure .vtk extension
155
+ if not fileName.endswith('.vtk'):
156
+ fileName += '.vtk'
157
+
158
+ with open(fileName, 'w') as f:
159
+ # Header
160
+ f.write('# vtk DataFile Version 3.0\n')
161
+ f.write('Magnetic Field Distribution\n')
162
+ f.write('ASCII\n')
163
+ f.write('DATASET POLYDATA\n')
164
+
165
+ # Points (convert to meters for VTK standard)
166
+ f.write(f'POINTS {len(points)} float\n')
167
+ for pt in points:
168
+ # Convert to meters using detected unit scale
169
+ f.write(f'{pt[0]*scale_to_meters} {pt[1]*scale_to_meters} {pt[2]*scale_to_meters}\n')
170
+
171
+ # Point data (vector field)
172
+ f.write(f'\nPOINT_DATA {len(points)}\n')
173
+ f.write(f'VECTORS {field_name} float\n')
174
+ for B in field_data:
175
+ f.write(f'{B[0]} {B[1]} {B[2]}\n')
176
+
177
+ print(f"VTK field file exported: {fileName}")
178
+ print(f" Points: {len(points)}")
179
+ print(f" Field: {field_name}")
180
+
181
+
96
182
  if __name__ == '__main__':
97
183
  """
98
184
  Demo: Export a simple Radia geometry to VTK format
@@ -101,8 +187,9 @@ if __name__ == '__main__':
101
187
  import os
102
188
 
103
189
  # Add build directory to path
104
- sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'build', 'lib', 'Release'))
105
- sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'dist'))
190
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'build', 'Release'))
191
+
192
+ import radia as rad
106
193
 
107
194
  print("=" * 60)
108
195
  print("Radia VTK Export Demo")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: radia
3
- Version: 1.3.3
3
+ Version: 1.3.4
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
@@ -182,9 +182,6 @@ See [examples/Radia_to_NGSolve_CoefficientFunction/](examples/Radia_to_NGSolve_C
182
182
  - [examples/Radia_to_NGSolve_CoefficientFunction/EXAMPLES_GUIDE.md](examples/Radia_to_NGSolve_CoefficientFunction/EXAMPLES_GUIDE.md) - Detailed usage guide
183
183
  - [tests/test_radia_ngsolve.py](tests/test_radia_ngsolve.py) - Integration tests
184
184
 
185
- ### Visualization
186
- - [docs/PYVISTA_VIEWER.md](examples/2024_02_03_振分電磁石/PYVISTA_VIEWER.md) - PyVista viewer guide
187
-
188
185
  ### Development
189
186
  - [docs/TAB_CONVERSION_REPORT.md](docs/TAB_CONVERSION_REPORT.md) - Code style conversion
190
187
  - [docs/CLAUDE.md](docs/CLAUDE.md) - Development notes
@@ -0,0 +1,17 @@
1
+ python/__init__.py,sha256=oUOAjf_vY8DNy5HRU7oArAMic8urvHCR9yHSi4HFkkQ,47
2
+ python/nastran_mesh_import.py,sha256=CSoVhZCXa85lPiTF2hlspE2clBKOD7-_sCp1bxu_IK0,18147
3
+ python/netgen_mesh_import.py,sha256=UopXk-5bbfj1j9_hyiq8jbjb4SQXnWaeuaC7TDf17wA,19872
4
+ python/rad_ngsolve.pyd,sha256=s5ZvpTIrjYeV_B3vQv5HrtP4u_RaPhvxuZf5aKv3oC0,566272
5
+ python/rad_ngsolve_fast.py,sha256=GkC7ruKy3MESHsO0iRSWsrgLU4-DPPgctOi6pPpsWg4,5675
6
+ python/radia_coil_builder.py,sha256=nQkiAbfhueNvvxUARHdPD0C68ImidHmUQv_q4RsImeY,11253
7
+ python/radia_field_cached.py,sha256=Bjw3ecNe3u7AAXnLob5m_tjYIY7HwB9DpgFg9a-aP_8,9509
8
+ python/radia_ngsolve.pyd,sha256=s5ZvpTIrjYeV_B3vQv5HrtP4u_RaPhvxuZf5aKv3oC0,566272
9
+ python/radia_ngsolve_field.py,sha256=suJr4wacfYFKOkyV-5AQuHWnW5rtUMb0gSSjq8VRSXc,10166
10
+ python/radia_ngsolve_utils.py,sha256=xZCR9DOIKMwdEjmC28rOXVZiWFY5BQYH2VfopfuVBps,8406
11
+ python/radia_pyvista_viewer.py,sha256=JS33Mx4azGI7hUX0bzefc6zJfhv6qfRjM3Kl1bE9Mjs,4275
12
+ python/radia_vtk_export.py,sha256=I8Vyyt9tky78Qw1xPru9f0Rii6QEmdEgTFjQtamyooc,6540
13
+ radia-1.3.4.dist-info/licenses/LICENSE,sha256=yaWxyzG9DpJ44dDNdGni4nukwiZ8pU-r_aW-1tYNAjk,4374
14
+ radia-1.3.4.dist-info/METADATA,sha256=iLmP3uISANgF67d-fTvmh17jl1YNvuHjiEcBvBRkQm0,13202
15
+ radia-1.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ radia-1.3.4.dist-info/top_level.txt,sha256=J-z0poNcsv31IHB413--iOY8LoHBKiTHeybHX3abokI,7
17
+ radia-1.3.4.dist-info/RECORD,,