|
| 1 | +# # Magnetic behavior of a magnet-collector system |
| 2 | +# |
| 3 | +# This example shows how to use PyAEDT to understand the magnetic behavior of a simplified |
| 4 | +# magnet-collector system when the magnet position changes. |
| 5 | +# The example shows how to setup the model, an optimetrics analysis to sweep the magnet position |
| 6 | +# and the post-processing of the results, from report creation to field plotting using PyVista. |
| 7 | +# |
| 8 | +# Keywords: **Maxwell 3D**, **Magnetostatic**, **Magnetic**, **Optimetrics**. |
| 9 | + |
| 10 | +# ## Perform imports and define constants |
| 11 | +# |
| 12 | +# Perform required imports. |
| 13 | + |
| 14 | +# + |
| 15 | +import os |
| 16 | +import tempfile |
| 17 | +import time |
| 18 | + |
| 19 | +import ansys.aedt.core # Interface to Ansys Electronics Desktop |
| 20 | +from ansys.aedt.core.generic.constants import Axis |
| 21 | + |
| 22 | +# - |
| 23 | + |
| 24 | +# ## Define constants |
| 25 | +# |
| 26 | +# Constants help ensure consistency and avoid repetition throughout the example. |
| 27 | + |
| 28 | +AEDT_VERSION = "2025.2" |
| 29 | +NUM_CORES = 4 |
| 30 | +NG_MODE = False # Open AEDT UI when it is launched. |
| 31 | + |
| 32 | +# ## Create temporary directory |
| 33 | +# |
| 34 | +# Create a temporary working directory. |
| 35 | +# The name of the working folder is stored in ``temp_folder.name``. |
| 36 | +# |
| 37 | +# > **Note:** The final cell in the notebook cleans up the temporary folder. If you want to |
| 38 | +# > retrieve the AEDT project and data, do so before executing the final cell in the notebook. |
| 39 | + |
| 40 | +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") |
| 41 | + |
| 42 | +# ## Launch Maxwell 3d |
| 43 | +# |
| 44 | +# Create an instance of |
| 45 | +# the ``Maxwell3d`` class. The Ansys Electronics Desktop will be launched |
| 46 | +# with an active Maxwell3D design. The ``m3d`` object is subsequently |
| 47 | +# used to create and simulate the model. |
| 48 | + |
| 49 | +m3d = ansys.aedt.core.Maxwell3d( |
| 50 | + project="magnet_collector", |
| 51 | + solution_type="Magnetostatic", |
| 52 | + version=AEDT_VERSION, |
| 53 | + non_graphical=NG_MODE, |
| 54 | + new_desktop=True, |
| 55 | +) |
| 56 | + |
| 57 | +# ## Define variables |
| 58 | +# |
| 59 | +# Later on we want to see how the magnetic behavior of the system changes with the position of the magnet. |
| 60 | + |
| 61 | +m3d["magnet_radius"] = "2mm" |
| 62 | +m3d["magnet_height"] = "15mm" |
| 63 | +m3d["magnet_z_pos"] = "0mm" |
| 64 | + |
| 65 | +# ## Add materials |
| 66 | +# |
| 67 | +# Create custom material ``"Aimant"``. |
| 68 | + |
| 69 | +mat = m3d.materials.add_material("Aimant") |
| 70 | +mat.permeability = "1.1" |
| 71 | +mat.set_magnetic_coercivity(value=2005600, x=1, y=1, z=0) |
| 72 | +mat.update() |
| 73 | + |
| 74 | +# ## Create non-linear magnetic material with single valued BH curve |
| 75 | +# |
| 76 | +# Create list with BH curve data |
| 77 | + |
| 78 | +bh_curve = [ |
| 79 | + [0.0, 0.0], |
| 80 | + [0.032, 0.5], |
| 81 | + [0.049, 0.8], |
| 82 | + [0.065, 1], |
| 83 | + [0.081, 1.13], |
| 84 | + [0.17, 1.52], |
| 85 | + [0.32, 1.59], |
| 86 | + [0.65, 1.62], |
| 87 | + [0.81, 1.65], |
| 88 | + [1.61, 1.7], |
| 89 | + [3.19, 1.75], |
| 90 | + [4.78, 1.79], |
| 91 | + [6.34, 1.83], |
| 92 | + [7.96, 1.86], |
| 93 | + [15.89, 1.99], |
| 94 | + [31.77, 2.1], |
| 95 | + [63.53, 2.2], |
| 96 | + [158.77, 2.41], |
| 97 | + [317.48, 2.65], |
| 98 | + [635, 3.1], |
| 99 | +] |
| 100 | + |
| 101 | +# ## Create custom material "Fer" and assign the BH curve to the permeability value |
| 102 | + |
| 103 | +mat = m3d.materials.add_material("Fer") |
| 104 | +mat.permeability.value = bh_curve |
| 105 | +mat.set_magnetic_coercivity(value=0, x=1, y=0, z=0) |
| 106 | +mat.update() |
| 107 | + |
| 108 | +# ## Create the collector |
| 109 | +# |
| 110 | +# Create a simple geometry to model the collector and assign a material to it. |
| 111 | + |
| 112 | +# + |
| 113 | +collector = m3d.modeler.create_cylinder( |
| 114 | + orientation=ansys.aedt.core.constants.AXIS.Z, |
| 115 | + origin=[12, 13, 25], |
| 116 | + height="3mm", |
| 117 | + radius="9.5mm", |
| 118 | + axisdir="Z", |
| 119 | + name="collector", |
| 120 | +) |
| 121 | +cylinder2 = m3d.modeler.create_cylinder( |
| 122 | + orientation=ansys.aedt.core.constants.AXIS.Z, |
| 123 | + origin=[12, 13, 25], |
| 124 | + height="3mm", |
| 125 | + radius="8mm", |
| 126 | + axisdir="Z", |
| 127 | + name="cyl2", |
| 128 | +) |
| 129 | + |
| 130 | +m3d.modeler.subtract( |
| 131 | + blank_list=[collector], tool_list=[cylinder2], keep_originals=False |
| 132 | +) |
| 133 | + |
| 134 | +cylinder3 = m3d.modeler.create_cylinder( |
| 135 | + orientation=ansys.aedt.core.constants.AXIS.Z, |
| 136 | + origin=[12, 13, 28], |
| 137 | + height="3mm", |
| 138 | + radius="8.7mm", |
| 139 | + axisdir="Z", |
| 140 | + name="cyl3", |
| 141 | +) |
| 142 | +cylinder4 = m3d.modeler.create_cylinder( |
| 143 | + orientation=ansys.aedt.core.constants.AXIS.Z, |
| 144 | + origin=[12, 13, 28], |
| 145 | + height="3mm", |
| 146 | + radius="2mm", |
| 147 | + axisdir="Z", |
| 148 | + name="cyl4", |
| 149 | +) |
| 150 | + |
| 151 | +m3d.modeler.subtract( |
| 152 | + blank_list=[cylinder3], tool_list=[cylinder4], keep_originals=False |
| 153 | +) |
| 154 | +m3d.modeler.unite(assignment=[collector, cylinder3], keep_originals=False) |
| 155 | + |
| 156 | +collector.material_name = "Fer" |
| 157 | +# - |
| 158 | + |
| 159 | +# ## Create magnet |
| 160 | +# |
| 161 | +# Create a cylinder and assign a material to it. |
| 162 | + |
| 163 | +magnet = m3d.modeler.create_cylinder( |
| 164 | + orientation=Axis.Z, |
| 165 | + origin=[0, 0, "magnet_z_pos"], |
| 166 | + radius="magnet_radius", |
| 167 | + height="magnet_height", |
| 168 | + num_sides=0, |
| 169 | + name="magnet", |
| 170 | + material="Aimant", |
| 171 | +) |
| 172 | + |
| 173 | +# ## Create a polyline |
| 174 | +# |
| 175 | +# Create a polyline to plot the field onto. |
| 176 | +# The polyline is placed in the center of the collector so to capture the magnetic flux density. |
| 177 | + |
| 178 | +line = m3d.modeler.create_polyline(points=[[12, 13, 0], [12, 13, "32mm"]], name="line") |
| 179 | + |
| 180 | +# ## Create a vacuum region to enclose all objects |
| 181 | + |
| 182 | +region = m3d.modeler.create_region( |
| 183 | + pad_value=50, pad_type="Percentage Offset", name="Region" |
| 184 | +) |
| 185 | + |
| 186 | +# ## Create the collector cross-section on the XZ plane |
| 187 | + |
| 188 | +collector_relative_cs = m3d.modeler.create_coordinate_system( |
| 189 | + origin=[12, 13, 28], name="collector_cs" |
| 190 | +) |
| 191 | +section = m3d.modeler.create_rectangle( |
| 192 | + orientation="XZ", |
| 193 | + position=[-25, 0, -35], |
| 194 | + dimension_list=["50mm", "50mm"], |
| 195 | + name="section", |
| 196 | +) |
| 197 | +m3d.modeler.set_working_coordinate_system("Global") |
| 198 | + |
| 199 | +# ## Create a dummy geometry for mesh operations |
| 200 | +# |
| 201 | +# Create a cylinder that encloses the polyline to force the mesh to be finer on the polyline. |
| 202 | + |
| 203 | +dummy_cylinder = m3d.modeler.create_cylinder( |
| 204 | + orientation=Axis.Z, |
| 205 | + origin=[12, 13, 0], |
| 206 | + radius="1mm", |
| 207 | + height="32mm", |
| 208 | + num_sides=6, |
| 209 | + name="dummy_cylinder", |
| 210 | +) |
| 211 | + |
| 212 | +# ## Create a custom named expression |
| 213 | +# |
| 214 | +# Create a custom named expression to calculate relative permeability of the ferromagnetic material. |
| 215 | +# This expression is used to see how the relative permeability of the collector changes with magnet position. |
| 216 | + |
| 217 | +mu_r = { |
| 218 | + "name": "mu_r", |
| 219 | + "description": "Relative permeability of the ferromagnetic material", |
| 220 | + "design_type": ["Maxwell 3D"], |
| 221 | + "fields_type": ["Fields"], |
| 222 | + "primary_sweep": "Time", |
| 223 | + "assignment": "", |
| 224 | + "assignment_type": [""], |
| 225 | + "operations": [ |
| 226 | + "NameOfExpression('Mag_B')", |
| 227 | + "NameOfExpression('Mag_H')", |
| 228 | + "Scalar_Constant(1.25664e-06)", |
| 229 | + "Operation('*')", |
| 230 | + "Operation('/')", |
| 231 | + ], |
| 232 | + "report": ["Field_3D"], |
| 233 | +} |
| 234 | +m3d.post.fields_calculator.add_expression(mu_r, None) |
| 235 | + |
| 236 | +# ## Set mesh operations |
| 237 | +# |
| 238 | +# Assign mesh operations to the dummy cylinder and the collector. |
| 239 | + |
| 240 | +poly_mesh = m3d.mesh.assign_length_mesh( |
| 241 | + assignment=[dummy_cylinder], maximum_length="1mm", name="polyline" |
| 242 | +) |
| 243 | +collector_mesh = m3d.mesh.assign_length_mesh( |
| 244 | + assignment=[collector], |
| 245 | + inside_selection=False, |
| 246 | + maximum_length="3.8mm", |
| 247 | + name="collector", |
| 248 | +) |
| 249 | + |
| 250 | +# ## Create simulation setup |
| 251 | + |
| 252 | +setup = m3d.create_setup() |
| 253 | +setup.props["MaximumPasses"] = 10 |
| 254 | +setup.props["PercentRefinement"] = 30 |
| 255 | +setup.props["PercentError"] = 2 |
| 256 | +setup.props["MinimumPasses"] = 2 |
| 257 | +setup.props["NonlinearResidual"] = 1e-3 |
| 258 | + |
| 259 | +# ## Add parametric sweep |
| 260 | +# |
| 261 | +# Create a linear count sweep where the parameter to sweep is ``"magnet_z_pos"``. |
| 262 | +# The magnet position is changed at each step to see how the magnetic behavior of the system changes. |
| 263 | +# Enable the saving fields option. |
| 264 | + |
| 265 | +# + |
| 266 | +param_sweep = m3d.parametrics.add( |
| 267 | + variable="magnet_z_pos", |
| 268 | + start_point=m3d["magnet_z_pos"], |
| 269 | + end_point="25mm", |
| 270 | + step=5, |
| 271 | + variation_type="LinearCount", |
| 272 | +) |
| 273 | + |
| 274 | +param_sweep.props["ProdOptiSetupDataV2"]["SaveFields"] = True |
| 275 | +# - |
| 276 | + |
| 277 | +# ## Analyze parametric sweep |
| 278 | + |
| 279 | +param_sweep.analyze(cores=NUM_CORES) |
| 280 | + |
| 281 | +# ## Create reports |
| 282 | +# |
| 283 | +# Create rectangular and data plots on the polyline for different magnet positions. |
| 284 | + |
| 285 | +# + |
| 286 | +data_table = m3d.post.create_report( |
| 287 | + expressions="Mag_B", |
| 288 | + report_category="Fields", |
| 289 | + plot_type="Data Table", |
| 290 | + plot_name="Mag_B", |
| 291 | + variations={"magnet_z_pos": "All"}, |
| 292 | + context=line.name, |
| 293 | + polyline_points=101, |
| 294 | +) |
| 295 | + |
| 296 | +rectangular_plot = m3d.post.create_report( |
| 297 | + expressions="Mag_B", |
| 298 | + report_category="Fields", |
| 299 | + plot_type="Rectangular Plot", |
| 300 | + plot_name="Mag_B", |
| 301 | + variations={"magnet_z_pos": "All"}, |
| 302 | + context=line.name, |
| 303 | + polyline_points=101, |
| 304 | +) |
| 305 | +# - |
| 306 | + |
| 307 | +# ## Create field plots |
| 308 | +# |
| 309 | +# Create field plots over the collector cross-section and on |
| 310 | +# the collector surface to see how the magnetic flux density (B), |
| 311 | +# the vector B field, the magnetic field strength (H) and the permeability |
| 312 | +# of the ferromagnetic material (μ) change. |
| 313 | + |
| 314 | +mag_b = m3d.post.create_fieldplot_surface( |
| 315 | + assignment=[section.name], quantity="Mag_B", plot_name="Mag_B", field_type="Fields" |
| 316 | +) |
| 317 | +vector_b = m3d.post.create_fieldplot_volume( |
| 318 | + assignment=[collector.name], |
| 319 | + quantity="B_Vector", |
| 320 | + plot_name="B_Vector", |
| 321 | + field_type="Fields", |
| 322 | +) |
| 323 | +mag_h = m3d.post.create_fieldplot_surface( |
| 324 | + assignment=[section.name], quantity="Mag_H", plot_name="Mag_H", field_type="Fields" |
| 325 | +) |
| 326 | +mu_r = m3d.post.create_fieldplot_surface( |
| 327 | + assignment=[collector.name], quantity="mu_r", plot_name="mu_r", field_type="Fields" |
| 328 | +) |
| 329 | + |
| 330 | +# ## Export field |
| 331 | +# |
| 332 | +# Export magnetic flux density B on the collector cross-section in a .fld file. |
| 333 | + |
| 334 | +fld_filename = os.path.join(temp_folder.name, "Mag_B.fld") |
| 335 | +m3d.post.export_field_file( |
| 336 | + quantity="Mag_B", |
| 337 | + output_file=fld_filename, |
| 338 | + assignment=section.name, |
| 339 | + objects_type="Surf", |
| 340 | +) |
| 341 | + |
| 342 | +# ## Overlay fields using PyVista |
| 343 | +# |
| 344 | +# Plot electric field using PyVista and save to an image file. |
| 345 | +# Plot the relative permeability on the collector surface at a given magnet position. |
| 346 | +# Change argument ``"show"`` to ``True`` see the permeability plot. |
| 347 | + |
| 348 | +m3d["magnet_z_pos"] = "18.75mm" |
| 349 | + |
| 350 | +py_vista_plot = m3d.post.plot_field( |
| 351 | + quantity="mu_r", assignment=collector.name, plot_cad_objs=True, show=False |
| 352 | +) |
| 353 | +py_vista_plot.isometric_view = True |
| 354 | +py_vista_plot.plot( |
| 355 | + export_image_path=os.path.join(temp_folder.name, "mu_r.jpg"), show=True |
| 356 | +) |
| 357 | + |
| 358 | +# ## BH curve of the ferromagnetic material |
| 359 | +# |
| 360 | +# From the plot exported in the previous section, we can see the trend of the relative permeability |
| 361 | +# when the magnet gets close to the collector. |
| 362 | +# Looking at the scale of the relative permeability, we can see that the collector is far from saturation. |
| 363 | +# With a permeability peak value around 1.3E+7, the collector is still in the linear region of the BH curve. |
| 364 | +#  |
| 365 | +#  |
| 366 | + |
| 367 | +# ## Release AEDT |
| 368 | + |
| 369 | +m3d.save_project() |
| 370 | +m3d.release_desktop() |
| 371 | +# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory. |
| 372 | +time.sleep(3) |
| 373 | + |
| 374 | +# ## Clean up |
| 375 | +# |
| 376 | +# All project files are saved in the folder ``temp_folder.name``. |
| 377 | +# If you've run this example as a Jupyter notebook, you |
| 378 | +# can retrieve those project files. The following cell |
| 379 | +# removes all temporary files, including the project folder. |
| 380 | + |
| 381 | +temp_folder.cleanup() |
0 commit comments