radia 1.3.4__py3-none-any.whl → 1.3.5__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.
radia/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ # Radia Python package
2
+ __version__ = "1.3.5"
@@ -0,0 +1,657 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ radia_tetra_mesh.py - Volume-based tetrahedral mesh solver for Radia
4
+
5
+ This module provides a specialized solver for tetrahedral meshes with linear
6
+ magnetic materials and background fields. It uses surface-based field computation
7
+ to correctly handle interior face cancellation.
8
+
9
+ Key features:
10
+ - Surface extraction: Only external faces are used for field computation
11
+ - Interior faces automatically cancel (volume-based approach)
12
+ - Relaxation method for linear material problems
13
+ - Compatible with NGSolve/Netgen tetrahedral meshes
14
+
15
+ Author: Radia Development Team
16
+ Created: 2025-11-27
17
+ Version: 0.1.0
18
+
19
+ Example
20
+ -------
21
+ >>> from ngsolve import Mesh
22
+ >>> from netgen.occ import Box, OCCGeometry
23
+ >>> import radia as rad
24
+ >>> import radia_tetra_mesh as rtm
25
+ >>>
26
+ >>> rad.FldUnits('m')
27
+ >>> geo = OCCGeometry(Box((-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)))
28
+ >>> mesh = Mesh(geo.GenerateMesh(maxh=0.2))
29
+ >>>
30
+ >>> # Solve with linear material in background field
31
+ >>> mu_0 = 4 * np.pi * 1e-7
32
+ >>> result = rtm.solve_linear_material(
33
+ ... mesh,
34
+ ... chi=99.0, # mu_r - 1
35
+ ... background_B=[0, 0, mu_0 * 1.0], # H0 = 1 A/m
36
+ ... precision=0.0001,
37
+ ... max_iter=10000
38
+ ... )
39
+ """
40
+
41
+ import numpy as np
42
+ import radia as rad
43
+ from ngsolve import VOL, ET
44
+
45
+
46
+ # Tetrahedral face topology (0-indexed vertices)
47
+ # v0, v1, v2, v3 are the 4 vertices of the tetrahedron
48
+ TETRA_FACE_VERTICES = [
49
+ (0, 2, 1), # Face 0: opposite to v3
50
+ (0, 1, 3), # Face 1: opposite to v2
51
+ (1, 2, 3), # Face 2: opposite to v0
52
+ (2, 0, 3) # Face 3: opposite to v1
53
+ ]
54
+
55
+
56
+ def extract_surface_faces(mesh, material_filter=None, verbose=True):
57
+ """
58
+ Extract external surface faces from tetrahedral mesh.
59
+
60
+ Interior faces (shared by two tetrahedra) are identified and excluded.
61
+ Only external (boundary) faces are returned.
62
+
63
+ Parameters
64
+ ----------
65
+ mesh : ngsolve.Mesh
66
+ Input tetrahedral mesh from Netgen/NGSolve
67
+ material_filter : str or list, optional
68
+ Filter elements by material name(s)
69
+ verbose : bool, default=True
70
+ Print progress information
71
+
72
+ Returns
73
+ -------
74
+ dict
75
+ {
76
+ 'surface_faces': list of dict
77
+ Each face: {
78
+ 'vertices': [[x1,y1,z1], [x2,y2,z2], [x3,y3,z3]],
79
+ 'normal': [nx, ny, nz],
80
+ 'area': float,
81
+ 'centroid': [cx, cy, cz],
82
+ 'element_idx': int, # Parent element index
83
+ 'local_face_idx': int # Face index within tetrahedron (0-3)
84
+ }
85
+ 'elements': list of dict
86
+ Each element: {
87
+ 'vertices': [[x1,y1,z1], ..., [x4,y4,z4]],
88
+ 'centroid': [cx, cy, cz],
89
+ 'volume': float,
90
+ 'surface_face_indices': list # Indices into surface_faces
91
+ }
92
+ 'interior_face_count': int
93
+ 'surface_face_count': int
94
+ }
95
+ """
96
+ # Normalize material_filter
97
+ if material_filter is None:
98
+ allowed_materials = None
99
+ elif isinstance(material_filter, str):
100
+ allowed_materials = {material_filter}
101
+ else:
102
+ allowed_materials = set(material_filter)
103
+
104
+ # First pass: collect all elements and their faces
105
+ elements = []
106
+ face_dict = {} # Key: sorted vertex indices, Value: list of (element_idx, local_face_idx)
107
+
108
+ for el_idx, el in enumerate(mesh.Elements(VOL)):
109
+ if el.type != ET.TET:
110
+ raise ValueError(f"Element {el_idx} is not tetrahedral (type={el.type})")
111
+
112
+ if allowed_materials is not None:
113
+ if el.mat not in allowed_materials:
114
+ continue
115
+
116
+ # Get vertex coordinates
117
+ vert_node_ids = el.vertices
118
+ vertices = []
119
+ for v_node in vert_node_ids:
120
+ v = mesh.vertices[v_node.nr]
121
+ coord = v.point
122
+ vertices.append([coord[0], coord[1], coord[2]])
123
+
124
+ # Compute centroid
125
+ centroid = [
126
+ sum(v[0] for v in vertices) / 4.0,
127
+ sum(v[1] for v in vertices) / 4.0,
128
+ sum(v[2] for v in vertices) / 4.0
129
+ ]
130
+
131
+ # Compute volume (1/6 * |det([v1-v0, v2-v0, v3-v0])|)
132
+ v0, v1, v2, v3 = [np.array(v) for v in vertices]
133
+ vol = abs(np.dot(v1 - v0, np.cross(v2 - v0, v3 - v0))) / 6.0
134
+
135
+ el_data = {
136
+ 'vertices': vertices,
137
+ 'centroid': centroid,
138
+ 'volume': vol,
139
+ 'vertex_indices': [v_node.nr for v_node in vert_node_ids],
140
+ 'surface_face_indices': []
141
+ }
142
+ elements.append(el_data)
143
+
144
+ current_el_idx = len(elements) - 1
145
+
146
+ # Process each face
147
+ for local_face_idx, face_verts in enumerate(TETRA_FACE_VERTICES):
148
+ # Get global vertex indices for this face
149
+ global_verts = tuple(sorted([el_data['vertex_indices'][i] for i in face_verts]))
150
+
151
+ if global_verts not in face_dict:
152
+ face_dict[global_verts] = []
153
+ face_dict[global_verts].append((current_el_idx, local_face_idx))
154
+
155
+ # Second pass: identify surface faces (appear only once)
156
+ surface_faces = []
157
+ interior_face_count = 0
158
+
159
+ for global_verts, occurrences in face_dict.items():
160
+ if len(occurrences) == 1:
161
+ # Surface face
162
+ el_idx, local_face_idx = occurrences[0]
163
+ el_data = elements[el_idx]
164
+
165
+ # Get face vertex coordinates
166
+ face_vert_indices = TETRA_FACE_VERTICES[local_face_idx]
167
+ face_vertices = [el_data['vertices'][i] for i in face_vert_indices]
168
+
169
+ # Compute face normal and area
170
+ v0, v1, v2 = [np.array(v) for v in face_vertices]
171
+ edge1 = v1 - v0
172
+ edge2 = v2 - v0
173
+ normal_vec = np.cross(edge1, edge2)
174
+ area = np.linalg.norm(normal_vec) / 2.0
175
+
176
+ if area > 1e-15:
177
+ normal_unit = normal_vec / (2.0 * area)
178
+ else:
179
+ normal_unit = np.array([0.0, 0.0, 1.0])
180
+
181
+ # Ensure normal points outward (away from element centroid)
182
+ face_centroid = (v0 + v1 + v2) / 3.0
183
+ el_centroid = np.array(el_data['centroid'])
184
+ outward = face_centroid - el_centroid
185
+ if np.dot(normal_unit, outward) < 0:
186
+ normal_unit = -normal_unit
187
+
188
+ face_data = {
189
+ 'vertices': face_vertices,
190
+ 'normal': normal_unit.tolist(),
191
+ 'area': area,
192
+ 'centroid': face_centroid.tolist(),
193
+ 'element_idx': el_idx,
194
+ 'local_face_idx': local_face_idx
195
+ }
196
+
197
+ face_idx = len(surface_faces)
198
+ surface_faces.append(face_data)
199
+ el_data['surface_face_indices'].append(face_idx)
200
+
201
+ elif len(occurrences) == 2:
202
+ # Interior face - skip
203
+ interior_face_count += 1
204
+ else:
205
+ # Should not happen in valid mesh
206
+ raise ValueError(f"Face with {len(occurrences)} occurrences (expected 1 or 2)")
207
+
208
+ if verbose:
209
+ print(f"[Surface Extraction]")
210
+ print(f" Total elements: {len(elements)}")
211
+ print(f" Total faces: {len(face_dict)}")
212
+ print(f" Surface faces: {len(surface_faces)}")
213
+ print(f" Interior faces: {interior_face_count} (excluded)")
214
+
215
+ return {
216
+ 'surface_faces': surface_faces,
217
+ 'elements': elements,
218
+ 'interior_face_count': interior_face_count,
219
+ 'surface_face_count': len(surface_faces)
220
+ }
221
+
222
+
223
+ def compute_h_field_from_surface_charge(obs_point, faces, magnetizations, element_map):
224
+ """
225
+ Compute H field at observation point from surface magnetic charges.
226
+
227
+ The surface charge density on each face is sigma = M . n, where M is the
228
+ magnetization of the parent element and n is the outward face normal.
229
+
230
+ Parameters
231
+ ----------
232
+ obs_point : array-like
233
+ Observation point [x, y, z]
234
+ faces : list
235
+ List of surface face dictionaries
236
+ magnetizations : ndarray
237
+ Magnetization vectors for each element, shape (n_elements, 3)
238
+ element_map : list
239
+ Maps face index to parent element index
240
+
241
+ Returns
242
+ -------
243
+ ndarray
244
+ H field vector [Hx, Hy, Hz] in A/m
245
+ """
246
+ obs = np.array(obs_point)
247
+ H = np.zeros(3)
248
+
249
+ for face_idx, face in enumerate(faces):
250
+ el_idx = face['element_idx']
251
+ M = magnetizations[el_idx]
252
+ n = np.array(face['normal'])
253
+
254
+ # Surface charge density: sigma = M . n
255
+ sigma = np.dot(M, n)
256
+
257
+ if abs(sigma) < 1e-20:
258
+ continue
259
+
260
+ # Face centroid
261
+ face_center = np.array(face['centroid'])
262
+
263
+ # Vector from face to observation point
264
+ r_vec = obs - face_center
265
+ r_mag = np.linalg.norm(r_vec)
266
+
267
+ if r_mag < 1e-15:
268
+ # Observation point at face centroid - use simplified formula
269
+ # H_local = -sigma / 2 * n (for field inside material)
270
+ continue
271
+
272
+ # H = sigma * Area / (4 * pi * r^2) * r_hat
273
+ # This is the monopole approximation for far field
274
+ area = face['area']
275
+ factor = sigma * area / (4.0 * np.pi * r_mag**3)
276
+ H += factor * r_vec
277
+
278
+ return H
279
+
280
+
281
+ def compute_interaction_matrix(mesh_data, verbose=True):
282
+ """
283
+ Compute interaction matrix for relaxation solver.
284
+
285
+ The interaction matrix A[i,j] gives the H field at element i's centroid
286
+ due to a unit magnetization in element j (through surface charges).
287
+
288
+ For linear materials: H_total = A @ M + H_ext
289
+
290
+ Parameters
291
+ ----------
292
+ mesh_data : dict
293
+ Output from extract_surface_faces()
294
+ verbose : bool, default=True
295
+ Print progress
296
+
297
+ Returns
298
+ -------
299
+ ndarray
300
+ Interaction matrix, shape (3*n_elements, 3*n_elements)
301
+ Organized as [Hx_0, Hy_0, Hz_0, Hx_1, Hy_1, Hz_1, ...]
302
+ """
303
+ elements = mesh_data['elements']
304
+ faces = mesh_data['surface_faces']
305
+ n_elements = len(elements)
306
+
307
+ if verbose:
308
+ print(f"[Interaction Matrix]")
309
+ print(f" Building {3*n_elements} x {3*n_elements} matrix...")
310
+
311
+ # For each source element, set unit M in x, y, z directions
312
+ # and compute H at all observation points
313
+ A = np.zeros((3 * n_elements, 3 * n_elements))
314
+
315
+ # Progress tracking
316
+ total_ops = n_elements * 3
317
+ progress_interval = max(1, total_ops // 10)
318
+
319
+ for src_el in range(n_elements):
320
+ for src_comp in range(3): # Mx, My, Mz
321
+ col_idx = 3 * src_el + src_comp
322
+
323
+ # Unit magnetization in direction src_comp
324
+ M_test = np.zeros((n_elements, 3))
325
+ M_test[src_el, src_comp] = 1.0
326
+
327
+ # Compute H at all element centroids
328
+ for obs_el in range(n_elements):
329
+ obs_point = elements[obs_el]['centroid']
330
+ H = compute_h_field_from_surface_charge(obs_point, faces, M_test, None)
331
+
332
+ for obs_comp in range(3):
333
+ row_idx = 3 * obs_el + obs_comp
334
+ A[row_idx, col_idx] = H[obs_comp]
335
+
336
+ if verbose and (col_idx + 1) % progress_interval == 0:
337
+ print(f" Progress: {100*(col_idx+1)/total_ops:.0f}%")
338
+
339
+ if verbose:
340
+ print(f" Matrix construction complete")
341
+
342
+ return A
343
+
344
+
345
+ def solve_linear_material(mesh, chi, background_B, precision=0.0001, max_iter=10000,
346
+ material_filter=None, relax_param=0.5, verbose=True):
347
+ """
348
+ Solve for magnetization in linear magnetic material with background field.
349
+
350
+ Uses relaxation method to solve: M = chi * H_total
351
+ where H_total = H_background + H_demagnetizing(M)
352
+
353
+ Parameters
354
+ ----------
355
+ mesh : ngsolve.Mesh
356
+ Input tetrahedral mesh
357
+ chi : float
358
+ Magnetic susceptibility (chi = mu_r - 1)
359
+ background_B : array-like
360
+ Background magnetic field [Bx, By, Bz] in Tesla
361
+ precision : float, default=0.0001
362
+ Convergence precision (relative change in M)
363
+ max_iter : int, default=10000
364
+ Maximum iterations
365
+ material_filter : str or list, optional
366
+ Filter elements by material name
367
+ relax_param : float, default=0.5
368
+ Relaxation parameter (0 < relax_param <= 1)
369
+ Smaller values = more stable but slower convergence
370
+ verbose : bool, default=True
371
+ Print progress information
372
+
373
+ Returns
374
+ -------
375
+ dict
376
+ {
377
+ 'magnetizations': ndarray, shape (n_elements, 3)
378
+ Final magnetization vectors for each element
379
+ 'H_fields': ndarray, shape (n_elements, 3)
380
+ H field at each element centroid
381
+ 'iterations': int
382
+ Number of iterations performed
383
+ 'converged': bool
384
+ Whether solution converged
385
+ 'mesh_data': dict
386
+ Surface extraction data
387
+ 'final_residual': float
388
+ Final relative residual
389
+ }
390
+ """
391
+ mu_0 = 4.0 * np.pi * 1e-7
392
+
393
+ # Convert background B to H
394
+ B0 = np.array(background_B)
395
+ H0 = B0 / mu_0
396
+
397
+ if verbose:
398
+ print("=" * 60)
399
+ print("Volume-based Tetrahedral Mesh Solver")
400
+ print("=" * 60)
401
+ print(f"Parameters:")
402
+ print(f" chi = {chi} (mu_r = {chi + 1})")
403
+ print(f" Background H0 = {H0} A/m")
404
+ print(f" Precision = {precision}")
405
+ print(f" Max iterations = {max_iter}")
406
+ print()
407
+
408
+ # Extract surface faces
409
+ mesh_data = extract_surface_faces(mesh, material_filter=material_filter, verbose=verbose)
410
+ elements = mesh_data['elements']
411
+ faces = mesh_data['surface_faces']
412
+ n_elements = len(elements)
413
+
414
+ if n_elements == 0:
415
+ raise ValueError("No elements found in mesh")
416
+
417
+ if verbose:
418
+ print()
419
+
420
+ # Compute interaction matrix
421
+ A = compute_interaction_matrix(mesh_data, verbose=verbose)
422
+
423
+ if verbose:
424
+ print()
425
+ print("[Relaxation Solver]")
426
+ print(f" Starting iteration...")
427
+
428
+ # Initialize magnetizations to chi * H0
429
+ M = np.zeros((n_elements, 3))
430
+ for i in range(n_elements):
431
+ M[i] = chi * H0
432
+
433
+ # External field array (same for all elements)
434
+ H_ext = np.tile(H0, n_elements) # Shape: (3*n_elements,)
435
+
436
+ # Relaxation iteration
437
+ converged = False
438
+ final_residual = np.inf
439
+
440
+ for iteration in range(max_iter):
441
+ # Flatten M for matrix multiplication
442
+ M_flat = M.flatten()
443
+
444
+ # Compute H_total = A @ M + H_ext
445
+ H_demag = A @ M_flat
446
+ H_total = H_demag + H_ext
447
+
448
+ # Compute new M from material relation: M_new = chi * H_total
449
+ M_new_flat = chi * H_total
450
+ M_new = M_new_flat.reshape((n_elements, 3))
451
+
452
+ # Apply relaxation
453
+ M_update = (1.0 - relax_param) * M + relax_param * M_new
454
+
455
+ # Check convergence
456
+ dM = M_update - M
457
+ residual = np.sqrt(np.sum(dM**2) / n_elements)
458
+ M_norm = np.sqrt(np.sum(M**2) / n_elements)
459
+
460
+ if M_norm > 1e-15:
461
+ rel_residual = residual / M_norm
462
+ else:
463
+ rel_residual = residual
464
+
465
+ M = M_update
466
+ final_residual = rel_residual
467
+
468
+ if verbose and (iteration + 1) % 100 == 0:
469
+ print(f" Iter {iteration+1}: residual = {rel_residual:.6e}")
470
+
471
+ if rel_residual < precision:
472
+ converged = True
473
+ if verbose:
474
+ print(f" Converged at iteration {iteration+1}")
475
+ break
476
+
477
+ if not converged and verbose:
478
+ print(f" [WARNING] Did not converge after {max_iter} iterations")
479
+ print(f" Final residual: {final_residual:.6e}")
480
+
481
+ # Compute final H fields
482
+ H_fields = np.zeros((n_elements, 3))
483
+ M_flat = M.flatten()
484
+ H_demag = A @ M_flat
485
+ for i in range(n_elements):
486
+ H_fields[i] = H_demag[3*i:3*i+3] + H0
487
+
488
+ if verbose:
489
+ print()
490
+ print("[Results]")
491
+ # Average M and H
492
+ M_avg = np.mean(M, axis=0)
493
+ H_avg = np.mean(H_fields, axis=0)
494
+ print(f" Average M: ({M_avg[0]:.6f}, {M_avg[1]:.6f}, {M_avg[2]:.6f}) A/m")
495
+ print(f" Average H: ({H_avg[0]:.6f}, {H_avg[1]:.6f}, {H_avg[2]:.6f}) A/m")
496
+ print(f" H at center element: ({H_fields[0][0]:.6f}, {H_fields[0][1]:.6f}, {H_fields[0][2]:.6f}) A/m")
497
+
498
+ return {
499
+ 'magnetizations': M,
500
+ 'H_fields': H_fields,
501
+ 'iterations': iteration + 1,
502
+ 'converged': converged,
503
+ 'mesh_data': mesh_data,
504
+ 'final_residual': final_residual,
505
+ 'elements': elements
506
+ }
507
+
508
+
509
+ def evaluate_field(result, point, include_background=True):
510
+ """
511
+ Evaluate H field at arbitrary point using solved magnetization.
512
+
513
+ Parameters
514
+ ----------
515
+ result : dict
516
+ Output from solve_linear_material()
517
+ point : array-like
518
+ Evaluation point [x, y, z]
519
+ include_background : bool, default=True
520
+ Whether to include background field in result
521
+
522
+ Returns
523
+ -------
524
+ ndarray
525
+ H field vector [Hx, Hy, Hz] in A/m
526
+ """
527
+ mesh_data = result['mesh_data']
528
+ faces = mesh_data['surface_faces']
529
+ M = result['magnetizations']
530
+
531
+ H = compute_h_field_from_surface_charge(point, faces, M, None)
532
+
533
+ # Background field is implicit in the solved M, but for external evaluation
534
+ # we need to add it back if requested
535
+ # Actually, the H_fields already include background, so we don't need to do anything
536
+
537
+ return H
538
+
539
+
540
+ def create_radia_container(result, apply_magnetization=True):
541
+ """
542
+ Create Radia container from solved result for field evaluation.
543
+
544
+ Parameters
545
+ ----------
546
+ result : dict
547
+ Output from solve_linear_material()
548
+ apply_magnetization : bool, default=True
549
+ If True, apply solved magnetizations to Radia objects
550
+
551
+ Returns
552
+ -------
553
+ int
554
+ Radia container object ID
555
+ """
556
+ from netgen_mesh_import import TETRA_FACES
557
+
558
+ elements = result['elements']
559
+ M = result['magnetizations']
560
+
561
+ obj_ids = []
562
+ for el_idx, el in enumerate(elements):
563
+ vertices = el['vertices']
564
+ mag = M[el_idx].tolist() if apply_magnetization else [0, 0, 0]
565
+
566
+ obj_id = rad.ObjPolyhdr(vertices, TETRA_FACES, mag)
567
+ obj_ids.append(obj_id)
568
+
569
+ container = rad.ObjCnt(obj_ids)
570
+ return container
571
+
572
+
573
+ # Convenience function for common use case
574
+ def solve_cube_in_field(cube_size, chi, H0_z, mesh_size=None, **kwargs):
575
+ """
576
+ Convenience function to solve a cube of linear material in uniform H field.
577
+
578
+ Parameters
579
+ ----------
580
+ cube_size : float
581
+ Full size of cube (centered at origin)
582
+ chi : float
583
+ Magnetic susceptibility (chi = mu_r - 1)
584
+ H0_z : float
585
+ z-component of background H field in A/m
586
+ mesh_size : float, optional
587
+ Maximum element size. Default: cube_size / 5
588
+ **kwargs
589
+ Additional arguments passed to solve_linear_material()
590
+
591
+ Returns
592
+ -------
593
+ dict
594
+ Result from solve_linear_material()
595
+ """
596
+ from ngsolve import Mesh
597
+ from netgen.occ import Box, Pnt, OCCGeometry
598
+
599
+ half = cube_size / 2.0
600
+ if mesh_size is None:
601
+ mesh_size = cube_size / 5.0
602
+
603
+ mu_0 = 4.0 * np.pi * 1e-7
604
+ B0 = [0, 0, mu_0 * H0_z]
605
+
606
+ cube_geo = Box(Pnt(-half, -half, -half), Pnt(half, half, half))
607
+ geo = OCCGeometry(cube_geo)
608
+ ngmesh = geo.GenerateMesh(maxh=mesh_size)
609
+ mesh = Mesh(ngmesh)
610
+
611
+ return solve_linear_material(mesh, chi, B0, **kwargs)
612
+
613
+
614
+ if __name__ == "__main__":
615
+ # Test with cube in uniform field (same as NGSolve reference)
616
+ print("Testing volume-based tetrahedral solver")
617
+ print("=" * 60)
618
+ print()
619
+
620
+ # Parameters matching NGSolve reference
621
+ cube_size = 1.0 # 1m cube
622
+ mu_r = 100
623
+ chi = mu_r - 1.0
624
+ H0 = 1.0 # A/m
625
+
626
+ rad.FldUnits('m')
627
+
628
+ result = solve_cube_in_field(
629
+ cube_size=cube_size,
630
+ chi=chi,
631
+ H0_z=H0,
632
+ mesh_size=0.25,
633
+ precision=0.0001,
634
+ max_iter=1000,
635
+ relax_param=0.3 # Slower but more stable
636
+ )
637
+
638
+ print()
639
+ print("=" * 60)
640
+ print("Comparison with NGSolve reference:")
641
+ print("=" * 60)
642
+ print(f"NGSolve Hz_total at origin: 0.034702 A/m")
643
+
644
+ # Find element closest to origin
645
+ min_dist = np.inf
646
+ center_el_idx = 0
647
+ for i, el in enumerate(result['elements']):
648
+ dist = np.linalg.norm(el['centroid'])
649
+ if dist < min_dist:
650
+ min_dist = dist
651
+ center_el_idx = i
652
+
653
+ Hz_center = result['H_fields'][center_el_idx][2]
654
+ print(f"Our Hz at center element: {Hz_center:.6f} A/m")
655
+ print(f"Difference: {abs(Hz_center - 0.034702):.6f} A/m")
656
+ if Hz_center > 1e-6:
657
+ print(f"Relative error: {abs(Hz_center - 0.034702) / 0.034702 * 100:.2f}%")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: radia
3
- Version: 1.3.4
3
+ Version: 1.3.5
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
@@ -0,0 +1,18 @@
1
+ radia/__init__.py,sha256=edxD1jM_-2LddwoxqtgATa_vTaruXk5WZsntpFJ9qtM,47
2
+ radia/nastran_mesh_import.py,sha256=CSoVhZCXa85lPiTF2hlspE2clBKOD7-_sCp1bxu_IK0,18147
3
+ radia/netgen_mesh_import.py,sha256=UopXk-5bbfj1j9_hyiq8jbjb4SQXnWaeuaC7TDf17wA,19872
4
+ radia/rad_ngsolve.pyd,sha256=s5ZvpTIrjYeV_B3vQv5HrtP4u_RaPhvxuZf5aKv3oC0,566272
5
+ radia/rad_ngsolve_fast.py,sha256=GkC7ruKy3MESHsO0iRSWsrgLU4-DPPgctOi6pPpsWg4,5675
6
+ radia/radia_coil_builder.py,sha256=nQkiAbfhueNvvxUARHdPD0C68ImidHmUQv_q4RsImeY,11253
7
+ radia/radia_field_cached.py,sha256=Bjw3ecNe3u7AAXnLob5m_tjYIY7HwB9DpgFg9a-aP_8,9509
8
+ radia/radia_ngsolve.pyd,sha256=s5ZvpTIrjYeV_B3vQv5HrtP4u_RaPhvxuZf5aKv3oC0,566272
9
+ radia/radia_ngsolve_field.py,sha256=suJr4wacfYFKOkyV-5AQuHWnW5rtUMb0gSSjq8VRSXc,10166
10
+ radia/radia_ngsolve_utils.py,sha256=xZCR9DOIKMwdEjmC28rOXVZiWFY5BQYH2VfopfuVBps,8406
11
+ radia/radia_pyvista_viewer.py,sha256=JS33Mx4azGI7hUX0bzefc6zJfhv6qfRjM3Kl1bE9Mjs,4275
12
+ radia/radia_tetra_mesh.py,sha256=nEpNpOBdJ-0DjS7WUx_bRHskrDKSKH3rSEWr-CwyQRM,21147
13
+ radia/radia_vtk_export.py,sha256=I8Vyyt9tky78Qw1xPru9f0Rii6QEmdEgTFjQtamyooc,6540
14
+ radia-1.3.5.dist-info/licenses/LICENSE,sha256=yaWxyzG9DpJ44dDNdGni4nukwiZ8pU-r_aW-1tYNAjk,4374
15
+ radia-1.3.5.dist-info/METADATA,sha256=LuqDACqJI2J9ucBkZe1UQFfh77ZuYnZvZIwI9JwRpX0,13202
16
+ radia-1.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ radia-1.3.5.dist-info/top_level.txt,sha256=kNDonE5X3Q2xnmOsWleQnGKQobuFsKM6Px5_Ta1I6x8,6
18
+ radia-1.3.5.dist-info/RECORD,,
@@ -0,0 +1 @@
1
+ radia
python/__init__.py DELETED
@@ -1,2 +0,0 @@
1
- # Radia Python package
2
- __version__ = "1.1.0"
@@ -1,17 +0,0 @@
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,,
@@ -1 +0,0 @@
1
- python
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes